android_usbser/
lib.rs

1//! Android USB serial driver, currently works with CDC-ACM devices.
2//!
3//! Inspired by <https://github.com/mik3y/usb-serial-for-android>.
4//!
5//! It is far from being feature-complete. Of course you can make use of something like
6//! [react-native-usb-serialport](https://www.npmjs.com/package/react-native-usb-serialport),
7//! however, that may introduce multiple layers between Rust and the Linux kernel.
8//!
9//! This crate uses `ndk_context::AndroidContext`, usually initialized by `android_activity`.
10//!
11//! The initial version of this crate performs USB transfers through JNI calls but not `nusb`,
12//! do not use it except you have encountered compatibility problems.
13
14mod usb_conn;
15mod usb_info;
16mod usb_sync;
17
18#[cfg(feature = "serialport")]
19mod ser_cdc;
20#[cfg(feature = "serialport")]
21pub use ser_cdc::*;
22
23/// Equals `std::io::Error`.
24pub type Error = std::io::Error;
25
26/// Android helper for `nusb`. It may be removed in version 0.3.0 (this is blocked by
27/// <https://github.com/kevinmehall/nusb/pull/150>).
28///
29/// Reference:
30/// - <https://developer.android.com/develop/connectivity/usb/host>
31/// - <https://developer.android.com/reference/android/hardware/usb/package-summary>
32pub mod usb {
33    pub use crate::usb_conn::*;
34    pub use crate::usb_info::*;
35    pub use crate::usb_sync::*;
36    pub use crate::Error;
37
38    /// Maps unexpected JNI errors to `std::io::Error` of `ErrorKind::Other`
39    /// (`From<jni::errors::Error>` cannot be implemented for `std::io::Error`
40    /// here because of the orphan rule). Side effect: `jni_last_cleared_ex()`.
41    #[inline(always)]
42    pub(crate) fn jerr(err: jni_min_helper::jni::errors::Error) -> Error {
43        use jni::errors::Error::*;
44        use jni_min_helper::*;
45        if let JavaException = err {
46            let err = jni_clear_ex(err);
47            if let Some(ex) = jni_last_cleared_ex() {
48                jni_with_env(|env| Ok((ex.get_class_name(env)?, ex.get_throwable_msg(env)?)))
49                    .map(|(cls, msg)| Error::other(format!("{cls}: {msg}")))
50                    .unwrap_or(Error::other(err))
51            } else {
52                Error::other(err)
53            }
54        } else {
55            Error::other(err)
56        }
57    }
58}
59
60#[cfg(feature = "serialport")]
61use nusb::transfer::{Queue, RequestBuffer};
62
63/// Serial driver implementations inside this crate should implement this trait.
64///
65/// TODO: add crate-level functions `probe() -> Result<Vec<DeviceInfo>, Error>`
66/// and `open(dev_info: &DeviceInfo, timeout: Duration) -> Result<Box<dyn UsbSerial>, Error>`.
67#[cfg(feature = "serialport")]
68pub trait UsbSerial: serialport::SerialPort {
69    /// Sets baudrate, parity check mode, data bits and stop bits.
70    fn configure(&mut self, conf: &SerialConfig) -> std::io::Result<()>;
71
72    /// Takes `nusb` transfer queues of the read endpoint and the write endpoint.
73    /// This can be called after serial configuration to do asynchronous operations.
74    fn into_queues(self) -> (Queue<RequestBuffer>, Queue<Vec<u8>>);
75
76    #[doc(hidden)]
77    fn sealer(_: private::Internal);
78}
79
80#[cfg(feature = "serialport")]
81use serialport::{DataBits, Parity, StopBits};
82
83/// Serial parameters including baudrate, parity check mode, data bits and stop bits.
84#[cfg(feature = "serialport")]
85#[derive(Debug, Copy, Clone, PartialEq, Eq)]
86pub struct SerialConfig {
87    pub baud_rate: u32,
88    pub parity: Parity,
89    pub data_bits: DataBits,
90    pub stop_bits: StopBits,
91}
92
93#[cfg(feature = "serialport")]
94impl Default for SerialConfig {
95    fn default() -> Self {
96        Self {
97            baud_rate: 9600,
98            parity: Parity::None,
99            data_bits: DataBits::Eight,
100            stop_bits: StopBits::One,
101        }
102    }
103}
104
105#[cfg(feature = "serialport")]
106impl std::str::FromStr for SerialConfig {
107    type Err = Error;
108
109    fn from_str(s: &str) -> Result<Self, Self::Err> {
110        let bad_par = std::io::ErrorKind::InvalidInput;
111        let mut strs = s.split(',');
112
113        let str_baud = strs.next().ok_or(Error::new(bad_par, s))?;
114        let baud_rate = str_baud
115            .trim()
116            .parse()
117            .map_err(|_| Error::new(bad_par, s))?;
118
119        let str_parity = strs.next().ok_or(Error::new(bad_par, s))?;
120        let parity = match str_parity
121            .trim()
122            .chars()
123            .next()
124            .ok_or(Error::new(bad_par, s))?
125        {
126            'N' => Parity::None,
127            'O' => Parity::Odd,
128            'E' => Parity::Even,
129            _ => return Err(Error::new(bad_par, s)),
130        };
131
132        let str_data_bits = strs.next().ok_or(Error::new(bad_par, s))?;
133        let data_bits = str_data_bits
134            .trim()
135            .parse()
136            .map_err(|_| Error::new(bad_par, s))?;
137        let data_bits = match data_bits {
138            5 => DataBits::Five,
139            6 => DataBits::Six,
140            7 => DataBits::Seven,
141            8 => DataBits::Eight,
142            _ => return Err(Error::new(bad_par, s)),
143        };
144
145        let str_stop_bits = strs.next().ok_or(Error::new(bad_par, s))?;
146        let stop_bits = str_stop_bits
147            .trim()
148            .parse()
149            .map_err(|_| Error::new(bad_par, s))?;
150        let stop_bits = match stop_bits {
151            1. => StopBits::One,
152            2. => StopBits::Two,
153            _ => return Err(Error::new(bad_par, s)),
154        };
155
156        Ok(Self {
157            baud_rate,
158            parity,
159            data_bits,
160            stop_bits,
161        })
162    }
163}
164
165#[cfg(feature = "serialport")]
166impl std::fmt::Display for SerialConfig {
167    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168        let baud_rate = self.baud_rate;
169        let parity = match self.parity {
170            Parity::None => 'N',
171            Parity::Odd => 'O',
172            Parity::Even => 'E',
173        };
174        let data_bits = match self.data_bits {
175            DataBits::Five => "5",
176            DataBits::Six => "6",
177            DataBits::Seven => "7",
178            DataBits::Eight => "8",
179        };
180        let stop_bits = match self.stop_bits {
181            StopBits::One => "1",
182            StopBits::Two => "2",
183        };
184        write!(f, "{baud_rate},{parity},{data_bits},{stop_bits}")
185    }
186}
187
188#[allow(unused)]
189mod private {
190    /// Used as a parameter of the hidden function in sealed traits.
191    #[derive(Debug)]
192    pub struct Internal;
193}