Skip to main content

pamoja-can

CAN 2.0 and CAN-FD frames with 11- and 29-bit identifiers, plus J1939 decode and compose. One capability of pamoja, one memory-safe Rust core with bindings for TypeScript, Python, and C#.

read the guide documentation API reference

Install

pip install pamoja-can
from pamoja import can

This pulls in pamoja-native, the compiled engine. pip install pamoja is the whole framework in one package.

Example

The script the test suite runs, spliced here as it ran.

From bindings/python/guides/can.py:

from pamoja.can import (
    NOT_AVAILABLE,
    Priority,
    broadcast_j1939,
    compose_j1939,
    decode_j1939,
    fd_frame,
    frame,
    signals,
    signals_from,
)
from pamoja.core import PamojaError

# The nodes on this bus, by the address each answers to, and the two parameter groups
# in play. J1939 publishes both, so naming them is what makes the traffic readable.
ENGINE = 0
GATEWAY = 1
GEARBOX = 33
ENGINE_CONTROLLER_1 = 61_444  # carries engine speed
REQUEST = 59_904  # asks another node for a parameter group

# Where engine speed sits inside that group, and the scale the standard fixes for it.
# Naming both is what stops a sender and a receiver disagreeing about either.
ENGINE_SPEED_AT = 3
RPM_PER_BIT = 0.125

# J1939 keeps its addressing inside the CAN identifier: a priority, the parameter
# group, and the address of whatever sent it. A broadcast has no destination, so it is
# its own constructor rather than a magic address a caller has to know.
speed_id = broadcast_j1939(Priority.CONTROL, ENGINE_CONTROLLER_1, ENGINE)
speed = decode_j1939(speed_id)
print(f"broadcast pgn {speed.pgn} at priority {speed.priority}")

# A parameter group below the PDU1 limit is addressed rather than broadcast, so those
# eight identifier bits carry a destination instead of extending the group number.
request_id = compose_j1939(Priority.DEFAULT, REQUEST, GATEWAY, GEARBOX)
print(f"request   pgn {decode_j1939(request_id).pgn} addressed to node {GEARBOX}")

# Reading one back off the bus is the same thing in reverse, so a receiver never
# unpacks 29 bits by hand.
heard = decode_j1939(request_id)
print(f"heard     from node {heard.source} for node {heard.destination}")

# The payload. Every signal starts marked not available, and this controller reports
# only engine speed, so that is the only one it writes.
reported = signals()
reported.set_u16(ENGINE_SPEED_AT, int(1000 / RPM_PER_BIT))
eec1 = frame(speed_id, reported.bytes, extended=True)

# The receiving node reads the same offset back, so neither end slices the payload.
rpm = signals_from(eec1.data).u16(ENGINE_SPEED_AT) * RPM_PER_BIT
print(f"engine    {rpm} rpm, carried in {eec1.dlc} bytes")

# Above eight bytes CAN-FD encodes the length in steps rather than exactly, and a
# classic frame still refuses a ninth byte.
print(f"32 bytes carries length code {fd_frame(speed_id, bytes(32), extended=True).dlc}")
try:
    frame(speed_id, bytes(9), extended=True)
    print("a classic frame took nine bytes, which should never happen")
except PamojaError as error:
    print(f"classic   refused nine bytes: {error}")

# J1939 never rides an 11-bit identifier, so a standard frame is not one of its
# messages however its bits happen to line up.
print(f"an 11-bit identifier is J1939: {decode_j1939(291, extended=False) is not None}")

The same capability in every language

Language Package Reference
Rust pamoja-can reference, docs.rs, install
TypeScript @pamoja/can reference, install
Python pamoja-can reference, install
C# Pamoja.Can reference, install

Documentation

License

MIT

Release files for pamoja-can 0.1.18

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pamoja-can 0.1.18
File Size Uploaded
pamoja_can-0.1.18.tar.gz 5.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pamoja-can 0.1.18
File Interpreter ABI Platform
pamoja_can-0.1.18-py3-none-any.whl Python 3 none any Details

Total release size: 11.3 kB

Release files / pamoja_can-0.1.18.tar.gz

Download URL pamoja_can-0.1.18.tar.gz
Size 5.3 kB
Tags Source
SHA-256 checksum
How to use checksums
9f4fc74099e9d596477360d0f416409ca21f8fd9739f5a7593dc9c9e2adcb260
BLAKE2b-256 checksum
How to use checksums
d10879ed24d193e11289694a3b82a3cc7e3db90251a49b2893d18cd06a557e90
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Release files / pamoja_can-0.1.18-py3-none-any.whl

Download URL pamoja_can-0.1.18-py3-none-any.whl
Size 6.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bcb482bfa48301fa69b43d353adef8be7fd533dcf79796db66043dedac36dae3
BLAKE2b-256 checksum
How to use checksums
59bc01a53beeb9c7fb69c8db654cfa59f21d68055c5e5bd22168b329607513a0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Release history Release notifications | RSS feed

0.2.0

2 release files

This release

0.1.18 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page