Skip to content

Commit aad0fc4

Browse files
committed
Merge remote-tracking branch 'upstream/develop' into xlSetApplConfig
# Conflicts: # can/interfaces/vector/canlib.py
2 parents 3b8c23e + 902eac0 commit aad0fc4

File tree

2 files changed

+148
-99
lines changed

2 files changed

+148
-99
lines changed

can/interfaces/ics_neovi/neovi_bus.py

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
import logging
1212
import os
1313
import tempfile
14-
from collections import deque
14+
from collections import deque, defaultdict
15+
from itertools import cycle
16+
from threading import Event
1517

1618
from can import Message, CanError, BusABC
1719

@@ -55,6 +57,7 @@ def __exit__(self, exc_type, exc_val, exc_tb):
5557
# Use inter-process mutex to prevent concurrent device open.
5658
# When neoVI server is enabled, there is an issue with concurrent device open.
5759
open_lock = FileLock(os.path.join(tempfile.gettempdir(), "neovi.lock"))
60+
description_id = cycle(range(1, 0x8000))
5861

5962

6063
class ICSApiError(CanError):
@@ -176,6 +179,7 @@ def __init__(self, channel, can_filters=None, **kwargs):
176179
logger.info("Using device: {}".format(self.channel_info))
177180

178181
self.rx_buffer = deque()
182+
self.message_receipts = defaultdict(Event)
179183

180184
@staticmethod
181185
def channel_to_netid(channel_name_or_id):
@@ -261,9 +265,18 @@ def _process_msg_queue(self, timeout=0.1):
261265
for ics_msg in messages:
262266
if ics_msg.NetworkID not in self.channels:
263267
continue
268+
264269
is_tx = bool(ics_msg.StatusBitField & ics.SPY_STATUS_TX_MSG)
265-
if not self._receive_own_messages and is_tx:
266-
continue
270+
271+
if is_tx:
272+
if bool(ics_msg.StatusBitField & ics.SPY_STATUS_GLOBAL_ERR):
273+
continue
274+
if ics_msg.DescriptionID:
275+
receipt_key = (ics_msg.ArbIDOrHeader, ics_msg.DescriptionID)
276+
self.message_receipts[receipt_key].set()
277+
if not self._receive_own_messages:
278+
continue
279+
267280
self.rx_buffer.append(ics_msg)
268281
if errors:
269282
logger.warning("%d error(s) found", errors)
@@ -343,7 +356,19 @@ def _recv_internal(self, timeout=0.1):
343356
return None, False
344357
return msg, False
345358

346-
def send(self, msg, timeout=None):
359+
def send(self, msg, timeout=0):
360+
"""Transmit a message to the CAN bus.
361+
362+
:param Message msg: A message object.
363+
364+
:param float timeout:
365+
If > 0, wait up to this many seconds for message to be ACK'ed.
366+
If timeout is exceeded, an exception will be raised.
367+
None blocks indefinitely.
368+
369+
:raises can.CanError:
370+
if the message could not be sent
371+
"""
347372
if not ics.validate_hobject(self.dev):
348373
raise CanError("bus not open")
349374
message = ics.SpyMessage()
@@ -379,7 +404,20 @@ def send(self, msg, timeout=None):
379404
else:
380405
raise ValueError("msg.channel must be set when using multiple channels.")
381406

407+
msg_desc_id = next(description_id)
408+
message.DescriptionID = msg_desc_id
409+
receipt_key = (msg.arbitration_id, msg_desc_id)
410+
411+
if timeout != 0:
412+
self.message_receipts[receipt_key].clear()
413+
382414
try:
383415
ics.transmit_messages(self.dev, message)
384416
except ics.RuntimeError:
385417
raise ICSApiError(*ics.get_last_api_error(self.dev))
418+
419+
# If timeout is set, wait for ACK
420+
# This requires a notifier for the bus or
421+
# some other thread calling recv periodically
422+
if timeout != 0 and not self.message_receipts[receipt_key].wait(timeout):
423+
raise CanError("Transmit timeout")

can/interfaces/vector/canlib.py

Lines changed: 106 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import logging
1111
import time
1212
import os
13-
from typing import Tuple, List
13+
from typing import List, Optional, Tuple
1414

1515
try:
1616
# Try builtin Python 3 Windows API
@@ -333,112 +333,32 @@ def _apply_filters(self, filters):
333333
except VectorError as exc:
334334
LOG.warning("Could not reset filters: %s", exc)
335335

336-
def _recv_internal(self, timeout):
336+
def _recv_internal(
337+
self, timeout: Optional[float]
338+
) -> Tuple[Optional[Message], bool]:
337339
end_time = time.time() + timeout if timeout is not None else None
338340

339-
if self.fd:
340-
event = xlclass.XLcanRxEvent()
341-
else:
342-
event = xlclass.XLevent()
343-
344341
while True:
345-
if self.fd:
346-
try:
347-
xldriver.xlCanReceive(self.port_handle, event)
348-
except VectorError as exc:
349-
if exc.error_code != xldefine.XL_Status.XL_ERR_QUEUE_IS_EMPTY.value:
350-
raise
342+
try:
343+
if self.fd:
344+
msg = self._recv_canfd()
351345
else:
352-
if (
353-
event.tag
354-
== xldefine.XL_CANFD_RX_EventTags.XL_CAN_EV_TAG_RX_OK.value
355-
or event.tag
356-
== xldefine.XL_CANFD_RX_EventTags.XL_CAN_EV_TAG_TX_OK.value
357-
):
358-
msg_id = event.tagData.canRxOkMsg.canId
359-
dlc = dlc2len(event.tagData.canRxOkMsg.dlc)
360-
flags = event.tagData.canRxOkMsg.msgFlags
361-
timestamp = event.timeStamp * 1e-9
362-
channel = self.index_to_channel.get(event.chanIndex)
363-
msg = Message(
364-
timestamp=timestamp + self._time_offset,
365-
arbitration_id=msg_id & 0x1FFFFFFF,
366-
is_extended_id=bool(
367-
msg_id
368-
& xldefine.XL_MessageFlagsExtended.XL_CAN_EXT_MSG_ID.value
369-
),
370-
is_remote_frame=bool(
371-
flags
372-
& xldefine.XL_CANFD_RX_MessageFlags.XL_CAN_RXMSG_FLAG_RTR.value
373-
),
374-
is_error_frame=bool(
375-
flags
376-
& xldefine.XL_CANFD_RX_MessageFlags.XL_CAN_RXMSG_FLAG_EF.value
377-
),
378-
is_fd=bool(
379-
flags
380-
& xldefine.XL_CANFD_RX_MessageFlags.XL_CAN_RXMSG_FLAG_EDL.value
381-
),
382-
error_state_indicator=bool(
383-
flags
384-
& xldefine.XL_CANFD_RX_MessageFlags.XL_CAN_RXMSG_FLAG_ESI.value
385-
),
386-
bitrate_switch=bool(
387-
flags
388-
& xldefine.XL_CANFD_RX_MessageFlags.XL_CAN_RXMSG_FLAG_BRS.value
389-
),
390-
dlc=dlc,
391-
data=event.tagData.canRxOkMsg.data[:dlc],
392-
channel=channel,
393-
)
394-
return msg, self._is_filtered
395-
else:
396-
self.handle_canfd_event(event)
346+
msg = self._recv_can()
397347

348+
except VectorError as exc:
349+
if exc.error_code != xldefine.XL_Status.XL_ERR_QUEUE_IS_EMPTY.value:
350+
raise
398351
else:
399-
event_count = ctypes.c_uint(1)
400-
try:
401-
xldriver.xlReceive(self.port_handle, event_count, event)
402-
except VectorError as exc:
403-
if exc.error_code != xldefine.XL_Status.XL_ERR_QUEUE_IS_EMPTY.value:
404-
raise
405-
else:
406-
if event.tag == xldefine.XL_EventTags.XL_RECEIVE_MSG.value:
407-
msg_id = event.tagData.msg.id
408-
dlc = event.tagData.msg.dlc
409-
flags = event.tagData.msg.flags
410-
timestamp = event.timeStamp * 1e-9
411-
channel = self.index_to_channel.get(event.chanIndex)
412-
msg = Message(
413-
timestamp=timestamp + self._time_offset,
414-
arbitration_id=msg_id & 0x1FFFFFFF,
415-
is_extended_id=bool(
416-
msg_id
417-
& xldefine.XL_MessageFlagsExtended.XL_CAN_EXT_MSG_ID.value
418-
),
419-
is_remote_frame=bool(
420-
flags
421-
& xldefine.XL_MessageFlags.XL_CAN_MSG_FLAG_REMOTE_FRAME.value
422-
),
423-
is_error_frame=bool(
424-
flags
425-
& xldefine.XL_MessageFlags.XL_CAN_MSG_FLAG_ERROR_FRAME.value
426-
),
427-
is_fd=False,
428-
dlc=dlc,
429-
data=event.tagData.msg.data[:dlc],
430-
channel=channel,
431-
)
432-
return msg, self._is_filtered
433-
else:
434-
self.handle_can_event(event)
352+
if msg:
353+
return msg, self._is_filtered
435354

355+
# if no message was received, wait or return on timeout
436356
if end_time is not None and time.time() > end_time:
437357
return None, self._is_filtered
438358

439359
if HAS_EVENTS:
440360
# Wait for receive event to occur
441-
if timeout is None:
361+
if end_time is None:
442362
time_left_ms = INFINITE
443363
else:
444364
time_left = end_time - time.time()
@@ -448,6 +368,97 @@ def _recv_internal(self, timeout):
448368
# Wait a short time until we try again
449369
time.sleep(self.poll_interval)
450370

371+
def _recv_canfd(self) -> Optional[Message]:
372+
xl_can_rx_event = xlclass.XLcanRxEvent()
373+
xldriver.xlCanReceive(self.port_handle, xl_can_rx_event)
374+
375+
if (
376+
xl_can_rx_event.tag
377+
== xldefine.XL_CANFD_RX_EventTags.XL_CAN_EV_TAG_RX_OK.value
378+
):
379+
is_rx = True
380+
data_struct = xl_can_rx_event.tagData.canRxOkMsg
381+
elif (
382+
xl_can_rx_event.tag
383+
== xldefine.XL_CANFD_RX_EventTags.XL_CAN_EV_TAG_TX_OK.value
384+
):
385+
is_rx = False
386+
data_struct = xl_can_rx_event.tagData.canTxOkMsg
387+
else:
388+
self.handle_canfd_event(xl_can_rx_event)
389+
return
390+
391+
msg_id = data_struct.canId
392+
dlc = dlc2len(data_struct.dlc)
393+
flags = data_struct.msgFlags
394+
timestamp = xl_can_rx_event.timeStamp * 1e-9
395+
channel = self.index_to_channel.get(xl_can_rx_event.chanIndex)
396+
397+
msg = Message(
398+
timestamp=timestamp + self._time_offset,
399+
arbitration_id=msg_id & 0x1FFFFFFF,
400+
is_extended_id=bool(
401+
msg_id & xldefine.XL_MessageFlagsExtended.XL_CAN_EXT_MSG_ID.value
402+
),
403+
is_remote_frame=bool(
404+
flags & xldefine.XL_CANFD_RX_MessageFlags.XL_CAN_RXMSG_FLAG_RTR.value
405+
),
406+
is_error_frame=bool(
407+
flags & xldefine.XL_CANFD_RX_MessageFlags.XL_CAN_RXMSG_FLAG_EF.value
408+
),
409+
is_fd=bool(
410+
flags & xldefine.XL_CANFD_RX_MessageFlags.XL_CAN_RXMSG_FLAG_EDL.value
411+
),
412+
bitrate_switch=bool(
413+
flags & xldefine.XL_CANFD_RX_MessageFlags.XL_CAN_RXMSG_FLAG_BRS.value
414+
),
415+
error_state_indicator=bool(
416+
flags & xldefine.XL_CANFD_RX_MessageFlags.XL_CAN_RXMSG_FLAG_ESI.value
417+
),
418+
is_rx=is_rx,
419+
channel=channel,
420+
dlc=dlc,
421+
data=data_struct.data[:dlc],
422+
)
423+
return msg
424+
425+
def _recv_can(self) -> Optional[Message]:
426+
xl_event = xlclass.XLevent()
427+
event_count = ctypes.c_uint(1)
428+
xldriver.xlReceive(self.port_handle, event_count, xl_event)
429+
430+
if xl_event.tag != xldefine.XL_EventTags.XL_RECEIVE_MSG.value:
431+
self.handle_can_event(xl_event)
432+
return
433+
434+
msg_id = xl_event.tagData.msg.id
435+
dlc = xl_event.tagData.msg.dlc
436+
flags = xl_event.tagData.msg.flags
437+
timestamp = xl_event.timeStamp * 1e-9
438+
channel = self.index_to_channel.get(xl_event.chanIndex)
439+
440+
msg = Message(
441+
timestamp=timestamp + self._time_offset,
442+
arbitration_id=msg_id & 0x1FFFFFFF,
443+
is_extended_id=bool(
444+
msg_id & xldefine.XL_MessageFlagsExtended.XL_CAN_EXT_MSG_ID.value
445+
),
446+
is_remote_frame=bool(
447+
flags & xldefine.XL_MessageFlags.XL_CAN_MSG_FLAG_REMOTE_FRAME.value
448+
),
449+
is_error_frame=bool(
450+
flags & xldefine.XL_MessageFlags.XL_CAN_MSG_FLAG_ERROR_FRAME.value
451+
),
452+
is_rx=not bool(
453+
flags & xldefine.XL_MessageFlags.XL_CAN_MSG_FLAG_TX_COMPLETED.value
454+
),
455+
is_fd=False,
456+
dlc=dlc,
457+
data=xl_event.tagData.msg.data[:dlc],
458+
channel=channel,
459+
)
460+
return msg
461+
451462
def handle_can_event(self, event: xlclass.XLevent) -> None:
452463
"""Handle non-message CAN events.
453464

0 commit comments

Comments
 (0)