ajazz_sdk/
lib.rs

1//! Ajazz library
2//!
3//! Library for interacting with Ajazz devices through [hidapi](https://crates.io/crates/hidapi).
4
5#![cfg_attr(docsrs, feature(doc_cfg))]
6#![warn(missing_docs)]
7
8use std::str::Utf8Error;
9
10use hidapi::HidError;
11use image::ImageError;
12use thiserror::Error;
13
14mod info;
15mod images;
16mod device;
17mod protocol;
18mod hid;
19
20pub use info::Kind;
21pub use device::{Ajazz, DeviceStateReader};
22pub use images::{
23    convert_image, convert_image_with_format, ImageFormat, ImageMode, ImageMirroring,
24    ImageRect, ImageRotation,
25};
26pub use hid::{new_hidapi, refresh_device_list, list_devices};
27
28/// Async Ajazz
29#[cfg(feature = "async")]
30#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
31pub mod asynchronous;
32#[cfg(feature = "async")]
33#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
34pub use asynchronous::AsyncAjazz;
35#[cfg(feature = "async")]
36#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
37pub use images::{convert_image_async, convert_image_with_format_async};
38
39/// Errors that can occur while working with Ajazz devices
40#[derive(Debug, Error)]
41pub enum AjazzError {
42    /// HidApi error
43    #[error("HidApi error: {0}")]
44    HidError(#[from] HidError),
45
46    /// Failed to convert bytes into string
47    #[error("Failed to convert bytes into string: {0}")]
48    Utf8Error(#[from] Utf8Error),
49
50    /// Failed to encode image
51    #[error("Failed to encode image: {0}")]
52    ImageError(#[from] ImageError),
53
54    /// Tokio join error
55    #[cfg(feature = "async")]
56    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
57    #[error("Tokio join error: {0}")]
58    JoinError(#[from] tokio::task::JoinError),
59
60    /// Reader mutex was poisoned
61    #[error("Reader mutex was poisoned")]
62    PoisonError,
63
64    /// Key index is invalid
65    #[error("Key index is invalid: {0}")]
66    InvalidKeyIndex(u8),
67
68    /// Unrecognized Product ID
69    #[error("Unrecognized Product ID: {0}")]
70    UnrecognizedPID(u16),
71
72    /// The device doesn't support doing that
73    #[error("The device doesn't support doing that")]
74    UnsupportedOperation,
75
76    /// Device sent unexpected data
77    #[error("Device sent unexpected data")]
78    BadData,
79
80    /// Invalid image size
81    #[error("Invalid image size: {0}x{1}, expected {2}x{3}")]
82    InvalidImageSize(usize, usize, usize, usize),
83
84    /// Device didn't respond with ACK
85    #[error("Device didn't respond with ACK")]
86    NoAck,
87}
88
89/// Type of input that the device produced
90#[derive(Clone, Debug)]
91pub enum AjazzInput {
92    /// No data was passed from the device
93    NoData,
94
95    /// Button was pressed
96    ButtonStateChange(Vec<bool>),
97
98    /// Encoder/Knob was pressed
99    EncoderStateChange(Vec<bool>),
100
101    /// Encoder/Knob was twisted/turned
102    EncoderTwist(Vec<i8>),
103}
104
105impl AjazzInput {
106    /// Checks if there's data received or not
107    pub fn is_empty(&self) -> bool {
108        matches!(self, AjazzInput::NoData)
109    }
110}
111
112/// Tells what changed in button states
113#[derive(Copy, Clone, Debug, Hash)]
114pub enum Event {
115    /// Button got pressed down
116    ButtonDown(u8),
117
118    /// Button got released
119    ButtonUp(u8),
120
121    /// Encoder got pressed down
122    EncoderDown(u8),
123
124    /// Encoder was released from being pressed down
125    EncoderUp(u8),
126
127    /// Encoder was twisted
128    EncoderTwist(u8, i8),
129}
130
131#[derive(Default)]
132struct DeviceState {
133    pub buttons: Vec<bool>,
134    pub encoders: Vec<bool>,
135}