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;