Expand description
§j1939-rs
A Rust library for working with SAE J1939 protocol messages in embedded and automotive systems.
This library provides a powerful macro-based approach to defining, encoding, and decoding J1939 messages with compile-time validation and automatic documentation generation.
§Features
- Type-safe message definitions using Rust structs
- Automatic marshalling/unmarshalling with the
MarshallandUnmarshalltraits - Bit-level field packing with arbitrary bit ranges
- Scaling and offset support for physical unit conversions
- Enum support with automatic documentation generation
- Compile-time validation of message layouts
- Comprehensive documentation automatically generated from your definitions
no_stdcompatible for embedded systems
§Quick Start
Add this to your Cargo.toml:
[dependencies]
j1939-rs = "0.1"Define a J1939 message:
use j1939_rs::prelude::*;
#[j1939_message(pgn = 61444, priority = 3)]
pub struct EngineController {
/// Engine speed in RPM
#[j1939(bits = 0..16, scale = 0.125, unit = "rpm")]
pub engine_speed: f32,
/// Actual engine torque as percentage
#[j1939(bits = 16..24, scale = 1.0, offset = -125.0, unit = "%")]
pub actual_torque: f32,
#[j1939(bits = 24..64, reserved)]
pub reserved: (),
}
// Create and encode a message
let msg = EngineController {
engine_speed: 1850.0,
actual_torque: 45.0,
reserved: (),
};
let mut j1939_msg = J1939Message::default();
msg.marshall(&mut j1939_msg).unwrap();
// Decode a message
let decoded = EngineController::unmarshall(&j1939_msg).unwrap();
assert_eq!(decoded.engine_speed, 1850.0);§Working with Enums
use j1939_rs::prelude::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
#[j1939_enum]
/// Transmission gear selection
pub enum GearPosition {
Park = 0,
Reverse = 1,
Neutral = 2,
Drive = 3,
}
#[j1939_message(pgn = 65265)]
pub struct TransmissionStatus {
#[j1939(bits = 0..2)]
pub current_gear: GearPosition,
#[j1939(bits = 2..64, reserved)]
pub reserved: (),
}§Core Concepts
§Messages
Messages are defined using the #[j1939_message] attribute macro on structs. Each message has:
- A PGN (Parameter Group Number) - unique identifier
- A priority level (0-7, where 0 is highest)
- A length in bits (defaults to 64 bits / 8 bytes)
§Fields
Each field in a message struct must specify its bit range using #[j1939(bits = start..end)].
Additional attributes control encoding:
scale: Multiply/divide factor for float valuesoffset: Additive offset for values (e.g., temperature with -40°C offset)encoding: Special encoding schemes like “q9” for fixed-pointunit: Documentation string for physical unitsreserved: Mark unused bits
§Marshalling
The Marshall trait encodes your struct into a J1939Message:
let msg = EngineController { engine_speed: 1850.0, reserved: () };
let mut j1939_msg = J1939Message::default();
msg.marshall(&mut j1939_msg)?;§Unmarshalling
The Unmarshall trait decodes a J1939Message back into your struct:
let decoded = EngineController::unmarshall(&j1939_msg)?;§Prelude
For convenience, import everything you need with:
use j1939_rs::prelude::*;This brings in all macros, traits, and core types.
§Embedded & no_std Support
This library is designed for embedded systems and is fully no_std compatible:
- No dynamic allocations: All operations use fixed-size buffers on the stack
- No standard library: Works in bare-metal embedded environments
- Compile-time code generation: The proc macros run during compilation on your host machine
- Runtime efficiency: Generated code is zero-cost abstractions with no overhead
§Architecture
The library has two execution contexts:
-
Compile-time (proc macros): The
j1939-macroscrate usesstdbecause it runs during compilation on your development machine. This is normal and required for proc macros. -
Runtime (target): The
j1939-coreand generated code areno_stdand run on your embedded target without requiring heap allocation or the standard library.
§Memory Usage
- Message structures: Stack-allocated, fixed size
J1939Messagebuffer: 1785 bytes maximum (SAE J1939 multi-packet limit)- No heap allocations during encoding/decoding
- All transformations compile to inline arithmetic
§Example for Embedded
#![no_std]
use j1939_rs::prelude::*;
#[j1939_message(pgn = 61444)]
pub struct EngineSpeed {
#[j1939(bits = 0..16, scale = 0.125)]
pub rpm: f32,
#[j1939(bits = 16..64, reserved)]
pub reserved: (),
}
// All of this works without std or allocations
fn send_engine_data() {
let msg = EngineSpeed { rpm: 1850.0, reserved: () };
let mut buffer = J1939Message::default();
msg.marshall(&mut buffer).unwrap();
}§See Also
j1939_message- Define J1939 message structuresj1939_enum- Register enums for documentationMarshall- Trait for encoding messagesUnmarshall- Trait for decoding messages
Modules§
- bitfield
- fixed_
point - message
- prelude
- Convenient prelude that imports all commonly used items.
Structs§
- J1939
Message - A J1939 CAN message containing header information and payload data.
- Q9
- A Q9 fixed-point number representation for precise fractional values.
Enums§
Traits§
- Marshall
- Trait for encoding structured data into J1939 message format.
- Unmarshall
- Trait for decoding J1939 messages into structured data.
Functions§
- decode_
bitfield - Decodes a value from a bitfield at the specified bit offset.
- encode_
bitfield - Encodes a value into a bitfield at the specified bit offset.
- round_
f32 - Round f32s in a
no_stdenvironment. - sign_
extend - Sign-extends a value based on its bit length.
Type Aliases§
Attribute Macros§
- j1939_
enum - Attribute macro for registering enums used in J1939 messages.
- j1939_
message - Attribute macro for defining J1939 message structures with automatic marshalling/unmarshalling.