1pub mod event;
7
8#[cfg(test)]
9mod tests;
10
11use std::sync::Arc;
12
13use num_enum::{IntoPrimitive, TryFromPrimitive};
14
15pub use event::{ActivityState, ButtonState, CrownEvent, CrownGesture, CrownUpdate, RotationState};
16
17use crate::{
18 channel::{HidppChannel, MessageListenerGuard},
19 event::EventEmitter,
20 feature::{CreatableFeature, EmittingFeature, Feature, FeatureEndpoint, event_payload},
21 protocol::v20::Hidpp20Error,
22};
23
24bitflags::bitflags! {
25 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
27 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
28 pub struct CrownControlCapabilities: u8 {
29 const BUTTON = 1 << 0;
31 const BUTTON_LONG_PRESS = 1 << 1;
33 const MECHANIZED_RATCHET = 1 << 2;
35 const ROTATION_TIMEOUT_CONFIGURABLE = 1 << 3;
37 const SHORT_LONG_TIMEOUT_CONFIGURABLE = 1 << 4;
39 const DOUBLE_TAP_SPEED_CONFIGURABLE = 1 << 5;
41 }
42}
43
44bitflags::bitflags! {
45 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
47 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
48 pub struct CrownSensorCapabilities: u8 {
49 const PROXIMITY = 1 << 0;
51 const TOUCH = 1 << 1;
53 const TAP_GESTURE = 1 << 2;
55 const DOUBLE_TAP_GESTURE = 1 << 3;
57 }
58}
59
60#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, TryFromPrimitive)]
62#[cfg_attr(feature = "serde", derive(serde::Serialize))]
63#[non_exhaustive]
64#[repr(u8)]
65pub enum ReportingMode {
66 NoChange = 0,
68 Hid = 1,
70 Diverted = 2,
72}
73
74#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, TryFromPrimitive)]
76#[cfg_attr(feature = "serde", derive(serde::Serialize))]
77#[non_exhaustive]
78#[repr(u8)]
79pub enum RatchetMode {
80 NoChange = 0,
82 Free = 1,
84 Ratchet = 2,
86}
87
88#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
90#[cfg_attr(feature = "serde", derive(serde::Serialize))]
91#[non_exhaustive]
92pub struct CrownInfo {
93 pub controls: CrownControlCapabilities,
95 pub sensors: CrownSensorCapabilities,
97 pub slots: u16,
99 pub ratchets: u16,
101}
102
103#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
106#[cfg_attr(feature = "serde", derive(serde::Serialize))]
107#[non_exhaustive]
108pub struct CrownMode {
109 pub diverting: ReportingMode,
111 pub ratchet_mode: RatchetMode,
113 pub rotation_timeout: u8,
115 pub short_long_timeout: u8,
117 pub double_tap_speed: u8,
119}
120
121impl CrownMode {
122 fn from_payload(payload: &[u8; 16]) -> Result<Self, Hidpp20Error> {
123 Ok(Self {
124 diverting: ReportingMode::try_from(payload[0])
125 .map_err(|_| Hidpp20Error::UnsupportedResponse)?,
126 ratchet_mode: RatchetMode::try_from(payload[1])
127 .map_err(|_| Hidpp20Error::UnsupportedResponse)?,
128 rotation_timeout: payload[2],
129 short_long_timeout: payload[3],
130 double_tap_speed: payload[4],
131 })
132 }
133}
134
135#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
140#[cfg_attr(feature = "serde", derive(serde::Serialize))]
141pub struct SetCrownMode {
142 pub diverting: ReportingMode,
144 pub ratchet_mode: RatchetMode,
146 pub rotation_timeout: u8,
148 pub short_long_timeout: u8,
150 pub double_tap_speed: u8,
152}
153
154pub struct CrownFeature {
156 endpoint: FeatureEndpoint,
158
159 emitter: Arc<EventEmitter<CrownEvent>>,
161
162 _msg_listener: MessageListenerGuard,
164}
165
166impl CreatableFeature for CrownFeature {
167 const ID: u16 = 0x4600;
168 const STARTING_VERSION: u8 = 0;
169
170 fn new(chan: Arc<HidppChannel>, device_index: u8, feature_index: u8) -> Self {
171 let emitter = Arc::new(EventEmitter::new());
172
173 let listener = chan.add_msg_listener_guarded({
174 let emitter = Arc::clone(&emitter);
175
176 move |raw, matched| {
177 let Some((func, payload)) =
178 event_payload(raw, matched, device_index, feature_index)
179 else {
180 return;
181 };
182 if let Some(event) = event::decode_event(func.to_lo(), &payload) {
183 emitter.emit(event);
184 }
185 }
186 });
187
188 Self {
189 endpoint: FeatureEndpoint::new(chan, device_index, feature_index),
190 emitter,
191 _msg_listener: listener,
192 }
193 }
194}
195
196impl Feature for CrownFeature {}
197
198impl EmittingFeature<CrownEvent> for CrownFeature {
199 fn listen(&self) -> async_channel::Receiver<CrownEvent> {
200 self.emitter.create_receiver()
201 }
202}
203
204impl CrownFeature {
205 pub async fn get_info(&self) -> Result<CrownInfo, Hidpp20Error> {
207 let payload = self.endpoint.call(0, [0; 3]).await?.extend_payload();
208 Ok(CrownInfo {
209 controls: CrownControlCapabilities::from_bits_retain(payload[0]),
210 sensors: CrownSensorCapabilities::from_bits_retain(payload[1]),
211 slots: u16::from_be_bytes([payload[2], payload[3]]),
212 ratchets: u16::from_be_bytes([payload[4], payload[5]]),
213 })
214 }
215
216 pub async fn get_mode(&self) -> Result<CrownMode, Hidpp20Error> {
218 let payload = self.endpoint.call(1, [0; 3]).await?.extend_payload();
219 CrownMode::from_payload(&payload)
220 }
221
222 pub async fn set_mode(&self, mode: SetCrownMode) -> Result<CrownMode, Hidpp20Error> {
227 let mut args = [0; 16];
228 args[..5].copy_from_slice(&[
229 mode.diverting.into(),
230 mode.ratchet_mode.into(),
231 mode.rotation_timeout,
232 mode.short_long_timeout,
233 mode.double_tap_speed,
234 ]);
235 let payload = self.endpoint.call_long(2, args).await?.extend_payload();
236 CrownMode::from_payload(&payload)
237 }
238}