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. CanBus is one node on a bus, simulated or a kernel interface
through SocketCAN, and the rest 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. :class:`CanBus` is one node on a bus, simulated or a kernel interface 6through SocketCAN, and the rest is the identifier and payload layer; the controller 7hardware handles the wire itself. 8""" 9 10from __future__ import annotations 11 12import enum 13from enum import IntEnum 14from typing import Iterable 15 16from pamoja._native import CanBus as _NativeBus 17from pamoja._native import CanFilter, CanFrame, J1939Message, Signals 18from pamoja._native import can_dlc_to_len as _dlc_to_len 19from pamoja._native import can_fd_frame as _fd_frame 20from pamoja._native import can_frame as _frame 21from pamoja._native import can_len_to_dlc as _len_to_dlc 22from pamoja._native import can_remote_frame as _remote_frame 23from pamoja._native import j1939_compose as _j1939_compose 24from pamoja._native import j1939_broadcast as _j1939_broadcast 25from pamoja._native import j1939_decode as _j1939_decode 26from pamoja._native import j1939_limits as _limits 27 28__all__ = [ 29 "BROADCAST_ADDRESS", 30 "NOT_AVAILABLE", 31 "CanBus", 32 "CanBusKind", 33 "CanFilter", 34 "CanFrame", 35 "J1939Message", 36 "Priority", 37 "Signals", 38 "broadcast_j1939", 39 "compose_j1939", 40 "decode_j1939", 41 "dlc_to_len", 42 "fd_frame", 43 "frame", 44 "len_to_dlc", 45 "remote_frame", 46 "signals", 47 "signals_from", 48] 49 50_NOT_AVAILABLE, _BROADCAST_ADDRESS, _CONTROL, _DEFAULT, _LOWEST = _limits() 51 52#: The byte a J1939 sender writes for a signal it is not reporting. 53NOT_AVAILABLE = _NOT_AVAILABLE 54 55#: The destination address every node on the bus reads. 56BROADCAST_ADDRESS = _BROADCAST_ADDRESS 57 58 59class Priority(IntEnum): 60 """The priorities J1939 publishes, so a caller does not write the number out.""" 61 62 CONTROL = _CONTROL 63 """Ahead of ordinary traffic, for a message that controls something.""" 64 65 DEFAULT = _DEFAULT 66 """What ordinary traffic uses.""" 67 68 LOWEST = _LOWEST 69 """Yields to everything else on the bus.""" 70 71 72def signals() -> Signals: 73 """Build a J1939 payload with every signal marked not available. 74 75 :returns: Eight bytes a controller writes only its own signals into. 76 """ 77 return Signals() 78 79 80def signals_from(data: bytes) -> Signals: 81 """Read the eight data bytes of a frame that arrived off the bus. 82 83 :param data: The frame's payload. 84 :returns: The payload, ready for its signals to be read out. 85 :raises PamojaError: The payload is not exactly eight bytes. 86 """ 87 return Signals.from_bytes(data) 88 89 90def frame(identifier: int, data: bytes, extended: bool = False) -> CanFrame: 91 """Build a classic CAN 2.0 frame. 92 93 :param identifier: The arbitration identifier, masked to the width ``extended`` 94 selects. 95 :param data: The payload, at most eight bytes. 96 :param extended: Whether the identifier is a 29-bit extended one. 97 :returns: The frame. 98 :raises PamojaError: If the payload is longer than a classic frame carries. 99 """ 100 return _frame(identifier, extended, bytes(data)) 101 102 103def fd_frame(identifier: int, data: bytes, extended: bool = False) -> CanFrame: 104 """Build a CAN-FD frame, which carries up to 64 bytes. 105 106 :param identifier: The arbitration identifier. 107 :param data: The payload, at one of the discrete CAN-FD lengths: 0 to 8, then 108 12, 16, 20, 24, 32, 48, or 64 bytes. 109 :param extended: Whether the identifier is a 29-bit extended one. 110 :returns: The frame. 111 :raises PamojaError: If the payload length is not one CAN-FD can carry. 112 """ 113 return _fd_frame(identifier, extended, bytes(data)) 114 115 116def remote_frame(identifier: int, length: int, extended: bool = False) -> CanFrame: 117 """Build a remote transmission request, which asks another node to send. 118 119 :param identifier: The arbitration identifier. 120 :param length: The data length being requested, clamped to eight bytes. 121 :param extended: Whether the identifier is a 29-bit extended one. 122 :returns: The frame, which carries no payload of its own. 123 """ 124 return _remote_frame(identifier, extended, length) 125 126 127def len_to_dlc(length: int) -> int: 128 """Return the data length code that encodes a payload length. 129 130 :param length: The payload length in bytes. 131 :returns: The code, rounding up to the next length CAN-FD can carry. 132 """ 133 return _len_to_dlc(length) 134 135 136def dlc_to_len(dlc: int) -> int: 137 """Return the payload length a data length code encodes. 138 139 :param dlc: The data length code. 140 :returns: The length in bytes. 141 """ 142 return _dlc_to_len(dlc) 143 144 145def decode_j1939(identifier: int, extended: bool = True) -> J1939Message | None: 146 """Decode the J1939 fields out of an extended CAN identifier. 147 148 :param identifier: The identifier as it arrived. 149 :param extended: Whether it is a 29-bit extended identifier. 150 :returns: The decoded message, or ``None`` for a standard identifier, which 151 J1939 does not use. 152 """ 153 return _j1939_decode(identifier, extended) 154 155 156def compose_j1939(priority: int, pgn: int, source: int, destination: int = 0) -> int: 157 """Compose the extended CAN identifier a set of J1939 fields describes. 158 159 :param priority: The message priority, 0 (highest) to 7. 160 :param pgn: The parameter group number. 161 :param source: The address of the sending node. 162 :param destination: The destination address, used only for an addressed (PDU1) 163 parameter group and ignored for a broadcast (PDU2) one. 164 :returns: The 29-bit identifier. 165 """ 166 return _j1939_compose(priority, pgn, source, destination) 167 168 169def broadcast_j1939(priority: int, pgn: int, source: int) -> int: 170 """Compose the identifier of a J1939 broadcast, which every node reads. 171 172 Most parameter groups are broadcast, so this is the common case; it saves a 173 caller knowing that a broadcast is addressed to ``0xFF``. 174 175 :param priority: The message priority, 0 (highest) to 7. 176 :param pgn: The parameter group number. 177 :param source: The address of the sending node. 178 :returns: The 29-bit identifier. 179 """ 180 return _j1939_broadcast(priority, pgn, source) 181 182 183class CanBusKind(str, enum.Enum): 184 """What a node's bus is.""" 185 186 #: A kernel CAN interface reached through SocketCAN. 187 DEVICE = "Device" 188 #: A bus inside the program. 189 SIMULATED = "Simulated" 190 191 192class CanBus: 193 """One node's place on a CAN bus. 194 195 :meth:`open` opens a kernel interface such as ``can0`` through SocketCAN on a Linux board, 196 once it is up with ``ip link set can0 up type can bitrate 250000``. :meth:`simulated` makes 197 a bus inside the program, and :meth:`join` puts another node on the same bus. A node hears 198 every frame the others send and none of its own, and keeps only the frames its filters 199 pass. A send and a receive release the interpreter while the bus is busy; a receive on a 200 simulated bus with nothing waiting returns ``None`` at once and counts its timeout in 201 :attr:`waited_micros`. 202 203 >>> engine = CanBus.simulated() 204 >>> gateway = engine.join() 205 >>> speed = (500).to_bytes(2, "big") 206 >>> engine.send(frame(0x20A, speed)) 207 >>> bytes(gateway.receive(timeout=0.01).data) == speed 208 True 209 """ 210 211 __slots__ = ("_native",) 212 213 def __init__(self, native: _NativeBus) -> None: 214 """Wrap a native node; use :meth:`open` or :meth:`simulated` instead.""" 215 self._native = native 216 217 @classmethod 218 def open(cls, interface: str) -> CanBus: 219 """Open a kernel CAN interface through SocketCAN, as one node on its bus. 220 221 :param interface: ``can0`` for the first controller, ``vcan0`` for a virtual one. 222 :returns: The node. 223 :raises PamojaError: Anywhere but Linux, or when the interface does not exist. 224 """ 225 return cls(_NativeBus.open(interface)) 226 227 @classmethod 228 def simulated(cls) -> CanBus: 229 """A new bus inside the program, with this node the first on it. 230 231 :returns: The node. 232 """ 233 return cls(_NativeBus.simulated()) 234 235 def join(self) -> CanBus: 236 """Put another node on the same bus. 237 238 :returns: The new node. 239 """ 240 return CanBus(self._native.join()) 241 242 @property 243 def kind(self) -> CanBusKind: 244 """What the bus is.""" 245 return CanBusKind(self._native.kind) 246 247 @property 248 def interface(self) -> str | None: 249 """The kernel interface the node is on, or ``None`` on a simulated bus.""" 250 return self._native.interface 251 252 def send(self, frame: CanFrame) -> None: 253 """Send a frame to every other node on the bus. 254 255 :param frame: The frame. 256 :raises PamojaError: When the kernel refuses the frame. 257 """ 258 self._native.send(frame) 259 260 def receive(self, timeout: float) -> CanFrame | None: 261 """Take the next frame the node keeps, waiting up to ``timeout`` for one. 262 263 :param timeout: How long to wait, in seconds. 264 :returns: The frame, or ``None`` when the timeout passed with nothing. 265 :raises PamojaError: When the interface fails. 266 """ 267 if not timeout >= 0: 268 raise ValueError("a time must be zero or more seconds") 269 return self._native.receive(round(timeout * 1_000_000)) 270 271 def set_filters(self, filters: Iterable[CanFilter]) -> None: 272 """Keep only the frames that pass at least one of the filters, from now on. 273 274 An empty list keeps nothing; :meth:`clear_filters` keeps everything again. 275 276 :param filters: ``CanFilter.pgn(61444)``, ``CanFilter.exact(0x20A)``, and the like. 277 """ 278 self._native.set_filters(list(filters)) 279 280 def clear_filters(self) -> None: 281 """Keep every frame again, as a node does when it joins.""" 282 self._native.clear_filters() 283 284 @property 285 def sent(self) -> int: 286 """How many frames the node has sent.""" 287 return self._native.sent 288 289 @property 290 def received(self) -> int: 291 """How many frames the node has received.""" 292 return self._native.received 293 294 @property 295 def waited_micros(self) -> int: 296 """How long receives have waited without a frame, whether or not the process slept.""" 297 return self._native.waited_micros
193class CanBus: 194 """One node's place on a CAN bus. 195 196 :meth:`open` opens a kernel interface such as ``can0`` through SocketCAN on a Linux board, 197 once it is up with ``ip link set can0 up type can bitrate 250000``. :meth:`simulated` makes 198 a bus inside the program, and :meth:`join` puts another node on the same bus. A node hears 199 every frame the others send and none of its own, and keeps only the frames its filters 200 pass. A send and a receive release the interpreter while the bus is busy; a receive on a 201 simulated bus with nothing waiting returns ``None`` at once and counts its timeout in 202 :attr:`waited_micros`. 203 204 >>> engine = CanBus.simulated() 205 >>> gateway = engine.join() 206 >>> speed = (500).to_bytes(2, "big") 207 >>> engine.send(frame(0x20A, speed)) 208 >>> bytes(gateway.receive(timeout=0.01).data) == speed 209 True 210 """ 211 212 __slots__ = ("_native",) 213 214 def __init__(self, native: _NativeBus) -> None: 215 """Wrap a native node; use :meth:`open` or :meth:`simulated` instead.""" 216 self._native = native 217 218 @classmethod 219 def open(cls, interface: str) -> CanBus: 220 """Open a kernel CAN interface through SocketCAN, as one node on its bus. 221 222 :param interface: ``can0`` for the first controller, ``vcan0`` for a virtual one. 223 :returns: The node. 224 :raises PamojaError: Anywhere but Linux, or when the interface does not exist. 225 """ 226 return cls(_NativeBus.open(interface)) 227 228 @classmethod 229 def simulated(cls) -> CanBus: 230 """A new bus inside the program, with this node the first on it. 231 232 :returns: The node. 233 """ 234 return cls(_NativeBus.simulated()) 235 236 def join(self) -> CanBus: 237 """Put another node on the same bus. 238 239 :returns: The new node. 240 """ 241 return CanBus(self._native.join()) 242 243 @property 244 def kind(self) -> CanBusKind: 245 """What the bus is.""" 246 return CanBusKind(self._native.kind) 247 248 @property 249 def interface(self) -> str | None: 250 """The kernel interface the node is on, or ``None`` on a simulated bus.""" 251 return self._native.interface 252 253 def send(self, frame: CanFrame) -> None: 254 """Send a frame to every other node on the bus. 255 256 :param frame: The frame. 257 :raises PamojaError: When the kernel refuses the frame. 258 """ 259 self._native.send(frame) 260 261 def receive(self, timeout: float) -> CanFrame | None: 262 """Take the next frame the node keeps, waiting up to ``timeout`` for one. 263 264 :param timeout: How long to wait, in seconds. 265 :returns: The frame, or ``None`` when the timeout passed with nothing. 266 :raises PamojaError: When the interface fails. 267 """ 268 if not timeout >= 0: 269 raise ValueError("a time must be zero or more seconds") 270 return self._native.receive(round(timeout * 1_000_000)) 271 272 def set_filters(self, filters: Iterable[CanFilter]) -> None: 273 """Keep only the frames that pass at least one of the filters, from now on. 274 275 An empty list keeps nothing; :meth:`clear_filters` keeps everything again. 276 277 :param filters: ``CanFilter.pgn(61444)``, ``CanFilter.exact(0x20A)``, and the like. 278 """ 279 self._native.set_filters(list(filters)) 280 281 def clear_filters(self) -> None: 282 """Keep every frame again, as a node does when it joins.""" 283 self._native.clear_filters() 284 285 @property 286 def sent(self) -> int: 287 """How many frames the node has sent.""" 288 return self._native.sent 289 290 @property 291 def received(self) -> int: 292 """How many frames the node has received.""" 293 return self._native.received 294 295 @property 296 def waited_micros(self) -> int: 297 """How long receives have waited without a frame, whether or not the process slept.""" 298 return self._native.waited_micros
One node's place on a CAN bus.
open() opens a kernel interface such as can0 through SocketCAN on a Linux board,
once it is up with ip link set can0 up type can bitrate 250000. simulated() makes
a bus inside the program, and join() puts another node on the same bus. A node hears
every frame the others send and none of its own, and keeps only the frames its filters
pass. A send and a receive release the interpreter while the bus is busy; a receive on a
simulated bus with nothing waiting returns None at once and counts its timeout in
waited_micros.
>>> engine = CanBus.simulated()
>>> gateway = engine.join()
>>> speed = (500).to_bytes(2, "big")
>>> engine.send(frame(0x20A, speed))
>>> bytes(gateway.receive(timeout=0.01).data) == speed
True
214 def __init__(self, native: _NativeBus) -> None: 215 """Wrap a native node; use :meth:`open` or :meth:`simulated` instead.""" 216 self._native = native
Wrap a native node; use open() or simulated() instead.
218 @classmethod 219 def open(cls, interface: str) -> CanBus: 220 """Open a kernel CAN interface through SocketCAN, as one node on its bus. 221 222 :param interface: ``can0`` for the first controller, ``vcan0`` for a virtual one. 223 :returns: The node. 224 :raises PamojaError: Anywhere but Linux, or when the interface does not exist. 225 """ 226 return cls(_NativeBus.open(interface))
Open a kernel CAN interface through SocketCAN, as one node on its bus.
Parameters
- interface:
can0for the first controller,vcan0for a virtual one. :returns: The node.
Raises
- PamojaError: Anywhere but Linux, or when the interface does not exist.
228 @classmethod 229 def simulated(cls) -> CanBus: 230 """A new bus inside the program, with this node the first on it. 231 232 :returns: The node. 233 """ 234 return cls(_NativeBus.simulated())
A new bus inside the program, with this node the first on it.
:returns: The node.
236 def join(self) -> CanBus: 237 """Put another node on the same bus. 238 239 :returns: The new node. 240 """ 241 return CanBus(self._native.join())
Put another node on the same bus.
:returns: The new node.
243 @property 244 def kind(self) -> CanBusKind: 245 """What the bus is.""" 246 return CanBusKind(self._native.kind)
What the bus is.
248 @property 249 def interface(self) -> str | None: 250 """The kernel interface the node is on, or ``None`` on a simulated bus.""" 251 return self._native.interface
The kernel interface the node is on, or None on a simulated bus.
253 def send(self, frame: CanFrame) -> None: 254 """Send a frame to every other node on the bus. 255 256 :param frame: The frame. 257 :raises PamojaError: When the kernel refuses the frame. 258 """ 259 self._native.send(frame)
Send a frame to every other node on the bus.
Parameters
- frame: The frame.
Raises
- PamojaError: When the kernel refuses the frame.
261 def receive(self, timeout: float) -> CanFrame | None: 262 """Take the next frame the node keeps, waiting up to ``timeout`` for one. 263 264 :param timeout: How long to wait, in seconds. 265 :returns: The frame, or ``None`` when the timeout passed with nothing. 266 :raises PamojaError: When the interface fails. 267 """ 268 if not timeout >= 0: 269 raise ValueError("a time must be zero or more seconds") 270 return self._native.receive(round(timeout * 1_000_000))
Take the next frame the node keeps, waiting up to timeout for one.
Parameters
- timeout: How long to wait, in seconds.
:returns: The frame, or
Nonewhen the timeout passed with nothing.
Raises
- PamojaError: When the interface fails.
272 def set_filters(self, filters: Iterable[CanFilter]) -> None: 273 """Keep only the frames that pass at least one of the filters, from now on. 274 275 An empty list keeps nothing; :meth:`clear_filters` keeps everything again. 276 277 :param filters: ``CanFilter.pgn(61444)``, ``CanFilter.exact(0x20A)``, and the like. 278 """ 279 self._native.set_filters(list(filters))
Keep only the frames that pass at least one of the filters, from now on.
An empty list keeps nothing; clear_filters() keeps everything again.
Parameters
- filters:
CanFilter.pgn(61444),CanFilter.exact(0x20A), and the like.
281 def clear_filters(self) -> None: 282 """Keep every frame again, as a node does when it joins.""" 283 self._native.clear_filters()
Keep every frame again, as a node does when it joins.
285 @property 286 def sent(self) -> int: 287 """How many frames the node has sent.""" 288 return self._native.sent
How many frames the node has sent.
184class CanBusKind(str, enum.Enum): 185 """What a node's bus is.""" 186 187 #: A kernel CAN interface reached through SocketCAN. 188 DEVICE = "Device" 189 #: A bus inside the program. 190 SIMULATED = "Simulated"
What a node's bus is.
A frame a node keeps: one whose identifier, masked, equals id, masked, and whose format is
the filter's.
A CAN frame: an identifier, its flags, and its payload.
The fields J1939 packs into an extended CAN identifier.
60class Priority(IntEnum): 61 """The priorities J1939 publishes, so a caller does not write the number out.""" 62 63 CONTROL = _CONTROL 64 """Ahead of ordinary traffic, for a message that controls something.""" 65 66 DEFAULT = _DEFAULT 67 """What ordinary traffic uses.""" 68 69 LOWEST = _LOWEST 70 """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.
170def broadcast_j1939(priority: int, pgn: int, source: int) -> int: 171 """Compose the identifier of a J1939 broadcast, which every node reads. 172 173 Most parameter groups are broadcast, so this is the common case; it saves a 174 caller knowing that a broadcast is addressed to ``0xFF``. 175 176 :param priority: The message priority, 0 (highest) to 7. 177 :param pgn: The parameter group number. 178 :param source: The address of the sending node. 179 :returns: The 29-bit identifier. 180 """ 181 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.
157def compose_j1939(priority: int, pgn: int, source: int, destination: int = 0) -> int: 158 """Compose the extended CAN identifier a set of J1939 fields describes. 159 160 :param priority: The message priority, 0 (highest) to 7. 161 :param pgn: The parameter group number. 162 :param source: The address of the sending node. 163 :param destination: The destination address, used only for an addressed (PDU1) 164 parameter group and ignored for a broadcast (PDU2) one. 165 :returns: The 29-bit identifier. 166 """ 167 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.
146def decode_j1939(identifier: int, extended: bool = True) -> J1939Message | None: 147 """Decode the J1939 fields out of an extended CAN identifier. 148 149 :param identifier: The identifier as it arrived. 150 :param extended: Whether it is a 29-bit extended identifier. 151 :returns: The decoded message, or ``None`` for a standard identifier, which 152 J1939 does not use. 153 """ 154 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.
137def dlc_to_len(dlc: int) -> int: 138 """Return the payload length a data length code encodes. 139 140 :param dlc: The data length code. 141 :returns: The length in bytes. 142 """ 143 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.
104def fd_frame(identifier: int, data: bytes, extended: bool = False) -> CanFrame: 105 """Build a CAN-FD frame, which carries up to 64 bytes. 106 107 :param identifier: The arbitration identifier. 108 :param data: The payload, at one of the discrete CAN-FD lengths: 0 to 8, then 109 12, 16, 20, 24, 32, 48, or 64 bytes. 110 :param extended: Whether the identifier is a 29-bit extended one. 111 :returns: The frame. 112 :raises PamojaError: If the payload length is not one CAN-FD can carry. 113 """ 114 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.
91def frame(identifier: int, data: bytes, extended: bool = False) -> CanFrame: 92 """Build a classic CAN 2.0 frame. 93 94 :param identifier: The arbitration identifier, masked to the width ``extended`` 95 selects. 96 :param data: The payload, at most eight bytes. 97 :param extended: Whether the identifier is a 29-bit extended one. 98 :returns: The frame. 99 :raises PamojaError: If the payload is longer than a classic frame carries. 100 """ 101 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.
128def len_to_dlc(length: int) -> int: 129 """Return the data length code that encodes a payload length. 130 131 :param length: The payload length in bytes. 132 :returns: The code, rounding up to the next length CAN-FD can carry. 133 """ 134 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.
117def remote_frame(identifier: int, length: int, extended: bool = False) -> CanFrame: 118 """Build a remote transmission request, which asks another node to send. 119 120 :param identifier: The arbitration identifier. 121 :param length: The data length being requested, clamped to eight bytes. 122 :param extended: Whether the identifier is a 29-bit extended one. 123 :returns: The frame, which carries no payload of its own. 124 """ 125 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.
73def signals() -> Signals: 74 """Build a J1939 payload with every signal marked not available. 75 76 :returns: Eight bytes a controller writes only its own signals into. 77 """ 78 return Signals()
Build a J1939 payload with every signal marked not available.
:returns: Eight bytes a controller writes only its own signals into.
81def signals_from(data: bytes) -> Signals: 82 """Read the eight data bytes of a frame that arrived off the bus. 83 84 :param data: The frame's payload. 85 :returns: The payload, ready for its signals to be read out. 86 :raises PamojaError: The payload is not exactly eight bytes. 87 """ 88 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.