j1939_rs/
lib.rs

1#![no_std]
2//! # j1939-rs
3//!
4//! A Rust library for working with SAE J1939 protocol messages in embedded and automotive systems.
5//!
6//! This library provides a powerful macro-based approach to defining, encoding, and decoding J1939
7//! messages with compile-time validation and automatic documentation generation.
8//!
9//! ## Features
10//!
11//! - **Type-safe message definitions** using Rust structs
12//! - **Automatic marshalling/unmarshalling** with the `Marshall` and `Unmarshall` traits
13//! - **Bit-level field packing** with arbitrary bit ranges
14//! - **Scaling and offset support** for physical unit conversions
15//! - **Enum support** with automatic documentation generation
16//! - **Compile-time validation** of message layouts
17//! - **Comprehensive documentation** automatically generated from your definitions
18//! - **`no_std` compatible** for embedded systems
19//!
20//! ## Quick Start
21//!
22//! Add this to your `Cargo.toml`:
23//!
24//! ```toml
25//! [dependencies]
26//! j1939-rs = "0.1"
27//! ```
28//!
29//! Define a J1939 message:
30//!
31//! ```rust
32//! use j1939_rs::prelude::*;
33//!
34//! #[j1939_message(pgn = 61444, priority = 3)]
35//! pub struct EngineController {
36//!     /// Engine speed in RPM
37//!     #[j1939(bits = 0..16, scale = 0.125, unit = "rpm")]
38//!     pub engine_speed: f32,
39//!
40//!     /// Actual engine torque as percentage
41//!     #[j1939(bits = 16..24, scale = 1.0, offset = -125.0, unit = "%")]
42//!     pub actual_torque: f32,
43//!
44//!     #[j1939(bits = 24..64, reserved)]
45//!     pub reserved: (),
46//! }
47//!
48//! // Create and encode a message
49//! let msg = EngineController {
50//!     engine_speed: 1850.0,
51//!     actual_torque: 45.0,
52//!     reserved: (),
53//! };
54//!
55//! let mut j1939_msg = J1939Message::default();
56//! msg.marshall(&mut j1939_msg).unwrap();
57//!
58//! // Decode a message
59//! let decoded = EngineController::unmarshall(&j1939_msg).unwrap();
60//! assert_eq!(decoded.engine_speed, 1850.0);
61//! ```
62//!
63//! ## Working with Enums
64//!
65//! ```rust
66//! use j1939_rs::prelude::*;
67//!
68//! #[derive(Debug, Clone, Copy, PartialEq, Eq)]
69//! #[repr(u8)]
70//! #[j1939_enum]
71//! /// Transmission gear selection
72//! pub enum GearPosition {
73//!     Park = 0,
74//!     Reverse = 1,
75//!     Neutral = 2,
76//!     Drive = 3,
77//! }
78//!
79//! #[j1939_message(pgn = 65265)]
80//! pub struct TransmissionStatus {
81//!     #[j1939(bits = 0..2)]
82//!     pub current_gear: GearPosition,
83//!
84//!     #[j1939(bits = 2..64, reserved)]
85//!     pub reserved: (),
86//! }
87//! ```
88//!
89//! ## Core Concepts
90//!
91//! ### Messages
92//!
93//! Messages are defined using the `#[j1939_message]` attribute macro on structs. Each message has:
94//! - A **PGN (Parameter Group Number)** - unique identifier
95//! - A **priority** level (0-7, where 0 is highest)
96//! - A **length** in bits (defaults to 64 bits / 8 bytes)
97//!
98//! ### Fields
99//!
100//! Each field in a message struct must specify its bit range using `#[j1939(bits = start..end)]`.
101//! Additional attributes control encoding:
102//! - `scale`: Multiply/divide factor for float values
103//! - `offset`: Additive offset for values (e.g., temperature with -40°C offset)
104//! - `encoding`: Special encoding schemes like "q9" for fixed-point
105//! - `unit`: Documentation string for physical units
106//! - `reserved`: Mark unused bits
107//!
108//! ### Marshalling
109//!
110//! The `Marshall` trait encodes your struct into a `J1939Message`:
111//!
112//! ```rust
113//! # use j1939_rs::prelude::*;
114//! # #[j1939_message(pgn = 61444)]
115//! # pub struct EngineController {
116//! #     #[j1939(bits = 0..16, scale = 0.125)]
117//! #     pub engine_speed: f32,
118//! #     #[j1939(bits = 16..64, reserved)]
119//! #     pub reserved: (),
120//! # }
121//! let msg = EngineController { engine_speed: 1850.0, reserved: () };
122//! let mut j1939_msg = J1939Message::default();
123//! msg.marshall(&mut j1939_msg)?;
124//! # Ok::<(), j1939_core::Error>(())
125//! ```
126//!
127//! ### Unmarshalling
128//!
129//! The `Unmarshall` trait decodes a `J1939Message` back into your struct:
130//!
131//! ```rust
132//! # use j1939_rs::prelude::*;
133//! # #[j1939_message(pgn = 61444)]
134//! # pub struct EngineController {
135//! #     #[j1939(bits = 0..16, scale = 0.125)]
136//! #     pub engine_speed: f32,
137//! #     #[j1939(bits = 16..64, reserved)]
138//! #     pub reserved: (),
139//! # }
140//! # let mut j1939_msg = J1939Message::default();
141//! # j1939_msg.pgn = 61444;
142//! # j1939_msg.length = 8;
143//! let decoded = EngineController::unmarshall(&j1939_msg)?;
144//! # Ok::<(), j1939_core::Error>(())
145//! ```
146//!
147//! ## Prelude
148//!
149//! For convenience, import everything you need with:
150//!
151//! ```rust
152//! use j1939_rs::prelude::*;
153//! ```
154//!
155//! This brings in all macros, traits, and core types.
156//!
157//! ## Embedded & `no_std` Support
158//!
159//! This library is designed for embedded systems and is fully `no_std` compatible:
160//!
161//! - **No dynamic allocations**: All operations use fixed-size buffers on the stack
162//! - **No standard library**: Works in bare-metal embedded environments
163//! - **Compile-time code generation**: The proc macros run during compilation on your host machine
164//! - **Runtime efficiency**: Generated code is zero-cost abstractions with no overhead
165//!
166//! ### Architecture
167//!
168//! The library has two execution contexts:
169//!
170//! 1. **Compile-time (proc macros)**: The `j1939-macros` crate uses `std` because it runs during
171//!    compilation on your development machine. This is normal and required for proc macros.
172//!
173//! 2. **Runtime (target)**: The `j1939-core` and generated code are `no_std` and run on your
174//!    embedded target without requiring heap allocation or the standard library.
175//!
176//! ### Memory Usage
177//!
178//! - Message structures: Stack-allocated, fixed size
179//! - `J1939Message` buffer: 1785 bytes maximum (SAE J1939 multi-packet limit)
180//! - No heap allocations during encoding/decoding
181//! - All transformations compile to inline arithmetic
182//!
183//! ### Example for Embedded
184//!
185//! ```rust,ignore
186//! #![no_std]
187//! use j1939_rs::prelude::*;
188//!
189//! #[j1939_message(pgn = 61444)]
190//! pub struct EngineSpeed {
191//!     #[j1939(bits = 0..16, scale = 0.125)]
192//!     pub rpm: f32,
193//!     #[j1939(bits = 16..64, reserved)]
194//!     pub reserved: (),
195//! }
196//!
197//! // All of this works without std or allocations
198//! fn send_engine_data() {
199//!     let msg = EngineSpeed { rpm: 1850.0, reserved: () };
200//!     let mut buffer = J1939Message::default();
201//!     msg.marshall(&mut buffer).unwrap();
202//! }
203//! ```
204//!
205//! ## See Also
206//!
207//! - [`j1939_message`] - Define J1939 message structures
208//! - [`j1939_enum`] - Register enums for documentation
209//! - [`Marshall`] - Trait for encoding messages
210//! - [`Unmarshall`] - Trait for decoding messages
211
212pub use j1939_core::*;
213pub use j1939_macros::*;
214
215/// Convenient prelude that imports all commonly used items.
216///
217/// # Examples
218///
219/// ```rust
220/// use j1939_rs::prelude::*;
221///
222/// // Now you have access to:
223/// // - j1939_message macro
224/// // - j1939_enum macro
225/// // - Marshall and Unmarshall traits
226/// // - J1939Message type
227/// // - Error and Result types
228/// ```
229pub mod prelude {
230    pub use j1939_core::*;
231    pub use j1939_macros::*;
232}