use cfg_if::cfg_if;
use std::path::PathBuf;
pub use libc::TIOCMBIS;
pub use libc::TIOCMBIC;
pub use libc::TIOCMGET;
pub use libc::TIOCM_RTS;
pub use libc::TIOCM_CTS;
pub use libc::TIOCM_DTR;
pub use libc::TIOCM_DSR;
pub use libc::TIOCM_RI;
pub use libc::TIOCM_CD;
pub fn enumerate() -> std::io::Result<Vec<PathBuf>> {
use std::os::unix::ffi::OsStrExt;
use std::os::unix::fs::FileTypeExt;
let serial_ports = std::fs::read_dir("/dev")?
.into_iter()
.filter_map(|entry| {
let entry = entry.ok()?;
let kind = entry.metadata().ok()?.file_type();
if kind.is_char_device() && is_tty_name(entry.file_name().as_bytes()) {
Some(entry.path())
} else {
None
}
})
.collect();
Ok(serial_ports)
}
fn is_tty_name(name: &[u8]) -> bool {
cfg_if! {
if #[cfg(any(target_os = "ios", target_os = "macos"))] {
name.starts_with(b"tty.") || name.starts_with(b"cu.")
} else {
#[cfg(target_os = "dragonfly")]
const PREFIXES: [&[u8]; 2] = [b"ttyd", b"cuaa"];
#[cfg(target_os = "freebsd")]
const PREFIXES: [&[u8]; 3] = [b"ttyu", b"cuau", b"cuad"];
#[cfg(target_os = "netbsd")]
const PREFIXES: [&[u8]; 4] = [b"tty", b"dty", b"ttyU", b"dtyU"];
#[cfg(target_os = "openbsd")]
const PREFIXES: [&[u8]; 4] = [b"tty", b"cua", b"ttyU", b"cuaU"];
for prefix in PREFIXES {
if let Some(suffix) = name.strip_prefix(prefix) {
if !suffix.is_empty() && suffix.iter().all(|c| c.is_ascii_digit()) {
return true;
}
}
}
false
}
}
}