Skip to main content

ph_haptics/
lib.rs

1//! `ph-haptics` is a `no_std`/`no_alloc` scheduling and motor-modeling runtime
2//! for compiled haptic catalogs.
3//!
4//! It is not a hardware layer: the runtime models ERM and LRA motor behavior
5//! (profiles, kicks, ramps, level clamping) and emits abstract [`DriveCommand`]
6//! values with tickless wake deadlines. Consuming firmware maps those commands
7//! onto its own PWM, GPIO, bus, or motor-driver hardware.
8//!
9//! Text/script compilation is handled by the `ph-haptics-gen` binary. Generated
10//! assets use this crate's DSL/runtime types (`Program`, `Instruction`,
11//! `CompiledHapticDef`, [`Runner`]) for execution. Curve shaping and tickless
12//! transition timing come from `ph-curves`.
13//!
14//! # Features
15//!
16//! The default feature set is the embedded runtime and remains `no_std` and
17//! `no_alloc`. The optional `gen` feature enables the host-only generator and
18//! its `std`-based dependencies; never enable it in a firmware dependency.
19//!
20//! # Example
21//!
22//! Generated catalogs expose the same constants assembled explicitly below.
23//! Firmware normally includes the generator output and starts a runner from its
24//! `COMPILED_CATALOG` constant.
25//!
26//! ```
27//! use ph_haptics::{
28//!     CompiledCatalog, CompiledHapticDef, DriveCommand, ErmConfig, Instruction,
29//!     MonotonicCurveLut256, MotorConfig, MotorKind, Program,
30//! };
31//!
32//! let instructions = [Instruction::<MonotonicCurveLut256>::hold(10, u16::MAX)];
33//! let program = Program::new(MotorKind::Erm, &instructions);
34//! let definition = CompiledHapticDef::new("click", program, None);
35//! let definitions = [definition];
36//! let catalog = CompiledCatalog::new(&definitions);
37//! let mut runner = catalog
38//!     .runner_started("click", MotorConfig::Erm(ErmConfig::new(255)), 0)
39//!     .unwrap();
40//!
41//! let frame = runner.poll(0);
42//! assert_eq!(frame.command, DriveCommand::Erm { duty: 255 });
43//! assert_eq!(frame.next_transition_ms, Some(10));
44//! ```
45
46#![no_std]
47#![deny(missing_docs)]
48#![forbid(unsafe_code)]
49#![deny(unsafe_op_in_unsafe_fn)]
50// Clippy lint levels live here; thresholds and config are in clippy.toml.
51#![deny(clippy::correctness)]
52#![deny(
53    clippy::std_instead_of_core,
54    clippy::std_instead_of_alloc,
55    clippy::alloc_instead_of_core
56)]
57#![warn(
58    clippy::suspicious,
59    clippy::style,
60    clippy::complexity,
61    clippy::perf,
62    clippy::cloned_instead_of_copied,
63    clippy::explicit_iter_loop,
64    clippy::implicit_clone,
65    clippy::inconsistent_struct_constructor,
66    clippy::manual_assert,
67    clippy::manual_let_else,
68    clippy::match_same_arms,
69    clippy::needless_pass_by_value,
70    clippy::semicolon_if_nothing_returned,
71    clippy::uninlined_format_args,
72    clippy::unnested_or_patterns
73)]
74#![allow(
75    clippy::mod_module_files,
76    clippy::self_named_module_files,
77    clippy::similar_names,
78    clippy::too_many_arguments,
79    clippy::struct_excessive_bools,
80    clippy::fn_params_excessive_bools,
81    clippy::type_complexity,
82    clippy::must_use_candidate,
83    clippy::assertions_on_constants,
84    clippy::cast_possible_truncation,
85    clippy::cast_possible_wrap,
86    clippy::cast_sign_loss,
87    clippy::cast_precision_loss,
88    clippy::cast_lossless,
89    clippy::panic_in_result_fn,
90    clippy::unwrap_used,
91    clippy::expect_used,
92    clippy::module_name_repetitions,
93    clippy::wildcard_imports,
94    clippy::items_after_statements,
95    clippy::let_underscore_future
96)]
97
98/// Compiled haptic definition and catalog types.
99pub mod compiled;
100mod dsl;
101/// Runtime/lookup error types.
102pub mod error;
103/// Motor models, profiles, and driver command types.
104pub mod motor;
105/// Haptics runner and frame evaluation.
106pub mod runtime;
107
108pub use compiled::{CompiledCatalog, CompiledCatalogError, CompiledHapticDef};
109pub use dsl::{Instruction, LoopMode, Program, Ramp};
110pub use error::Error;
111pub use motor::{
112    DEFAULT_ERM_PROFILE, DEFAULT_LRA_PROFILE, DriveCommand, ErmConfig, LraConfig, MotorConfig,
113    MotorKind, MotorProfile,
114};
115pub use runtime::{Frame, Runner};
116
117pub use ph_curves::{
118    self, Curve, MonotonicCurve, MonotonicCurveLut, MonotonicCurveLut256, Rounding, Tickless,
119    TicklessDeadline, TicklessSchedule, UnitValue,
120};
121
122#[cfg(test)]
123extern crate std;