Expand description
CAN for the pamoja SDK: the frames, J1939, and a node on a bus.
CAN is the bus that connects the moving parts of a machine: motor controllers, servos, battery management, and the engines, gensets, and farm equipment that speak J1939 on top of it. It is how a robot or a vehicle’s pieces talk to each other reliably over a short, noisy two-wire link, which is why it is the SDK’s path to actuators and to the diesel-and-hydraulic world of rural machinery.
The byte layer needs no controller and no allocation:
CanId- a standard 11-bit or extended 29-bit identifier, always masked to width.Frame- a classic CAN 2.0 frame, a CAN-FD frame at the discrete CAN-FD lengths, or a remote frame, withlen_to_dlcanddlc_to_lenfor the length encoding CAN-FD uses above eight bytes.J1939Id- the priority, parameter group, and addresses J1939 packs into a 29-bit identifier, decoded from one and composed back into one.Signals- the eight data bytes of a J1939 frame, read and written by the offsets its parameter group publishes, starting every signal as not available.
The controller hardware handles the wire itself (arbitration, bit timing, the frame CRC); this is the identifier and payload layer above it, the part an application actually reasons about.
With the bus feature, bus::CanBus is one node’s place on a bus: a bus simulated
inside the program, or with the linux feature, a kernel interface such as can0
through SocketCAN. A node hears every frame the others send and none of its own, and keeps
the ones its bus::Filters pass, by identifier or by J1939 parameter group.
§Examples
use pamoja_can::{CanId, Frame, J1939Id, Signals};
// A classic frame: the motor controller at identifier 0x20A told to run at 500 rpm,
// sent big-endian as its protocol asks.
let command = Frame::new(CanId::standard(0x20A), &500u16.to_be_bytes())?;
assert_eq!(command.dlc(), 2);
// A J1939 broadcast: a genset's engine controller, at source address 0, reports its
// speed in EEC1, parameter group 61444. The speed sits in bytes 4 and 5 of the payload,
// offset 3 counting from zero, at 0.125 rpm per bit, and every signal the controller does
// not report stays marked not available.
const EEC1: u32 = 61_444;
let mut payload = Signals::new();
payload.set_u16(3, (1500.0 / 0.125) as u16);
let report = Frame::new(J1939Id::broadcast(3, EEC1, 0).to_id(), payload.as_bytes())?;
// A listener reads the group from the identifier and the speed from the payload.
let heard = J1939Id::from_id(report.id()).expect("an extended identifier");
assert_eq!(heard.pgn(), EEC1);
assert!(heard.is_broadcast());
let speed = report.signals().and_then(|signals| signals.u16(3)).expect("a speed");
assert_eq!(f64::from(speed) * 0.125, 1500.0);Modules§
Structs§
- CanId
- A CAN arbitration identifier.
- Frame
- A CAN frame: an identifier and its data.
- J1939Id
- The fields a J1939 message packs into its 29-bit identifier.
- Signals
- The eight data bytes of a J1939 frame.
Enums§
- CanError
- What can go wrong building a CAN frame.
Constants§
- BROADCAST_
ADDRESS - The destination address that means every node on the bus.
- NOT_
AVAILABLE - The byte a J1939 sender writes for a signal it is not reporting.
Functions§
- dlc_
to_ len - Maps a data-length code to the number of bytes it represents.
- len_
to_ dlc - Maps a data length to the data-length code that represents it.