pamoja.can
Idiomatic CAN facade.
CAN is how the moving parts of a machine talk to each other: motor controllers, servos, battery management, and the engines and farm equipment that speak J1939 on top of it. This is the identifier and payload layer; the controller hardware handles the wire itself.
1"""Idiomatic CAN facade. 2 3CAN is how the moving parts of a machine talk to each other: motor controllers, 4servos, battery management, and the engines and farm equipment that speak J1939 on 5top of it. This is the identifier and payload layer; the controller hardware 6handles the wire itself. 7""" 8 9from __future__ import annotations 10 11from enum import IntEnum 12 13from pamoja._native import CanFrame, J1939Message, Signals 14from pamoja._native import can_dlc_to_len as _dlc_to_len 15from pamoja._native import can_fd_frame as _fd_frame 16from pamoja._native import can_frame as _frame 17from pamoja._native import can_len_to_dlc as _len_to_dlc 18from pamoja._native import can_remote_frame as _remote_frame 19from pamoja._native import j1939_compose as _j1939_compose 20from pamoja._native import j1939_broadcast as _j1939_broadcast 21from pamoja._native import j1939_decode as _j1939_decode 22from pamoja._native import j1939_limits as _limits 23 24__all__ = [ 25 "BROADCAST_ADDRESS", 26 "NOT_AVAILABLE", 27 "CanFrame", 28 "J1939Message", 29 "Priority", 30 "Signals", 31 "broadcast_j1939", 32 "compose_j1939", 33 "decode_j1939", 34 "dlc_to_len", 35 "fd_frame", 36 "frame", 37 "len_to_dlc", 38 "remote_frame", 39 "signals", 40 "signals_from", 41] 42 43_NOT_AVAILABLE, _BROADCAST_ADDRESS, _CONTROL, _DEFAULT, _LOWEST = _limits() 44 45#: The byte a J1939 sender writes for a signal it is not reporting. 46NOT_AVAILABLE = _NOT_AVAILABLE 47 48#: The destination address every node on the bus reads. 49BROADCAST_ADDRESS = _BROADCAST_ADDRESS 50 51 52class Priority(IntEnum): 53 """The priorities J1939 publishes, so a caller does not write the number out.""" 54 55 CONTROL = _CONTROL 56 """Ahead of ordinary traffic, for a message that controls something.""" 57 58 DEFAULT = _DEFAULT 59 """What ordinary traffic uses.""" 60 61 LOWEST = _LOWEST 62 """Yields to everything else on the bus.""" 63 64 65def signals() -> Signals: 66 """Build a J1939 payload with every signal marked not available. 67 68 :returns: Eight bytes a controller writes only its own signals into. 69 """ 70 return Signals() 71 72 73def signals_from(data: bytes) -> Signals: 74 """Read the eight data bytes of a frame that arrived off the bus. 75 76 :param data: The frame's payload. 77 :returns: The payload, ready for its signals to be read out. 78 :raises PamojaError: The payload is not exactly eight bytes. 79 """ 80 return Signals.from_bytes(data) 81 82 83def frame(identifier: int, data: bytes, extended: bool = False) -> CanFrame: 84 """Build a classic CAN 2.0 frame. 85 86 :param identifier: The arbitration identifier, masked to the width ``extended`` 87 selects. 88 :param data: The payload, at most eight bytes. 89 :param extended: Whether the identifier is a 29-bit extended one. 90 :returns: The frame. 91 :raises PamojaError: If the payload is longer than a classic frame carries. 92 """ 93 return _frame(identifier, extended, bytes(data)) 94 95 96def fd_frame(identifier: int, data: bytes, extended: bool = False) -> CanFrame: 97 """Build a CAN-FD frame, which carries up to 64 bytes. 98 99 :param identifier: The arbitration identifier. 100 :param data: The payload, at one of the discrete CAN-FD lengths: 0 to 8, then 101 12, 16, 20, 24, 32, 48, or 64 bytes. 102 :param extended: Whether the identifier is a 29-bit extended one. 103 :returns: The frame. 104 :raises PamojaError: If the payload length is not one CAN-FD can carry. 105 """ 106 return _fd_frame(identifier, extended, bytes(data)) 107 108 109def remote_frame(identifier: int, length: int, extended: bool = False) -> CanFrame: 110 """Build a remote transmission request, which asks another node to send. 111 112 :param identifier: The arbitration identifier. 113 :param length: The data length being requested, clamped to eight bytes. 114 :param extended: Whether the identifier is a 29-bit extended one. 115 :returns: The frame, which carries no payload of its own. 116 """ 117 return _remote_frame(identifier, extended, length) 118 119 120def len_to_dlc(length: int) -> int: 121 """Return the data length code that encodes a payload length. 122 123 :param length: The payload length in bytes. 124 :returns: The code, rounding up to the next length CAN-FD can carry. 125 """ 126 return _len_to_dlc(length) 127 128 129def dlc_to_len(dlc: int) -> int: 130 """Return the payload length a data length code encodes. 131 132 :param dlc: The data length code. 133 :returns: The length in bytes. 134 """ 135 return _dlc_to_len(dlc) 136 137 138def decode_j1939(identifier: int, extended: bool = True) -> J1939Message | None: 139 """Decode the J1939 fields out of an extended CAN identifier. 140 141 :param identifier: The identifier as it arrived. 142 :param extended: Whether it is a 29-bit extended identifier. 143 :returns: The decoded message, or ``None`` for a standard identifier, which 144 J1939 does not use. 145 """ 146 return _j1939_decode(identifier, extended) 147 148 149def compose_j1939(priority: int, pgn: int, source: int, destination: int = 0) -> int: 150 """Compose the extended CAN identifier a set of J1939 fields describes. 151 152 :param priority: The message priority, 0 (highest) to 7. 153 :param pgn: The parameter group number. 154 :param source: The address of the sending node. 155 :param destination: The destination address, used only for an addressed (PDU1) 156 parameter group and ignored for a broadcast (PDU2) one. 157 :returns: The 29-bit identifier. 158 """ 159 return _j1939_compose(priority, pgn, source, destination) 160 161 162def broadcast_j1939(priority: int, pgn: int, source: int) -> int: 163 """Compose the identifier of a J1939 broadcast, which every node reads. 164 165 Most parameter groups are broadcast, so this is the common case; it saves a 166 caller knowing that a broadcast is addressed to ``0xFF``. 167 168 :param priority: The message priority, 0 (highest) to 7. 169 :param pgn: The parameter group number. 170 :param source: The address of the sending node. 171 :returns: The 29-bit identifier. 172 """ 173 return _j1939_broadcast(priority, pgn, source)
A CAN frame: an identifier, its flags, and its payload.
The fields J1939 packs into an extended CAN identifier.
53class Priority(IntEnum): 54 """The priorities J1939 publishes, so a caller does not write the number out.""" 55 56 CONTROL = _CONTROL 57 """Ahead of ordinary traffic, for a message that controls something.""" 58 59 DEFAULT = _DEFAULT 60 """What ordinary traffic uses.""" 61 62 LOWEST = _LOWEST 63 """Yields to everything else on the bus."""
The priorities J1939 publishes, so a caller does not write the number out.
The eight data bytes of a J1939 frame, addressed by the signals inside them.
A parameter group places each signal at a fixed byte offset, little-endian. A payload starts with every signal marked not available, so a controller writes only the signals it actually reports.
Writes a two-byte little-endian signal at the offset its group defines.
163def broadcast_j1939(priority: int, pgn: int, source: int) -> int: 164 """Compose the identifier of a J1939 broadcast, which every node reads. 165 166 Most parameter groups are broadcast, so this is the common case; it saves a 167 caller knowing that a broadcast is addressed to ``0xFF``. 168 169 :param priority: The message priority, 0 (highest) to 7. 170 :param pgn: The parameter group number. 171 :param source: The address of the sending node. 172 :returns: The 29-bit identifier. 173 """ 174 return _j1939_broadcast(priority, pgn, source)
Compose the identifier of a J1939 broadcast, which every node reads.
Most parameter groups are broadcast, so this is the common case; it saves a
caller knowing that a broadcast is addressed to 0xFF.
Parameters
- priority: The message priority, 0 (highest) to 7.
- pgn: The parameter group number.
- source: The address of the sending node. :returns: The 29-bit identifier.
150def compose_j1939(priority: int, pgn: int, source: int, destination: int = 0) -> int: 151 """Compose the extended CAN identifier a set of J1939 fields describes. 152 153 :param priority: The message priority, 0 (highest) to 7. 154 :param pgn: The parameter group number. 155 :param source: The address of the sending node. 156 :param destination: The destination address, used only for an addressed (PDU1) 157 parameter group and ignored for a broadcast (PDU2) one. 158 :returns: The 29-bit identifier. 159 """ 160 return _j1939_compose(priority, pgn, source, destination)
Compose the extended CAN identifier a set of J1939 fields describes.
Parameters
- priority: The message priority, 0 (highest) to 7.
- pgn: The parameter group number.
- source: The address of the sending node.
- destination: The destination address, used only for an addressed (PDU1) parameter group and ignored for a broadcast (PDU2) one. :returns: The 29-bit identifier.
139def decode_j1939(identifier: int, extended: bool = True) -> J1939Message | None: 140 """Decode the J1939 fields out of an extended CAN identifier. 141 142 :param identifier: The identifier as it arrived. 143 :param extended: Whether it is a 29-bit extended identifier. 144 :returns: The decoded message, or ``None`` for a standard identifier, which 145 J1939 does not use. 146 """ 147 return _j1939_decode(identifier, extended)
Decode the J1939 fields out of an extended CAN identifier.
Parameters
- identifier: The identifier as it arrived.
- extended: Whether it is a 29-bit extended identifier.
:returns: The decoded message, or
Nonefor a standard identifier, which J1939 does not use.
130def dlc_to_len(dlc: int) -> int: 131 """Return the payload length a data length code encodes. 132 133 :param dlc: The data length code. 134 :returns: The length in bytes. 135 """ 136 return _dlc_to_len(dlc)
Return the payload length a data length code encodes.
Parameters
- dlc: The data length code. :returns: The length in bytes.
97def fd_frame(identifier: int, data: bytes, extended: bool = False) -> CanFrame: 98 """Build a CAN-FD frame, which carries up to 64 bytes. 99 100 :param identifier: The arbitration identifier. 101 :param data: The payload, at one of the discrete CAN-FD lengths: 0 to 8, then 102 12, 16, 20, 24, 32, 48, or 64 bytes. 103 :param extended: Whether the identifier is a 29-bit extended one. 104 :returns: The frame. 105 :raises PamojaError: If the payload length is not one CAN-FD can carry. 106 """ 107 return _fd_frame(identifier, extended, bytes(data))
Build a CAN-FD frame, which carries up to 64 bytes.
Parameters
- identifier: The arbitration identifier.
- data: The payload, at one of the discrete CAN-FD lengths: 0 to 8, then 12, 16, 20, 24, 32, 48, or 64 bytes.
- extended: Whether the identifier is a 29-bit extended one. :returns: The frame.
Raises
- PamojaError: If the payload length is not one CAN-FD can carry.
84def frame(identifier: int, data: bytes, extended: bool = False) -> CanFrame: 85 """Build a classic CAN 2.0 frame. 86 87 :param identifier: The arbitration identifier, masked to the width ``extended`` 88 selects. 89 :param data: The payload, at most eight bytes. 90 :param extended: Whether the identifier is a 29-bit extended one. 91 :returns: The frame. 92 :raises PamojaError: If the payload is longer than a classic frame carries. 93 """ 94 return _frame(identifier, extended, bytes(data))
Build a classic CAN 2.0 frame.
Parameters
- identifier: The arbitration identifier, masked to the width
extendedselects. - data: The payload, at most eight bytes.
- extended: Whether the identifier is a 29-bit extended one. :returns: The frame.
Raises
- PamojaError: If the payload is longer than a classic frame carries.
121def len_to_dlc(length: int) -> int: 122 """Return the data length code that encodes a payload length. 123 124 :param length: The payload length in bytes. 125 :returns: The code, rounding up to the next length CAN-FD can carry. 126 """ 127 return _len_to_dlc(length)
Return the data length code that encodes a payload length.
Parameters
- length: The payload length in bytes. :returns: The code, rounding up to the next length CAN-FD can carry.
110def remote_frame(identifier: int, length: int, extended: bool = False) -> CanFrame: 111 """Build a remote transmission request, which asks another node to send. 112 113 :param identifier: The arbitration identifier. 114 :param length: The data length being requested, clamped to eight bytes. 115 :param extended: Whether the identifier is a 29-bit extended one. 116 :returns: The frame, which carries no payload of its own. 117 """ 118 return _remote_frame(identifier, extended, length)
Build a remote transmission request, which asks another node to send.
Parameters
- identifier: The arbitration identifier.
- length: The data length being requested, clamped to eight bytes.
- extended: Whether the identifier is a 29-bit extended one. :returns: The frame, which carries no payload of its own.
66def signals() -> Signals: 67 """Build a J1939 payload with every signal marked not available. 68 69 :returns: Eight bytes a controller writes only its own signals into. 70 """ 71 return Signals()
Build a J1939 payload with every signal marked not available.
:returns: Eight bytes a controller writes only its own signals into.
74def signals_from(data: bytes) -> Signals: 75 """Read the eight data bytes of a frame that arrived off the bus. 76 77 :param data: The frame's payload. 78 :returns: The payload, ready for its signals to be read out. 79 :raises PamojaError: The payload is not exactly eight bytes. 80 """ 81 return Signals.from_bytes(data)
Read the eight data bytes of a frame that arrived off the bus.
Parameters
- data: The frame's payload. :returns: The payload, ready for its signals to be read out.
Raises
- PamojaError: The payload is not exactly eight bytes.