|
7 | 7 | Implementation references:
|
8 | 8 | * https://github.com/intrepidcs/python_ics
|
9 | 9 | """
|
| 10 | + |
10 | 11 | import functools
|
11 | 12 | import logging
|
12 | 13 | import os
|
@@ -135,6 +136,7 @@ def check_if_bus_open(func):
|
135 | 136 |
|
136 | 137 | If the bus is not open, it raises a CanOperationError.
|
137 | 138 | """
|
| 139 | + |
138 | 140 | @functools.wraps(func)
|
139 | 141 | def wrapper(self, *args, **kwargs):
|
140 | 142 | """
|
@@ -432,91 +434,72 @@ def _recv_internal(self, timeout=0.1):
|
432 | 434 |
|
433 | 435 | @check_if_bus_open
|
434 | 436 | def send(self, msg, timeout=0):
|
435 |
| - """Transmit a message to the CAN bus. |
436 |
| -
|
437 |
| - :param Message msg: A message object. |
438 |
| -
|
439 |
| - :param float timeout: |
440 |
| - If > 0, wait up to this many seconds for message to be ACK'ed. |
441 |
| - If timeout is exceeded, an exception will be raised. |
442 |
| - None blocks indefinitely. |
443 |
| -
|
444 |
| - :raises ValueError: |
445 |
| - if the message is invalid |
446 |
| - :raises can.CanTimeoutError: |
447 |
| - if sending timed out |
448 |
| - :raises CanOperationError: |
449 |
| - If the bus is closed or the message could otherwise not be sent. |
450 |
| - May or may not be a :class:`~ICSOperationError`. |
| 437 | + """ |
| 438 | + Sends a message over the CAN bus. |
| 439 | +
|
| 440 | + :param msg: The CAN message to be sent. |
| 441 | + :type msg: can.Message |
| 442 | + :param timeout: The maximum amount of time to wait for the message to be sent. |
| 443 | + :type timeout: float |
| 444 | +
|
| 445 | + :raises CanOperationError: If the bus is not open. |
| 446 | + :raises ValueError: If the DLC of the message is greater than the maximum allowed. |
| 447 | + :raises ICSOperationError: If there is an error in transmitting the message. |
| 448 | + :raises CanTimeoutError: If the message could not be sent within the specified timeout. |
451 | 449 | """
|
452 | 450 | if not ics.validate_hobject(self.dev):
|
453 | 451 | raise CanOperationError("bus not open")
|
454 | 452 |
|
455 |
| - # Check for valid DLC to avoid passing extra long data to the driver |
456 |
| - if msg.is_fd: |
457 |
| - if msg.dlc > 64: |
458 |
| - raise ValueError( |
459 |
| - f"DLC was {msg.dlc} but it should be <= 64 for CAN FD frames" |
460 |
| - ) |
461 |
| - elif msg.dlc > 8: |
| 453 | + if msg.is_fd and msg.dlc > 64 or not msg.is_fd and msg.dlc > 8: |
462 | 454 | raise ValueError(
|
463 |
| - f"DLC was {msg.dlc} but it should be <= 8 for normal CAN frames" |
| 455 | + f"DLC was {msg.dlc} but it should be <= {64 if msg.is_fd else 8}" |
464 | 456 | )
|
465 | 457 |
|
466 | 458 | message = ics.SpyMessage()
|
| 459 | + message.ArbIDOrHeader = msg.arbitration_id |
| 460 | + message.NumberBytesData = msg.dlc |
| 461 | + message.Data = tuple(msg.data[:8]) |
| 462 | + message.StatusBitField = 0 |
| 463 | + message.StatusBitField2 = 0 |
| 464 | + message.StatusBitField3 = 0 |
467 | 465 |
|
468 |
| - flag0 = 0 |
469 | 466 | if msg.is_extended_id:
|
470 |
| - flag0 |= ics.SPY_STATUS_XTD_FRAME |
| 467 | + message.StatusBitField |= ics.SPY_STATUS_XTD_FRAME |
471 | 468 | if msg.is_remote_frame:
|
472 |
| - flag0 |= ics.SPY_STATUS_REMOTE_FRAME |
473 |
| - |
474 |
| - flag3 = 0 |
| 469 | + message.StatusBitField |= ics.SPY_STATUS_REMOTE_FRAME |
475 | 470 | if msg.is_fd:
|
476 | 471 | message.Protocol = ics.SPY_PROTOCOL_CANFD
|
477 | 472 | if msg.bitrate_switch:
|
478 |
| - flag3 |= ics.SPY_STATUS3_CANFD_BRS |
| 473 | + message.StatusBitField3 |= ics.SPY_STATUS3_CANFD_BRS |
479 | 474 | if msg.error_state_indicator:
|
480 |
| - flag3 |= ics.SPY_STATUS3_CANFD_ESI |
481 |
| - |
482 |
| - message.ArbIDOrHeader = msg.arbitration_id |
483 |
| - msg_data = msg.data[: msg.dlc] |
484 |
| - message.NumberBytesData = msg.dlc |
485 |
| - message.Data = tuple(msg_data[:8]) |
486 |
| - if msg.is_fd and len(msg_data) > 8: |
487 |
| - message.ExtraDataPtrEnabled = 1 |
488 |
| - message.ExtraDataPtr = tuple(msg_data) |
489 |
| - message.StatusBitField = flag0 |
490 |
| - message.StatusBitField2 = 0 |
491 |
| - message.StatusBitField3 = flag3 |
492 |
| - if msg.channel is not None: |
493 |
| - network_id = msg.channel |
494 |
| - elif len(self.channels) == 1: |
495 |
| - network_id = self.channels[0] |
496 |
| - else: |
| 475 | + message.StatusBitField3 |= ics.SPY_STATUS3_CANFD_ESI |
| 476 | + if len(msg.data) > 8: |
| 477 | + message.ExtraDataPtrEnabled = 1 |
| 478 | + message.ExtraDataPtr = tuple(msg.data) |
| 479 | + |
| 480 | + network_id = ( |
| 481 | + msg.channel |
| 482 | + if msg.channel is not None |
| 483 | + else self.channels[0] if len(self.channels) == 1 else None |
| 484 | + ) |
| 485 | + if network_id is None: |
497 | 486 | raise ValueError("msg.channel must be set when using multiple channels.")
|
498 |
| - |
499 | 487 | message.NetworkID, message.NetworkID2 = int(network_id & 0xFF), int(
|
500 | 488 | (network_id >> 8) & 0xFF
|
501 | 489 | )
|
502 | 490 |
|
503 | 491 | if timeout != 0:
|
504 | 492 | msg_desc_id = next(description_id)
|
505 | 493 | message.DescriptionID = msg_desc_id
|
506 |
| - receipt_key = (msg.arbitration_id, msg_desc_id) |
507 |
| - self.message_receipts[receipt_key].clear() |
| 494 | + self.message_receipts[(msg.arbitration_id, msg_desc_id)].clear() |
508 | 495 |
|
509 | 496 | try:
|
510 | 497 | ics.transmit_messages(self.dev, message)
|
511 | 498 | except ics.RuntimeError:
|
512 | 499 | raise ICSOperationError(*ics.get_last_api_error(self.dev)) from None
|
513 | 500 |
|
514 |
| - # If timeout is set, wait for ACK |
515 |
| - # This requires a notifier for the bus or |
516 |
| - # some other thread calling recv periodically |
517 |
| - if timeout != 0: |
518 |
| - got_receipt = self.message_receipts[receipt_key].wait(timeout) |
519 |
| - # We no longer need this receipt, so no point keeping it in memory |
520 |
| - del self.message_receipts[receipt_key] |
521 |
| - if not got_receipt: |
522 |
| - raise CanTimeoutError("Transmit timeout") |
| 501 | + if timeout != 0 and not self.message_receipts[ |
| 502 | + (msg.arbitration_id, msg_desc_id) |
| 503 | + ].wait(timeout): |
| 504 | + del self.message_receipts[(msg.arbitration_id, msg_desc_id)] |
| 505 | + raise CanTimeoutError("Transmit timeout") |
0 commit comments