Skip to main content

hidpp/feature/crown/
event.rs

1//! The event emitted by the `Crown` feature (`0x4600`).
2
3use num_enum::{FromPrimitive, IntoPrimitive};
4
5use crate::feature::DecodeEvent;
6
7/// Rotation phase reported in a [`CrownUpdate`].
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, FromPrimitive)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize))]
10#[non_exhaustive]
11#[repr(u8)]
12pub enum RotationState {
13    /// Not rotating (or not diverted).
14    Inactive = 0,
15    /// Rotation started.
16    Start = 1,
17    /// Rotation ongoing.
18    Active = 2,
19    /// Rotation stopped.
20    Stop = 3,
21    /// A state this crate does not model; carries the raw byte.
22    #[num_enum(catch_all)]
23    Other(u8),
24}
25
26/// Proximity or touch activity phase reported in a [`CrownUpdate`].
27#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, FromPrimitive)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize))]
29#[non_exhaustive]
30#[repr(u8)]
31pub enum ActivityState {
32    /// Inactive.
33    Inactive = 0,
34    /// Started.
35    Start = 1,
36    /// Ongoing.
37    Active = 2,
38    /// Stopped.
39    Stop = 3,
40    /// A state this crate does not model; carries the raw byte.
41    #[num_enum(catch_all)]
42    Other(u8),
43}
44
45/// Touch gesture reported in a [`CrownUpdate`].
46#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, FromPrimitive)]
47#[cfg_attr(feature = "serde", derive(serde::Serialize))]
48#[non_exhaustive]
49#[repr(u8)]
50pub enum CrownGesture {
51    /// No gesture.
52    None = 0,
53    /// Single tap.
54    Tap = 1,
55    /// Double tap.
56    DoubleTap = 2,
57    /// A gesture this crate does not model; carries the raw byte.
58    #[num_enum(catch_all)]
59    Other(u8),
60}
61
62/// Crown button state reported in a [`CrownUpdate`].
63#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, IntoPrimitive, FromPrimitive)]
64#[cfg_attr(feature = "serde", derive(serde::Serialize))]
65#[non_exhaustive]
66#[repr(u8)]
67pub enum ButtonState {
68    /// Inactive (or not diverted).
69    Inactive = 0,
70    /// Press started.
71    Press = 1,
72    /// Short press active.
73    ShortPressActive = 2,
74    /// Long press reached the time threshold.
75    LongPress = 3,
76    /// Long press active.
77    LongPressActive = 4,
78    /// Released.
79    Release = 5,
80    /// A state this crate does not model; carries the raw byte.
81    #[num_enum(catch_all)]
82    Other(u8),
83}
84
85/// An event emitted by [`CrownFeature`](super::CrownFeature).
86#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
87#[cfg_attr(feature = "serde", derive(serde::Serialize))]
88#[non_exhaustive]
89pub enum CrownEvent {
90    /// The crown's rotation, proximity, touch, gesture or button state changed.
91    ///
92    /// Only reported while the crown is diverted (see
93    /// [`set_mode`](super::CrownFeature::set_mode)).
94    Update(CrownUpdate),
95}
96
97/// Payload of [`CrownEvent::Update`].
98#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
99#[cfg_attr(feature = "serde", derive(serde::Serialize))]
100#[non_exhaustive]
101pub struct CrownUpdate {
102    /// Current rotation phase.
103    pub rotation_state: RotationState,
104    /// Slots rotated since the last event (`-127..=127`).
105    pub relative_slot_rotation: i8,
106    /// Ratchets rotated since the last event (`-127..=127`).
107    pub relative_ratchet_rotation: i8,
108    /// Proximity-sensor phase.
109    pub proximity: ActivityState,
110    /// Touch-sensor phase.
111    pub touch: ActivityState,
112    /// Touch gesture detected.
113    pub gesture: CrownGesture,
114    /// Button state.
115    pub button: ButtonState,
116    /// Crown speed in slots per second (signed).
117    pub speed: i16,
118}
119
120/// Decodes the `0x4600` event payload by its sub-id.
121pub(super) fn decode_event(sub_id: u8, payload: &[u8; 16]) -> Option<CrownEvent> {
122    match sub_id {
123        0 => Some(CrownEvent::Update(CrownUpdate {
124            rotation_state: RotationState::from(payload[0]),
125            relative_slot_rotation: payload[1].cast_signed(),
126            relative_ratchet_rotation: payload[2].cast_signed(),
127            proximity: ActivityState::from(payload[3]),
128            touch: ActivityState::from(payload[4]),
129            gesture: CrownGesture::from(payload[5]),
130            button: ButtonState::from(payload[6]),
131            speed: i16::from_be_bytes([payload[14], payload[15]]),
132        })),
133        _ => None,
134    }
135}
136
137impl DecodeEvent for CrownEvent {
138    fn decode(sub_id: u8, payload: &[u8; 16]) -> Option<Self> {
139        decode_event(sub_id, payload)
140    }
141}