1use crate::hardware::Device;
2use anyhow::{anyhow, bail, Result};
3use maybe_async::{async_impl, sync_impl};
4use std::str;
5use std::time::Duration;
6use tracing::{error, trace};
7
8#[cfg(feature = "is_async")]
9use tokio_serial::{
10 SerialPort, SerialPortBuilderExt, SerialPortInfo, SerialPortType, SerialStream,
11};
12
13#[cfg(feature = "is_sync")]
14use serialport::{SerialPort, SerialPortInfo, SerialPortType};
15
16#[cfg(all(feature = "is_sync", windows))]
17use serialport::COMPort;
18#[cfg(all(feature = "is_sync", not(windows)))]
19use serialport::TTYPort;
20
21pub mod api;
22pub mod color;
23pub mod enums;
24pub mod hardware;
25pub mod helpers;
26pub mod prelude;
27pub mod settings;
28
29pub const MAX_LAYERS: u8 = 10 - 1;
30
31#[derive(Debug)]
33pub struct Focus {
34 #[cfg(feature = "is_async")]
35 pub(crate) serial: SerialStream,
36 #[cfg(all(feature = "is_sync", windows))]
37 pub(crate) serial: COMPort,
38 #[cfg(all(feature = "is_sync", not(windows)))]
39 pub(crate) serial: TTYPort,
40 pub(crate) response_buffer: Vec<u8>,
41}
42
43impl Focus {
45 #[async_impl]
47 pub fn find_all_devices() -> Result<Vec<Device>> {
48 let ports = match tokio_serial::available_ports() {
49 Ok(ports) => ports,
50 Err(e) => {
51 let err_msg = format!("Failed to enumerate serial ports: {:?}", e);
52 error!("{}", err_msg);
53 bail!(err_msg)
54 }
55 };
56
57 Self::collect_devices(ports)
58 }
59
60 #[sync_impl]
62 pub fn find_all_devices() -> Result<Vec<Device>> {
63 let ports = match serialport::available_ports() {
64 Ok(ports) => ports,
65 Err(e) => {
66 let err_msg = format!("Failed to enumerate serial ports: {:?}", e);
67 error!("{}", err_msg);
68 bail!(err_msg)
69 }
70 };
71
72 Self::collect_devices(ports)
73 }
74
75 fn collect_devices(ports: Vec<SerialPortInfo>) -> Result<Vec<Device>> {
76 trace!("Available serial ports: {:?}", ports);
77
78 let devices: Vec<Device> = ports
79 .into_iter()
80 .filter_map(|port| match &port.port_type {
81 SerialPortType::UsbPort(info) => {
82 let matching_devices: Vec<Device> =
83 hardware::types::hardware_physical::DEVICES_PHYSICAL
84 .iter()
85 .filter_map(|device| {
86 if device.usb.vendor_id == info.vid
87 && device.usb.product_id == info.pid
88 {
89 Some(Device {
90 hardware: device.to_owned(),
91 serial_port: port.port_name.to_owned(),
92 })
93 } else {
94 None
95 }
96 })
97 .collect();
98
99 if matching_devices.is_empty() {
100 None
101 } else {
102 Some(matching_devices)
103 }
104 }
105 _ => None,
106 })
107 .flatten()
108 .collect();
109
110 trace!("Found devices: {:?}", devices);
111
112 Ok(devices)
113 }
114
115 pub fn find_first_device() -> Result<Device> {
117 let devices = match Self::find_all_devices() {
118 Ok(devices) => devices,
119 Err(e) => {
120 let err_msg = format!("No device found: {:?}", e);
121 error!("{}", err_msg);
122 bail!(err_msg)
123 }
124 };
125
126 let device = devices.into_iter().nth(0).ok_or_else(|| {
127 let err_msg = "No supported devices found";
128 error!("{}", err_msg);
129 anyhow!(err_msg)
130 })?;
131
132 Ok(device)
133 }
134
135 #[async_impl]
137 pub fn new_via_port(port: &str) -> Result<Self> {
138 let port_settings = tokio_serial::new(port, 115_200)
139 .data_bits(tokio_serial::DataBits::Eight)
140 .flow_control(tokio_serial::FlowControl::None)
141 .parity(tokio_serial::Parity::None)
142 .stop_bits(tokio_serial::StopBits::One)
143 .timeout(Duration::from_secs(5));
144
145 let mut serial = port_settings.open_native_async().map_err(|e| {
146 let err_msg = format!("Failed to open serial port: {} ({:?})", &port, e);
147 error!("{}", err_msg);
148 anyhow!(err_msg)
149 })?;
150
151 serial.write_data_terminal_ready(true)?;
152
153 #[cfg(unix)]
154 serial.set_exclusive(false)?;
155
156 Ok(Self {
157 serial,
158 response_buffer: Vec::with_capacity(1_024 * 8),
159 })
160 }
161
162 #[sync_impl]
164 pub fn new_via_port(port: &str) -> Result<Self> {
165 let port_settings = serialport::new(port, 115_200)
166 .data_bits(serialport::DataBits::Eight)
167 .flow_control(serialport::FlowControl::None)
168 .parity(serialport::Parity::None)
169 .stop_bits(serialport::StopBits::One)
170 .timeout(Duration::from_millis(40));
171 let mut serial = port_settings.open_native().map_err(|e| {
174 let err_msg = format!("Failed to open serial port: {} ({:?})", &port, e);
175 error!("{}", err_msg);
176 anyhow!(err_msg)
177 })?;
178
179 serial.write_data_terminal_ready(true)?;
180
181 #[cfg(unix)]
182 serial.set_exclusive(false)?;
183
184 Ok(Self {
185 serial,
186 response_buffer: Vec::with_capacity(1_024 * 8),
187 })
188 }
189
190 pub fn new_via_device(device: &Device) -> Result<Self> {
192 Self::new_via_port(&device.serial_port)
193 }
194
195 pub fn new_first_available() -> Result<Self> {
197 Self::new_via_device(Self::find_all_devices()?.first().ok_or_else(|| {
198 let err_msg = "No supported devices found";
199 error!("{}", err_msg);
200 anyhow!(err_msg)
201 })?)
202 }
203}