use std::{
ffi::{OsStr, OsString},
io::{Error, ErrorKind, Result},
path::PathBuf,
};
use super::{
util::{FunctionDir, Status},
Function, Handle,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum SerialClass {
Acm,
Generic,
}
impl SerialClass {
fn driver(&self) -> &OsStr {
OsStr::new(match self {
SerialClass::Acm => "acm",
SerialClass::Generic => "gser",
})
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct SerialBuilder {
serial_class: SerialClass,
pub console: Option<bool>,
}
impl SerialBuilder {
pub fn build(self) -> (Serial, Handle) {
let dir = FunctionDir::new();
(Serial { dir: dir.clone() }, Handle::new(SerialFunction { builder: self, dir }))
}
}
#[derive(Debug)]
struct SerialFunction {
builder: SerialBuilder,
dir: FunctionDir,
}
impl Function for SerialFunction {
fn driver(&self) -> OsString {
self.builder.serial_class.driver().to_os_string()
}
fn dir(&self) -> FunctionDir {
self.dir.clone()
}
fn register(&self) -> Result<()> {
if let Some(console) = self.builder.console {
let _ = self.dir.write("console", if console { "1" } else { "0" });
}
Ok(())
}
}
#[derive(Debug)]
pub struct Serial {
dir: FunctionDir,
}
impl Serial {
pub fn new(serial_class: SerialClass) -> (Serial, Handle) {
Self::builder(serial_class).build()
}
pub fn builder(serial_class: SerialClass) -> SerialBuilder {
SerialBuilder { serial_class, console: None }
}
pub fn status(&self) -> Status {
self.dir.status()
}
pub fn tty(&self) -> Result<PathBuf> {
let port_num: u32 =
self.dir.read_string("port_num")?.parse().map_err(|err| Error::new(ErrorKind::InvalidData, err))?;
Ok(format!("/dev/ttyGS{port_num}").into())
}
}