def _recv_canfd(self) -> Optional[Message]: xl_can_rx_event = xlclass.XLcanRxEvent() xldriver.xlCanReceive(self.port_handle, xl_can_rx_event) if xl_can_rx_event.tag == xldefine.XL_CANFD_RX_EventTags.XL_CAN_EV_TAG_RX_OK: is_rx = True data_struct = xl_can_rx_event.tagData.canRxOkMsg elif xl_can_rx_event.tag == xldefine.XL_CANFD_RX_EventTags.XL_CAN_EV_TAG_TX_OK: is_rx = False data_struct = xl_can_rx_event.tagData.canTxOkMsg else: self.handle_canfd_event(xl_can_rx_event) return msg_id = data_struct.canId dlc = dlc2len(data_struct.dlc) flags = data_struct.msgFlags timestamp = xl_can_rx_event.timeStamp * 1e-9 channel = self.index_to_channel.get(xl_can_rx_event.chanIndex) msg = Message( timestamp=timestamp + self._time_offset, arbitration_id=msg_id & 0x1FFFFFFF, is_extended_id=bool( msg_id & xldefine.XL_MessageFlagsExtended.XL_CAN_EXT_MSG_ID), is_remote_frame=bool( flags & xldefine.XL_CANFD_RX_MessageFlags.XL_CAN_RXMSG_FLAG_RTR), is_error_frame=bool( flags & xldefine.XL_CANFD_RX_MessageFlags.XL_CAN_RXMSG_FLAG_EF), is_fd=bool( flags & xldefine.XL_CANFD_RX_MessageFlags.XL_CAN_RXMSG_FLAG_EDL), bitrate_switch=bool( flags & xldefine.XL_CANFD_RX_MessageFlags.XL_CAN_RXMSG_FLAG_BRS), error_state_indicator=bool( flags & xldefine.XL_CANFD_RX_MessageFlags.XL_CAN_RXMSG_FLAG_ESI), is_rx=is_rx, channel=channel, dlc=dlc, data=data_struct.data[:dlc], ) return msg
def _parse_data(self, data): """Optimized inner loop by making local copies of global variables and class members and hardcoding some values.""" unpack_obj_header_base = OBJ_HEADER_BASE_STRUCT.unpack_from obj_header_base_size = OBJ_HEADER_BASE_STRUCT.size unpack_obj_header_v1 = OBJ_HEADER_V1_STRUCT.unpack_from obj_header_v1_size = OBJ_HEADER_V1_STRUCT.size unpack_obj_header_v2 = OBJ_HEADER_V2_STRUCT.unpack_from obj_header_v2_size = OBJ_HEADER_V2_STRUCT.size unpack_can_msg = CAN_MSG_STRUCT.unpack_from unpack_can_fd_msg = CAN_FD_MSG_STRUCT.unpack_from unpack_can_fd_64_msg = CAN_FD_MSG_64_STRUCT.unpack_from can_fd_64_msg_size = CAN_FD_MSG_64_STRUCT.size unpack_can_error_ext = CAN_ERROR_EXT_STRUCT.unpack_from start_timestamp = self.start_timestamp max_pos = len(data) pos = 0 # Loop until a struct unpack raises an exception while True: self._pos = pos # Find next object after padding (depends on object type) try: pos = data.index(b"LOBJ", pos, pos + 8) except ValueError: if pos + 8 > max_pos: # Not enough data in container return raise BLFParseError("Could not find next object") header = unpack_obj_header_base(data, pos) # print(header) signature, _, header_version, obj_size, obj_type = header if signature != b"LOBJ": raise BLFParseError() # Calculate position of next object next_pos = pos + obj_size if next_pos > max_pos: # This object continues in the next container return pos += obj_header_base_size # Read rest of header if header_version == 1: flags, _, _, timestamp = unpack_obj_header_v1(data, pos) pos += obj_header_v1_size elif header_version == 2: flags, _, _, timestamp = unpack_obj_header_v2(data, pos) pos += obj_header_v2_size else: LOG.warning("Unknown object header version (%d)", header_version) pos = next_pos continue # Calculate absolute timestamp in seconds factor = 1e-5 if flags == 1 else 1e-9 timestamp = timestamp * factor + start_timestamp if obj_type == CAN_MESSAGE or obj_type == CAN_MESSAGE2: channel, flags, dlc, can_id, can_data = unpack_can_msg( data, pos) yield Message( timestamp=timestamp, arbitration_id=can_id & 0x1FFFFFFF, is_extended_id=bool(can_id & CAN_MSG_EXT), is_remote_frame=bool(flags & REMOTE_FLAG), is_rx=not bool(flags & DIR), dlc=dlc, data=can_data[:dlc], channel=channel - 1, ) elif obj_type == CAN_ERROR_EXT: members = unpack_can_error_ext(data, pos) channel = members[0] dlc = members[5] can_id = members[7] can_data = members[9] yield Message( timestamp=timestamp, is_error_frame=True, is_extended_id=bool(can_id & CAN_MSG_EXT), arbitration_id=can_id & 0x1FFFFFFF, dlc=dlc, data=can_data[:dlc], channel=channel - 1, ) elif obj_type == CAN_FD_MESSAGE: members = unpack_can_fd_msg(data, pos) ( channel, flags, dlc, can_id, _, _, fd_flags, valid_bytes, can_data, ) = members yield Message( timestamp=timestamp, arbitration_id=can_id & 0x1FFFFFFF, is_extended_id=bool(can_id & CAN_MSG_EXT), is_remote_frame=bool(flags & REMOTE_FLAG), is_fd=bool(fd_flags & 0x1), is_rx=not bool(flags & DIR), bitrate_switch=bool(fd_flags & 0x2), error_state_indicator=bool(fd_flags & 0x4), dlc=dlc2len(dlc), data=can_data[:valid_bytes], channel=channel - 1, ) elif obj_type == CAN_FD_MESSAGE_64: members = unpack_can_fd_64_msg(data, pos)[:7] channel, dlc, valid_bytes, _, can_id, _, fd_flags = members pos += can_fd_64_msg_size yield Message( timestamp=timestamp, arbitration_id=can_id & 0x1FFFFFFF, is_extended_id=bool(can_id & CAN_MSG_EXT), is_remote_frame=bool(fd_flags & 0x0010), is_fd=bool(fd_flags & 0x1000), bitrate_switch=bool(fd_flags & 0x2000), error_state_indicator=bool(fd_flags & 0x4000), dlc=dlc2len(dlc), data=data[pos:pos + valid_bytes], channel=channel - 1, ) pos = next_pos
def _recv_internal(self, timeout): end_time = time.time() + timeout if timeout is not None else None if self.fd: event = vxlapi.XLcanRxEvent() else: event = vxlapi.XLevent() event_count = ctypes.c_uint() while True: if self.fd: try: vxlapi.xlCanReceive(self.port_handle, event) except VectorError as exc: if exc.error_code != vxlapi.XL_ERR_QUEUE_IS_EMPTY: raise else: if event.tag == vxlapi.XL_CAN_EV_TAG_RX_OK or event.tag == vxlapi.XL_CAN_EV_TAG_TX_OK: msg_id = event.tagData.canRxOkMsg.canId dlc = dlc2len(event.tagData.canRxOkMsg.dlc) flags = event.tagData.canRxOkMsg.msgFlags timestamp = event.timeStamp * 1e-9 channel = self.index_to_channel.get(event.chanIndex) msg = Message( timestamp=timestamp + self._time_offset, arbitration_id=msg_id & 0x1FFFFFFF, is_extended_id=bool(msg_id & vxlapi.XL_CAN_EXT_MSG_ID), is_remote_frame=bool(flags & vxlapi.XL_CAN_RXMSG_FLAG_RTR), is_error_frame=bool(flags & vxlapi.XL_CAN_RXMSG_FLAG_EF), is_fd=bool(flags & vxlapi.XL_CAN_RXMSG_FLAG_EDL), error_state_indicator=bool(flags & vxlapi.XL_CAN_RXMSG_FLAG_ESI), bitrate_switch=bool(flags & vxlapi.XL_CAN_RXMSG_FLAG_BRS), dlc=dlc, data=event.tagData.canRxOkMsg.data[:dlc], channel=channel) return msg, self._is_filtered else: event_count.value = 1 try: vxlapi.xlReceive(self.port_handle, event_count, event) except VectorError as exc: if exc.error_code != vxlapi.XL_ERR_QUEUE_IS_EMPTY: raise else: if event.tag == vxlapi.XL_RECEIVE_MSG: msg_id = event.tagData.msg.id dlc = event.tagData.msg.dlc flags = event.tagData.msg.flags timestamp = event.timeStamp * 1e-9 channel = self.index_to_channel.get(event.chanIndex) msg = Message( timestamp=timestamp + self._time_offset, arbitration_id=msg_id & 0x1FFFFFFF, is_extended_id=bool(msg_id & vxlapi.XL_CAN_EXT_MSG_ID), is_remote_frame=bool(flags & vxlapi.XL_CAN_MSG_FLAG_REMOTE_FRAME), is_error_frame=bool(flags & vxlapi.XL_CAN_MSG_FLAG_ERROR_FRAME), is_fd=False, dlc=dlc, data=event.tagData.msg.data[:dlc], channel=channel) return msg, self._is_filtered if end_time is not None and time.time() > end_time: return None, self._is_filtered if HAS_EVENTS: # Wait for receive event to occur if timeout is None: time_left_ms = INFINITE else: time_left = end_time - time.time() time_left_ms = max(0, int(time_left * 1000)) WaitForSingleObject(self.event_handle.value, time_left_ms) else: # Wait a short time until we try again time.sleep(self.poll_interval)
def __iter__(self): tail = b"" while True: data = self.file.read(OBJ_HEADER_BASE_STRUCT.size) if not data: # EOF break header = OBJ_HEADER_BASE_STRUCT.unpack(data) if header[0] != b"LOBJ": raise BLFParseError() obj_type = header[4] obj_data_size = header[3] - OBJ_HEADER_BASE_STRUCT.size obj_data = self.file.read(obj_data_size) # Read padding bytes self.file.read(obj_data_size % 4) if obj_type == LOG_CONTAINER: method, uncompressed_size = LOG_CONTAINER_STRUCT.unpack_from( obj_data) container_data = obj_data[LOG_CONTAINER_STRUCT.size:] if method == NO_COMPRESSION: data = container_data elif method == ZLIB_DEFLATE: data = zlib.decompress(container_data, 15, uncompressed_size) else: # Unknown compression method LOG.warning("Unknown compression method (%d)", method) continue if tail: data = tail + data pos = 0 while pos + OBJ_HEADER_BASE_STRUCT.size < len(data): header = OBJ_HEADER_BASE_STRUCT.unpack_from(data, pos) #print(header) if header[0] != b"LOBJ": raise BLFParseError() obj_size = header[3] # Calculate position of next object next_pos = pos + obj_size + (obj_size % 4) if next_pos > len(data): # Object continues in next log container break pos += OBJ_HEADER_BASE_STRUCT.size # Read rest of header header_version = header[2] if header_version == 1: flags, _, _, timestamp = OBJ_HEADER_V1_STRUCT.unpack_from(data, pos) pos += OBJ_HEADER_V1_STRUCT.size elif header_version == 2: flags, _, _, timestamp, _ = OBJ_HEADER_V2_STRUCT.unpack_from(data, pos) pos += OBJ_HEADER_V2_STRUCT.size else: # Unknown header version LOG.warning("Unknown object header version (%d)", header_version) pos = next_pos continue if flags == TIME_TEN_MICS: factor = 10 * 1e-6 else: factor = 1e-9 timestamp = timestamp * factor + self.start_timestamp obj_type = header[4] # Both CAN message types have the same starting content if obj_type in (CAN_MESSAGE, CAN_MESSAGE2): (channel, flags, dlc, can_id, can_data) = CAN_MSG_STRUCT.unpack_from(data, pos) msg = Message(timestamp=timestamp, arbitration_id=can_id & 0x1FFFFFFF, is_extended_id=bool(can_id & CAN_MSG_EXT), is_remote_frame=bool(flags & REMOTE_FLAG), dlc=dlc, data=can_data[:dlc], channel=channel - 1) yield msg elif obj_type == CAN_FD_MESSAGE: (channel, flags, dlc, can_id, _, _, fd_flags, _, can_data) = CAN_FD_MSG_STRUCT.unpack_from(data, pos) length = dlc2len(dlc) msg = Message(timestamp=timestamp, arbitration_id=can_id & 0x1FFFFFFF, is_extended_id=bool(can_id & CAN_MSG_EXT), is_remote_frame=bool(flags & REMOTE_FLAG), is_fd=bool(fd_flags & EDL), bitrate_switch=bool(fd_flags & BRS), error_state_indicator=bool(fd_flags & ESI), dlc=length, data=can_data[:length], channel=channel - 1) yield msg elif obj_type == CAN_FD_MESSAGE_64: ( channel, dlc, _, _, can_id, _, fd_flags ) = CAN_FD_MSG_64_STRUCT.unpack_from(data, pos)[:7] length = dlc2len(dlc) can_data = struct.unpack_from( "<{}s".format(length), data, pos + CAN_FD_MSG_64_STRUCT.size )[0] msg = Message( timestamp=timestamp, arbitration_id=can_id & 0x1FFFFFFF, is_extended_id=bool(can_id & CAN_MSG_EXT), is_remote_frame=bool(fd_flags & REMOTE_FLAG_64), is_fd=bool(fd_flags & EDL_64), bitrate_switch=bool(fd_flags & BRS_64), error_state_indicator=bool(fd_flags & ESI_64), dlc=length, data=can_data[:length], channel=channel - 1 ) yield msg elif obj_type == CAN_ERROR_EXT: (channel, _, _, _, _, dlc, _, can_id, _, can_data) = CAN_ERROR_EXT_STRUCT.unpack_from(data, pos) msg = Message(timestamp=timestamp, is_error_frame=True, is_extended_id=bool(can_id & CAN_MSG_EXT), arbitration_id=can_id & 0x1FFFFFFF, dlc=dlc, data=can_data[:dlc], channel=channel - 1) yield msg # else: # LOG.warning("Unknown object type (%d)", obj_type) pos = next_pos # save the remaining data that could not be processed tail = data[pos:] self.stop()
def _recv_internal(self, timeout): if HAS_EVENTS: # We will utilize events for the timeout handling timeout_ms = int(timeout * 1000) if timeout is not None else INFINITE elif timeout is not None: # Calculate max time end_time = timeout_clock() + timeout #log.debug("Trying to read a msg") result = None while result is None: if self.fd: result = self.m_objPCANBasic.ReadFD(self.m_PcanHandle) else: result = self.m_objPCANBasic.Read(self.m_PcanHandle) if result[0] == PCAN_ERROR_QRCVEMPTY: if HAS_EVENTS: result = None val = WaitForSingleObject(self._recv_event, timeout_ms) if val != WAIT_OBJECT_0: return None, False elif timeout is not None and timeout_clock() >= end_time: return None, False else: result = None time.sleep(0.001) elif result[0] & (PCAN_ERROR_BUSLIGHT | PCAN_ERROR_BUSHEAVY): log.warning(self._get_formatted_error(result[0])) return None, False elif result[0] != PCAN_ERROR_OK: raise PcanError(self._get_formatted_error(result[0])) theMsg = result[1] itsTimeStamp = result[2] #log.debug("Received a message") is_extended_id = ( theMsg.MSGTYPE & PCAN_MESSAGE_EXTENDED.value) == PCAN_MESSAGE_EXTENDED.value is_remote_frame = (theMsg.MSGTYPE & PCAN_MESSAGE_RTR.value) == PCAN_MESSAGE_RTR.value is_fd = (theMsg.MSGTYPE & PCAN_MESSAGE_FD.value) == PCAN_MESSAGE_FD.value bitrate_switch = (theMsg.MSGTYPE & PCAN_MESSAGE_BRS.value) == PCAN_MESSAGE_BRS.value error_state_indicator = ( theMsg.MSGTYPE & PCAN_MESSAGE_ESI.value) == PCAN_MESSAGE_ESI.value is_error_frame = ( theMsg.MSGTYPE & PCAN_MESSAGE_ERRFRAME.value) == PCAN_MESSAGE_ERRFRAME.value if self.fd: dlc = dlc2len(theMsg.DLC) timestamp = boottimeEpoch + (itsTimeStamp.value / (1000.0 * 1000.0)) else: dlc = theMsg.LEN timestamp = boottimeEpoch + ( (itsTimeStamp.micros + 1000 * itsTimeStamp.millis + 0x100000000 * 1000 * itsTimeStamp.millis_overflow) / (1000.0 * 1000.0)) rx_msg = Message(timestamp=timestamp, arbitration_id=theMsg.ID, is_extended_id=is_extended_id, is_remote_frame=is_remote_frame, is_error_frame=is_error_frame, dlc=dlc, data=theMsg.DATA[:dlc], is_fd=is_fd, bitrate_switch=bitrate_switch, error_state_indicator=error_state_indicator) return rx_msg, False
def __iter__(self): tail = b"" while True: data = self.file.read(OBJ_HEADER_BASE_STRUCT.size) if not data: # EOF break header = OBJ_HEADER_BASE_STRUCT.unpack(data) if header[0] != b"LOBJ": raise BLFParseError() obj_type = header[4] obj_data_size = header[3] - OBJ_HEADER_BASE_STRUCT.size obj_data = self.file.read(obj_data_size) # Read padding bytes self.file.read(obj_data_size % 4) if obj_type == LOG_CONTAINER: method, uncompressed_size = LOG_CONTAINER_STRUCT.unpack_from( obj_data) container_data = obj_data[LOG_CONTAINER_STRUCT.size:] if method == NO_COMPRESSION: data = container_data elif method == ZLIB_DEFLATE: data = zlib.decompress(container_data, 15, uncompressed_size) else: # Unknown compression method LOG.warning("Unknown compression method (%d)", method) continue if tail: data = tail + data pos = 0 while pos + OBJ_HEADER_BASE_STRUCT.size < len(data): header = OBJ_HEADER_BASE_STRUCT.unpack_from(data, pos) #print(header) if header[0] != b"LOBJ": raise BLFParseError() obj_size = header[3] # Calculate position of next object next_pos = pos + obj_size + (obj_size % 4) if next_pos > len(data): # Object continues in next log container break pos += OBJ_HEADER_BASE_STRUCT.size # Read rest of header header_version = header[2] if header_version == 1: flags, _, _, timestamp = OBJ_HEADER_V1_STRUCT.unpack_from(data, pos) pos += OBJ_HEADER_V1_STRUCT.size elif header_version == 2: flags, _, _, timestamp, _ = OBJ_HEADER_V2_STRUCT.unpack_from(data, pos) pos += OBJ_HEADER_V2_STRUCT.size else: # Unknown header version LOG.warning("Unknown object header version (%d)", header_version) pos = next_pos continue if flags == TIME_TEN_MICS: factor = 10 * 1e-6 else: factor = 1e-9 timestamp = timestamp * factor + self.start_timestamp obj_type = header[4] # Both CAN message types have the same starting content if obj_type in (CAN_MESSAGE, CAN_MESSAGE2): (channel, flags, dlc, can_id, can_data) = CAN_MSG_STRUCT.unpack_from(data, pos) msg = Message(timestamp=timestamp, arbitration_id=can_id & 0x1FFFFFFF, extended_id=bool(can_id & CAN_MSG_EXT), is_remote_frame=bool(flags & REMOTE_FLAG), dlc=dlc, data=can_data[:dlc], channel=channel - 1) yield msg elif obj_type == CAN_FD_MESSAGE: (channel, flags, dlc, can_id, _, _, fd_flags, _, can_data) = CAN_FD_MSG_STRUCT.unpack_from(data, pos) length = dlc2len(dlc) msg = Message(timestamp=timestamp, arbitration_id=can_id & 0x1FFFFFFF, extended_id=bool(can_id & CAN_MSG_EXT), is_remote_frame=bool(flags & REMOTE_FLAG), is_fd=bool(fd_flags & EDL), bitrate_switch=bool(fd_flags & BRS), error_state_indicator=bool(fd_flags & ESI), dlc=length, data=can_data[:length], channel=channel - 1) yield msg elif obj_type == CAN_ERROR_EXT: (channel, _, _, _, _, dlc, _, can_id, _, can_data) = CAN_ERROR_EXT_STRUCT.unpack_from(data, pos) msg = Message(timestamp=timestamp, is_error_frame=True, extended_id=bool(can_id & CAN_MSG_EXT), arbitration_id=can_id & 0x1FFFFFFF, dlc=dlc, data=can_data[:dlc], channel=channel - 1) yield msg pos = next_pos # save the remaining data that could not be processed tail = data[pos:] self.stop()
def _recv_internal(self, timeout): end_time = time.time() + timeout if timeout is not None else None if self.fd: event = vxlapi.XLcanRxEvent() else: event = vxlapi.XLevent() event_count = ctypes.c_uint() while True: if self.fd: try: vxlapi.xlCanReceive(self.port_handle, event) except VectorError as exc: if exc.error_code != vxlapi.XL_ERR_QUEUE_IS_EMPTY: raise else: if event.tag == vxlapi.XL_CAN_EV_TAG_RX_OK or event.tag == vxlapi.XL_CAN_EV_TAG_TX_OK: msg_id = event.tagData.canRxOkMsg.canId dlc = dlc2len(event.tagData.canRxOkMsg.dlc) flags = event.tagData.canRxOkMsg.msgFlags timestamp = event.timeStamp * 1e-9 channel = self.index_to_channel.get(event.chanIndex) msg = Message( timestamp=timestamp + self._time_offset, arbitration_id=msg_id & 0x1FFFFFFF, extended_id=bool(msg_id & vxlapi.XL_CAN_EXT_MSG_ID), is_remote_frame=bool(flags & vxlapi.XL_CAN_RXMSG_FLAG_RTR), is_error_frame=bool(flags & vxlapi.XL_CAN_RXMSG_FLAG_EF), is_fd=bool(flags & vxlapi.XL_CAN_RXMSG_FLAG_EDL), error_state_indicator=bool(flags & vxlapi.XL_CAN_RXMSG_FLAG_ESI), bitrate_switch=bool(flags & vxlapi.XL_CAN_RXMSG_FLAG_BRS), dlc=dlc, data=event.tagData.canRxOkMsg.data[:dlc], channel=channel) return msg, self._is_filtered else: event_count.value = 1 try: vxlapi.xlReceive(self.port_handle, event_count, event) except VectorError as exc: if exc.error_code != vxlapi.XL_ERR_QUEUE_IS_EMPTY: raise else: if event.tag == vxlapi.XL_RECEIVE_MSG: msg_id = event.tagData.msg.id dlc = event.tagData.msg.dlc flags = event.tagData.msg.flags timestamp = event.timeStamp * 1e-9 channel = self.index_to_channel.get(event.chanIndex) msg = Message( timestamp=timestamp + self._time_offset, arbitration_id=msg_id & 0x1FFFFFFF, extended_id=bool(msg_id & vxlapi.XL_CAN_EXT_MSG_ID), is_remote_frame=bool(flags & vxlapi.XL_CAN_MSG_FLAG_REMOTE_FRAME), is_error_frame=bool(flags & vxlapi.XL_CAN_MSG_FLAG_ERROR_FRAME), is_fd=False, dlc=dlc, data=event.tagData.msg.data[:dlc], channel=channel) return msg, self._is_filtered if end_time is not None and time.time() > end_time: return None, self._is_filtered if HAS_EVENTS: # Wait for receive event to occur if timeout is None: time_left_ms = INFINITE else: time_left = end_time - time.time() time_left_ms = max(0, int(time_left * 1000)) WaitForSingleObject(self.event_handle.value, time_left_ms) else: # Wait a short time until we try again time.sleep(self.poll_interval)