vex_v5_serial/
generic.rs

1use crate::{Connection, ConnectionType, bluetooth, serial};
2use futures::{TryFutureExt, try_join};
3use std::time::Duration;
4use thiserror::Error;
5use vex_cdc::{Decode, DecodeError, Encode, FixedStringSizeError, cdc2::Cdc2Ack};
6
7use super::{CheckHeader, bluetooth::BluetoothError, serial::SerialError};
8
9pub enum GenericConnection {
10    Bluetooth(bluetooth::BluetoothConnection),
11    Serial(serial::SerialConnection),
12}
13impl Connection for GenericConnection {
14    type Error = GenericError;
15
16    fn connection_type(&self) -> ConnectionType {
17        match self {
18            GenericConnection::Bluetooth(_) => ConnectionType::Bluetooth,
19            GenericConnection::Serial(s) => s.connection_type(),
20        }
21    }
22
23    async fn send(&mut self, packet: impl Encode) -> Result<(), GenericError> {
24        match self {
25            GenericConnection::Bluetooth(c) => c.send(packet).await?,
26            GenericConnection::Serial(s) => s.send(packet).await?,
27        };
28        Ok(())
29    }
30
31    async fn recv<P: Decode + CheckHeader>(
32        &mut self,
33        timeout: std::time::Duration,
34    ) -> Result<P, GenericError> {
35        Ok(match self {
36            GenericConnection::Bluetooth(c) => c.recv(timeout).await?,
37            GenericConnection::Serial(s) => s.recv(timeout).await?,
38        })
39    }
40
41    async fn read_user(&mut self, buf: &mut [u8]) -> Result<usize, GenericError> {
42        Ok(match self {
43            GenericConnection::Bluetooth(c) => c.read_user(buf).await?,
44            GenericConnection::Serial(s) => s.read_user(buf).await?,
45        })
46    }
47
48    async fn write_user(&mut self, buf: &[u8]) -> Result<usize, GenericError> {
49        Ok(match self {
50            GenericConnection::Bluetooth(c) => c.write_user(buf).await?,
51            GenericConnection::Serial(s) => s.write_user(buf).await?,
52        })
53    }
54}
55impl GenericConnection {
56    /// Returns whether the connection is over bluetooth.
57    pub fn is_bluetooth(&self) -> bool {
58        self.connection_type().is_bluetooth()
59    }
60    /// Returns whether the connection is over serial.
61    pub fn is_wired(&self) -> bool {
62        self.connection_type().is_wired()
63    }
64    /// Returns whether the connection is a controller.
65    pub fn is_controller(&self) -> bool {
66        self.connection_type().is_controller()
67    }
68
69    /// Checks if the connection is paired.
70    /// If the connection is not over bluetooth, this function will return an error.
71    pub async fn is_paired(&self) -> Result<bool, GenericError> {
72        match self {
73            GenericConnection::Bluetooth(c) => Ok(c.is_paired().await?),
74            GenericConnection::Serial(_) => Err(GenericError::PairingNotSupported),
75        }
76    }
77
78    /// Requests pairing with the device.
79    /// # Errors
80    /// If the connection is not over bluetooth, this function will return an error.
81    /// This function will also error if there is a communication error while requesting pairing.
82    pub async fn request_pairing(&mut self) -> Result<(), GenericError> {
83        match self {
84            GenericConnection::Bluetooth(c) => Ok(c.request_pairing().await?),
85            GenericConnection::Serial(_) => Err(GenericError::PairingNotSupported),
86        }
87    }
88
89    /// Attempts to authenticate the pairing request with the given pin.
90    /// If the connection is not over bluetooth, this function will return an error.
91    pub async fn authenticate_pairing(&mut self, pin: [u8; 4]) -> Result<(), GenericError> {
92        match self {
93            GenericConnection::Bluetooth(c) => Ok(c.authenticate_pairing(pin).await?),
94            GenericConnection::Serial(_) => Err(GenericError::PairingNotSupported),
95        }
96    }
97}
98
99impl From<bluetooth::BluetoothConnection> for GenericConnection {
100    fn from(c: bluetooth::BluetoothConnection) -> Self {
101        GenericConnection::Bluetooth(c)
102    }
103}
104impl From<serial::SerialConnection> for GenericConnection {
105    fn from(c: serial::SerialConnection) -> Self {
106        GenericConnection::Serial(c)
107    }
108}
109
110#[derive(Debug, Clone)]
111pub enum GenericDevice {
112    Bluetooth(bluetooth::BluetoothDevice),
113    Serial(serial::SerialDevice),
114}
115impl GenericDevice {
116    pub async fn connect(&self, timeout: Duration) -> Result<GenericConnection, GenericError> {
117        match self.clone() {
118            GenericDevice::Bluetooth(d) => Ok(GenericConnection::Bluetooth(d.connect().await?)),
119            GenericDevice::Serial(d) => Ok(GenericConnection::Serial(d.connect(timeout)?)),
120        }
121    }
122}
123impl From<serial::SerialDevice> for GenericDevice {
124    fn from(d: serial::SerialDevice) -> Self {
125        GenericDevice::Serial(d)
126    }
127}
128impl From<bluetooth::BluetoothDevice> for GenericDevice {
129    fn from(d: bluetooth::BluetoothDevice) -> Self {
130        GenericDevice::Bluetooth(d)
131    }
132}
133
134pub async fn find_devices() -> Result<Vec<GenericDevice>, GenericError> {
135    let res = try_join! {
136        bluetooth_devices().map_err(GenericError::BluetoothError),
137        serial_devices().map_err(GenericError::SerialError),
138    }
139    .map(|(bluetooth, serial)| bluetooth.into_iter().chain(serial.into_iter()).collect())?;
140    Ok(res)
141}
142
143async fn bluetooth_devices() -> Result<Vec<GenericDevice>, BluetoothError> {
144    // Scan for 10 seconds
145    let devices = bluetooth::find_devices(Duration::from_secs(10), None).await?;
146    let devices = devices.into_iter().map(GenericDevice::Bluetooth).collect();
147    Ok(devices)
148}
149
150async fn serial_devices() -> Result<Vec<GenericDevice>, SerialError> {
151    let devices = serial::find_devices()?;
152    let devices = devices.into_iter().map(GenericDevice::Serial).collect();
153    Ok(devices)
154}
155
156#[derive(Error, Debug)]
157pub enum GenericError {
158    #[error("Serial Error: {0}")]
159    SerialError(#[from] SerialError),
160    #[error("Bluetooth Error: {0}")]
161    BluetoothError(#[from] BluetoothError),
162    #[error("Packet decoding error: {0}")]
163    DecodeError(#[from] DecodeError),
164    #[error("NACK received: {0:?}")]
165    Nack(#[from] Cdc2Ack),
166    #[error("Pairing is not supported over any connection other than Bluetooth")]
167    PairingNotSupported,
168    #[error(transparent)]
169    FixedStringSizeError(#[from] FixedStringSizeError),
170}