1pub mod event;
7
8#[cfg(test)]
9mod tests;
10
11use num_enum::{IntoPrimitive, TryFromPrimitive};
12use openlogi_hidpp_derive::Feature;
13
14pub use event::{ActivityState, ButtonState, CrownEvent, CrownGesture, CrownUpdate, RotationState};
15
16use crate::{
17 feature::{EventSource, FeatureEndpoint},
18 protocol::v20::Hidpp20Error,
19};
20
21bitflags::bitflags! {
22 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
24 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
25 pub struct CrownControlCapabilities: u8 {
26 const BUTTON = 1 << 0;
28 const BUTTON_LONG_PRESS = 1 << 1;
30 const MECHANIZED_RATCHET = 1 << 2;
32 const ROTATION_TIMEOUT_CONFIGURABLE = 1 << 3;
34 const SHORT_LONG_TIMEOUT_CONFIGURABLE = 1 << 4;
36 const DOUBLE_TAP_SPEED_CONFIGURABLE = 1 << 5;
38 }
39}
40
41bitflags::bitflags! {
42 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
44 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
45 pub struct CrownSensorCapabilities: u8 {
46 const PROXIMITY = 1 << 0;
48 const TOUCH = 1 << 1;
50 const TAP_GESTURE = 1 << 2;
52 const DOUBLE_TAP_GESTURE = 1 << 3;
54 }
55}
56
57#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, TryFromPrimitive)]
59#[cfg_attr(feature = "serde", derive(serde::Serialize))]
60#[non_exhaustive]
61#[repr(u8)]
62pub enum ReportingMode {
63 NoChange = 0,
65 Hid = 1,
67 Diverted = 2,
69}
70
71#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, TryFromPrimitive)]
73#[cfg_attr(feature = "serde", derive(serde::Serialize))]
74#[non_exhaustive]
75#[repr(u8)]
76pub enum RatchetMode {
77 NoChange = 0,
79 Free = 1,
81 Ratchet = 2,
83}
84
85#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
87#[cfg_attr(feature = "serde", derive(serde::Serialize))]
88#[non_exhaustive]
89pub struct CrownInfo {
90 pub controls: CrownControlCapabilities,
92 pub sensors: CrownSensorCapabilities,
94 pub slots: u16,
96 pub ratchets: u16,
98}
99
100#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
103#[cfg_attr(feature = "serde", derive(serde::Serialize))]
104#[non_exhaustive]
105pub struct CrownMode {
106 pub diverting: ReportingMode,
108 pub ratchet_mode: RatchetMode,
110 pub rotation_timeout: u8,
112 pub short_long_timeout: u8,
114 pub double_tap_speed: u8,
116}
117
118impl CrownMode {
119 fn from_payload(payload: &[u8; 16]) -> Result<Self, Hidpp20Error> {
120 Ok(Self {
121 diverting: ReportingMode::try_from(payload[0])
122 .map_err(|_| Hidpp20Error::UnsupportedResponse)?,
123 ratchet_mode: RatchetMode::try_from(payload[1])
124 .map_err(|_| Hidpp20Error::UnsupportedResponse)?,
125 rotation_timeout: payload[2],
126 short_long_timeout: payload[3],
127 double_tap_speed: payload[4],
128 })
129 }
130}
131
132#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
137#[cfg_attr(feature = "serde", derive(serde::Serialize))]
138pub struct SetCrownMode {
139 pub diverting: ReportingMode,
141 pub ratchet_mode: RatchetMode,
143 pub rotation_timeout: u8,
145 pub short_long_timeout: u8,
147 pub double_tap_speed: u8,
149}
150
151#[derive(Feature)]
153#[creatable(id = 0x4600, version = 0)]
154pub struct CrownFeature {
155 endpoint: FeatureEndpoint,
157
158 events: EventSource<CrownEvent>,
160}
161
162impl CrownFeature {
163 pub async fn get_info(&self) -> Result<CrownInfo, Hidpp20Error> {
165 let payload = self.endpoint.call(0, [0; 3]).await?.extend_payload();
166 Ok(CrownInfo {
167 controls: CrownControlCapabilities::from_bits_retain(payload[0]),
168 sensors: CrownSensorCapabilities::from_bits_retain(payload[1]),
169 slots: u16::from_be_bytes([payload[2], payload[3]]),
170 ratchets: u16::from_be_bytes([payload[4], payload[5]]),
171 })
172 }
173
174 pub async fn get_mode(&self) -> Result<CrownMode, Hidpp20Error> {
176 let payload = self.endpoint.call(1, [0; 3]).await?.extend_payload();
177 CrownMode::from_payload(&payload)
178 }
179
180 pub async fn set_mode(&self, mode: SetCrownMode) -> Result<CrownMode, Hidpp20Error> {
185 let mut args = [0; 16];
186 args[..5].copy_from_slice(&[
187 mode.diverting.into(),
188 mode.ratchet_mode.into(),
189 mode.rotation_timeout,
190 mode.short_long_timeout,
191 mode.double_tap_speed,
192 ]);
193 let payload = self.endpoint.call_long(2, args).await?.extend_payload();
194 CrownMode::from_payload(&payload)
195 }
196}