joycon_rs/
lib.rs

1#![doc(html_favicon_url = "https://raw.githubusercontent.com/KaiseiYokoyama/joycon-rs/master/images/favicon.ico")]
2#![doc(html_logo_url = "https://raw.githubusercontent.com/KaiseiYokoyama/joycon-rs/master/images/logo.png")]
3//! # Joycon-rs Library Documentation
4//!
5//! Hello, and welcome to joycon-rs documentation.
6//!
7//! Joycon-rs is a framework for dealing with Nintendo Switch Joy-Con on Rust easily and efficiently.
8//! In a way, this library is a wrapper of [`hidapi-rs`].
9//! This is a free and open source library, the source code is available for download on [Github].
10//!
11//! Joycon-rs is in development and is still incomplete.
12//! Please be aware that the update will include breaking changes for the time being. Pardon out dust!
13//!
14//! # Usage
15//! First, add dependency to `Cargo.toml`
16//!
17//! ```toml
18//! [dependencies]
19//! joycon_rs = "*"
20//! ```
21//!
22//! Then, `use` prelude on `.rs` file.
23//! ```
24//! use joycon_rs::prelude::*;
25//! ```
26//!
27//! Perfect! Now you have Joycon-rs available in code.
28//!
29//! ### Receive reports
30//! For starters, let's take a simple signal from JoyCon.
31//! If you have more than one JoyCon, [`mspc`] can be very helpful.
32//!
33//! ```no_run
34//! use joycon_rs::prelude::*;
35//!
36//! let (tx, rx) = std::sync::mpsc::channel();
37//! let _output = std::thread::spawn( move || {
38//!     while let Ok(update) = rx.recv() {
39//!         dbg!(update);
40//!     }
41//! });
42//!
43//! let manager = JoyConManager::get_instance();
44//!
45//! let devices = {
46//!     let lock = manager.lock();
47//!     match lock {
48//!         Ok(manager) => manager.new_devices(),
49//!         Err(_) => return,
50//!     }
51//! };
52//!
53//! devices.iter()
54//!     .flat_map(|dev| SimpleJoyConDriver::new(&dev))
55//!     .try_for_each::<_, JoyConResult<()>>(|driver| {
56//!         // Change JoyCon to Simple hid mode.
57//!         let simple_hid_mode = SimpleHIDMode::new(driver)?;
58//!
59//!         let tx = tx.clone();
60//!
61//!         // Spawn thread
62//!         std::thread::spawn( move || {
63//!             loop {
64//!                 // Forward the report to the main thread
65//!                 tx.send(simple_hid_mode.read_input_report()).unwrap();
66//!             }
67//!         });
68//!
69//!         Ok(())
70//!     })
71//!     .unwrap();
72//! ```
73//!
74//! ### Set player lights
75//! Then, lets deal with player lights.
76//!
77//! ```no_run
78//! use joycon_rs::prelude::{*, lights::*};
79//! use joycon_rs::joycon::input_report_mode::StandardInputReport;
80//! use joycon_rs::joycon::input_report_mode::sub_command_mode::SubCommandReport;
81//!
82//! let (tx, rx) =
83//!     std::sync::mpsc::channel::<JoyConResult<SubCommandReply<StandardInputReport<SubCommandReport<LightsStatus>>>>>();
84//!
85//! // Receive status of player lights
86//! std::thread::spawn(move ||{
87//!     while let Ok(Ok(SubCommandReply::Checked(light_status))) = rx.recv() {
88//!         assert_eq!(
89//!             light_status.extra.reply,
90//!             LightsStatus {
91//!                 light_up: vec![LightUp::LED1, LightUp::LED3],
92//!                 flash: vec![Flash::LED0, Flash::LED2],
93//!             }
94//!         )
95//!     }
96//! });
97//!
98//! let manager = JoyConManager::get_instance();
99//!
100//! let devices = {
101//!     let lock = manager.lock();
102//!     match lock {
103//!         Ok(manager) => manager.new_devices(),
104//!         Err(_) => return,
105//!     }
106//! };
107//!
108//! devices.iter()
109//!     .flat_map(|dev| SimpleJoyConDriver::new(&dev))
110//!     .try_for_each::<_, JoyConResult<()>>(|mut driver| {
111//!         // Set player lights
112//!         // [SL BUTTON] πŸ“ΈπŸ’‘πŸ“ΈπŸ’‘ [SR BUTTON]
113//!         driver.set_player_lights(&vec![LightUp::LED1, LightUp::LED3], &vec![Flash::LED0, Flash::LED2]).unwrap();
114//!         tx.send(driver.get_player_lights()).unwrap();
115//!         Ok(())
116//!     })
117//!     .unwrap();
118//! ```
119//!
120//! # Features
121//! You can use `Joycon-rs` for...
122//! - Manage Joy-Cons
123//!    - Connection / Disconnection / Reconnection
124//! - [Send] / [Receive] raw packets (u8 array) to / from Joy-Con
125//! - [Receive input to Joy-Con][input_report_mode]
126//!     - [Receive pushed buttons, and stick directions (one of 8 directions) on every button pressed.][SimpleHIDMode<D>]
127//!     - [Receive pushed buttons, stick directions (analog value), and 6-Axis sensor at 60Hz.][StandardFullMode<D>]
128//!     - [Get status of Joy-Con][SubCommandMode<D, RD>]
129//! - [Deal with LED (Player lights)]
130//! - [Vibration (Rumble)]
131//!
132//! ## Planning
133//! - Receive NFC/IR data
134//! - Deal with HOME light
135//!
136//! [Github]: https://github.com/KaiseiYokoyama/joycon-rs
137//! [`hidapi-rs`]: https://github.com/ruabmbua/hidapi-rs
138//! [`mspc`]: https://doc.rust-lang.org/book/ch16-02-message-passing.html
139//! [Send]: joycon/trait.JoyConDriver.html#tymethod.write
140//! [Receive]: joycon/trait.JoyConDriver.html#tymethod.read
141//! [input_report_mode]: joycon/input_report_mode/index.html
142//! [SimpleHIDMode<D>]: joycon/input_report_mode/simple_hid_mode/struct.SimpleHIDMode.html
143//! [StandardFullMode<D>]: joycon/input_report_mode/standard_full_mode/struct.StandardFullMode.html
144//! [SubCommandMode<D, RD>]: joycon/input_report_mode/sub_command_mode/struct.SubCommandMode.html
145//! [Deal with LED (Player lights)]: joycon/lights/index.html
146//! [Vibration (Rumble)]:joycon/struct.Rumble.html
147extern crate hidapi;
148#[macro_use]
149extern crate lazy_static;
150
151pub mod joycon;
152
153#[cfg(doctest)]
154#[macro_use]
155extern crate doc_comment;
156
157#[cfg(doctest)]
158doctest!("../README.md");
159
160pub mod prelude {
161    #[cfg(feature = "use_serde")]
162    pub(crate) use serde::{Serialize, Deserialize};
163    pub use hidapi::*;
164    pub use crossbeam_channel;
165    pub use crate::result::*;
166    pub use crate::joycon::*;
167}
168
169pub mod result {
170    // use crate::prelude::SubCommand;
171    use hidapi::HidError;
172
173    #[derive(Debug)]
174    pub enum JoyConError {
175        HidApiError(hidapi::HidError),
176        // SubCommandError(SubCommand),
177        SubCommandError(u8, Vec<u8>),
178        JoyConDeviceError(JoyConDeviceError),
179        JoyConReportError(JoyConReportError),
180        Disconnected,
181    }
182
183    impl From<hidapi::HidError> for JoyConError {
184        fn from(e: HidError) -> Self {
185            JoyConError::HidApiError(e)
186        }
187    }
188
189    #[derive(Debug)]
190    pub enum JoyConDeviceError {
191        InvalidVendorID(u16),
192        InvalidProductID(u16),
193        FailedStickParameterLoading,
194        FailedStickCalibrationLoading,
195        FailedIMUOffsetsLoading,
196        FailedIMUCalibrationLoading,
197        FailedColorLoading,
198    }
199
200    impl From<JoyConDeviceError> for JoyConError {
201        fn from(e: JoyConDeviceError) -> Self {
202            JoyConError::JoyConDeviceError(e)
203        }
204    }
205
206    #[derive(Debug)]
207    pub enum JoyConReportError {
208        InvalidSimpleHidReport(InvalidSimpleHIDReport),
209        InvalidStandardInputReport(InvalidStandardInputReport),
210        EmptyReport,
211    }
212
213    impl From<JoyConReportError> for JoyConError {
214        fn from(e: JoyConReportError) -> Self {
215            JoyConError::JoyConReportError(e)
216        }
217    }
218
219    #[derive(Debug)]
220    pub enum InvalidSimpleHIDReport {
221        InvalidReport(Vec<u8>),
222        InvalidStickDirection(u8),
223    }
224
225    impl From<InvalidSimpleHIDReport> for JoyConReportError {
226        fn from(e: InvalidSimpleHIDReport) -> Self {
227            JoyConReportError::InvalidSimpleHidReport(e)
228        }
229    }
230
231    impl From<InvalidSimpleHIDReport> for JoyConError {
232        fn from(e: InvalidSimpleHIDReport) -> Self {
233            let report_error = JoyConReportError::from(e);
234            JoyConError::from(report_error)
235        }
236    }
237
238    #[derive(Debug)]
239    pub enum InvalidStandardInputReport {
240        InvalidReport(Vec<u8>),
241        InvalidExtraReport(Vec<u8>),
242        Battery(u8),
243        ConnectionInfo(u8),
244        InvalidInputReportId(u8),
245    }
246
247    impl From<InvalidStandardInputReport> for JoyConReportError {
248        fn from(e: InvalidStandardInputReport) -> Self {
249            JoyConReportError::InvalidStandardInputReport(e)
250        }
251    }
252
253    impl From<InvalidStandardInputReport> for JoyConError {
254        fn from(e: InvalidStandardInputReport) -> Self {
255            let report_error = JoyConReportError::from(e);
256            JoyConError::from(report_error)
257        }
258    }
259
260    pub type JoyConResult<T> = Result<T, JoyConError>;
261}
262
263#[cfg(test)]
264mod tests {
265    #[test]
266    fn it_works() {
267        assert_eq!(2 + 2, 4);
268    }
269}