embedded_fans_async/lib.rs
1//! Async Fan API
2//!
3//! This API provides generic methods for interfacing with fans.
4//!
5//! # For HAL authors
6//!
7//! Here is an example of an embedded-fans implementation of the Fan and RpmSense traits.
8//!
9//! ```
10//! use embedded_fans_async::{self, Fan, RpmSense};
11//!
12//! // A struct representing a fan device.
13//! pub struct MyFan {
14//! // ...
15//! }
16//!
17//! #[derive(Clone, Copy, Debug)]
18//! pub enum Error {
19//! // ...
20//! }
21//!
22//! impl embedded_fans_async::Error for Error {
23//! fn kind(&self) -> embedded_fans::ErrorKind {
24//! match *self {
25//! // ...
26//! }
27//! }
28//! }
29//!
30//! impl embedded_fans_async::ErrorType for MyFan {
31//! type Error = Error;
32//! }
33//!
34//! impl Fan for MyFan {
35//! fn max_rpm(&self) -> u16 {
36//! 3150
37//! }
38//!
39//! fn min_rpm(&self) -> u16 {
40//! 0
41//! }
42//!
43//! fn min_start_rpm(&self) -> u16 {
44//! 1120
45//! }
46//!
47//! async fn set_speed_rpm(&mut self, rpm: u16) -> Result<u16, Self::Error> {
48//! // ...
49//! Ok(rpm)
50//! }
51//! }
52//!
53//! impl RpmSense for MyFan {
54//! async fn rpm(&mut self) -> Result<u16, Self::Error> {
55//! // ...
56//! Ok(42)
57//! }
58//! }
59//! ```
60
61#![doc = include_str!("../README.md")]
62#![forbid(missing_docs)]
63#![forbid(unsafe_code)]
64#![no_std]
65#![allow(async_fn_in_trait)]
66
67pub use embedded_fans::{Error, ErrorKind, ErrorType};
68
69/// Async fan methods
70pub trait Fan: ErrorType {
71 /// Returns the maximum RPM the fan is capable of running at.
72 fn max_rpm(&self) -> u16;
73
74 /// Returns the minimum RPM the fan is capable of running at.
75 fn min_rpm(&self) -> u16;
76
77 /// Returns the minimum RPM needed for the fan to begin running from a dead stop
78 /// (which may be the same as the minimum running speed).
79 fn min_start_rpm(&self) -> u16;
80
81 /// Sets the fan's speed in terms of absolute RPM.
82 /// Returns the actual RPM set on success.
83 async fn set_speed_rpm(&mut self, rpm: u16) -> Result<u16, Self::Error>;
84
85 /// Sets the fan's speed in terms of percent of maximum RPM.
86 /// Returns the actual RPM set on success.
87 #[inline]
88 async fn set_speed_percent(&mut self, percent: u8) -> Result<u16, Self::Error> {
89 debug_assert!((0..=100).contains(&percent));
90
91 // Cast operands to u32 to prevent overflow during multiplication
92 self.set_speed_rpm(((u32::from(self.max_rpm()) * u32::from(percent)) / 100) as u16)
93 .await
94 }
95
96 /// Sets the fan's speed to the maximum RPM it's capable of running at.
97 #[inline]
98 async fn set_speed_max(&mut self) -> Result<(), Self::Error> {
99 self.set_speed_rpm(self.max_rpm()).await?;
100 Ok(())
101 }
102
103 /// Starts the fan at its minimum RPM needed to begin from a dead stop.
104 #[inline]
105 async fn start(&mut self) -> Result<(), Self::Error> {
106 self.set_speed_rpm(self.min_start_rpm()).await?;
107 Ok(())
108 }
109
110 /// Stops the fan completely.
111 #[inline]
112 async fn stop(&mut self) -> Result<(), Self::Error> {
113 self.set_speed_rpm(0).await?;
114 Ok(())
115 }
116}
117
118impl<T: Fan + ?Sized> Fan for &mut T {
119 #[inline]
120 fn max_rpm(&self) -> u16 {
121 T::max_rpm(self)
122 }
123
124 #[inline]
125 fn min_rpm(&self) -> u16 {
126 T::min_rpm(self)
127 }
128
129 #[inline]
130 fn min_start_rpm(&self) -> u16 {
131 T::min_start_rpm(self)
132 }
133
134 #[inline]
135 async fn set_speed_rpm(&mut self, rpm: u16) -> Result<u16, Self::Error> {
136 T::set_speed_rpm(self, rpm).await
137 }
138
139 #[inline]
140 async fn set_speed_percent(&mut self, percent: u8) -> Result<u16, Self::Error> {
141 T::set_speed_percent(self, percent).await
142 }
143
144 #[inline]
145 async fn set_speed_max(&mut self) -> Result<(), Self::Error> {
146 T::set_speed_max(self).await
147 }
148
149 #[inline]
150 async fn stop(&mut self) -> Result<(), Self::Error> {
151 T::stop(self).await
152 }
153}
154
155/// Async RPM sensing (tachometer) methods
156pub trait RpmSense: ErrorType {
157 /// Returns the fan's currently measured RPM.
158 async fn rpm(&mut self) -> Result<u16, Self::Error>;
159}
160
161impl<T: RpmSense + ?Sized> RpmSense for &mut T {
162 #[inline]
163 async fn rpm(&mut self) -> Result<u16, Self::Error> {
164 T::rpm(self).await
165 }
166}