use cfg_if::cfg_if;
use crate::{DataBits, FlowControl, Parity, Result, StopBits};
use nix::libc;
use std::os::unix::prelude::*;
cfg_if! {
if #[cfg(any(
target_os = "dragonflybsd",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
all(
target_os = "linux",
any(
target_env = "musl",
target_arch = "powerpc",
target_arch = "powerpc64"
)
)
))] {
pub(crate) type Termios = libc::termios;
} else if #[cfg(any(
target_os = "android",
all(
target_os = "linux",
not(any(
target_env = "musl",
target_arch = "powerpc",
target_arch = "powerpc64"
))
)
))] {
pub(crate) type Termios = libc::termios2;
} else {
compile_error!("Unsupported platform. See crate documentation for supported platforms");
}
}
#[cfg(any(target_os = "ios", target_os = "macos",))]
pub(crate) fn get_termios(fd: RawFd) -> Result<Termios> {
use std::mem::MaybeUninit;
let mut termios = MaybeUninit::uninit();
let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) };
nix::errno::Errno::result(res)?;
let mut termios = unsafe { termios.assume_init() };
termios.c_ispeed = self::libc::B9600;
termios.c_ospeed = self::libc::B9600;
Ok(termios)
}
#[cfg(any(
target_os = "dragonflybsd",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
all(
target_os = "linux",
any(
target_env = "musl",
target_arch = "powerpc",
target_arch = "powerpc64"
)
)
))]
pub(crate) fn get_termios(fd: RawFd) -> Result<Termios> {
use std::mem::MaybeUninit;
let mut termios = MaybeUninit::uninit();
let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) };
nix::errno::Errno::result(res)?;
unsafe { Ok(termios.assume_init()) }
}
#[cfg(any(
target_os = "android",
all(
target_os = "linux",
not(any(
target_env = "musl",
target_arch = "powerpc",
target_arch = "powerpc64"
))
)
))]
pub(crate) fn get_termios(fd: RawFd) -> Result<Termios> {
crate::posix::ioctl::tcgets2(fd)
}
#[cfg(any(target_os = "ios", target_os = "macos",))]
pub(crate) fn set_termios(fd: RawFd, termios: &libc::termios, baud_rate: u32) -> Result<()> {
let res = unsafe { libc::tcsetattr(fd, libc::TCSANOW, termios) };
nix::errno::Errno::result(res)?;
if baud_rate > 0 {
crate::posix::ioctl::iossiospeed(fd, &(baud_rate as libc::speed_t))?;
}
Ok(())
}
#[cfg(any(
target_os = "dragonflybsd",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
all(
target_os = "linux",
any(
target_env = "musl",
target_arch = "powerpc",
target_arch = "powerpc64"
)
)
))]
pub(crate) fn set_termios(fd: RawFd, termios: &libc::termios) -> Result<()> {
let res = unsafe { libc::tcsetattr(fd, libc::TCSANOW, termios) };
nix::errno::Errno::result(res)?;
Ok(())
}
#[cfg(any(
target_os = "android",
all(
target_os = "linux",
not(any(
target_env = "musl",
target_arch = "powerpc",
target_arch = "powerpc64"
))
)
))]
pub(crate) fn set_termios(fd: RawFd, termios: &Termios) -> Result<()> {
crate::posix::ioctl::tcsets2(fd, termios)
}
pub(crate) fn set_parity(termios: &mut Termios, parity: Parity) {
match parity {
Parity::None => {
termios.c_cflag &= !(libc::PARENB | libc::PARODD);
termios.c_iflag &= !libc::INPCK;
termios.c_iflag |= libc::IGNPAR;
}
Parity::Odd => {
termios.c_cflag |= libc::PARENB | libc::PARODD;
termios.c_iflag |= libc::INPCK;
termios.c_iflag &= !libc::IGNPAR;
}
Parity::Even => {
termios.c_cflag &= !libc::PARODD;
termios.c_cflag |= libc::PARENB;
termios.c_iflag |= libc::INPCK;
termios.c_iflag &= !libc::IGNPAR;
}
};
}
pub(crate) fn set_flow_control(termios: &mut Termios, flow_control: FlowControl) {
match flow_control {
FlowControl::None => {
termios.c_iflag &= !(libc::IXON | libc::IXOFF);
termios.c_cflag &= !libc::CRTSCTS;
}
FlowControl::Software => {
termios.c_iflag |= libc::IXON | libc::IXOFF;
termios.c_cflag &= !libc::CRTSCTS;
}
FlowControl::Hardware => {
termios.c_iflag &= !(libc::IXON | libc::IXOFF);
termios.c_cflag |= libc::CRTSCTS;
}
};
}
pub(crate) fn set_data_bits(termios: &mut Termios, data_bits: DataBits) {
let size = match data_bits {
DataBits::Five => libc::CS5,
DataBits::Six => libc::CS6,
DataBits::Seven => libc::CS7,
DataBits::Eight => libc::CS8,
};
termios.c_cflag &= !libc::CSIZE;
termios.c_cflag |= size;
}
pub(crate) fn set_stop_bits(termios: &mut Termios, stop_bits: StopBits) {
match stop_bits {
StopBits::One => termios.c_cflag &= !libc::CSTOPB,
StopBits::Two => termios.c_cflag |= libc::CSTOPB,
};
}
#[cfg(any(
target_os = "android",
all(
target_os = "linux",
not(any(
target_env = "musl",
target_arch = "powerpc",
target_arch = "powerpc64"
))
)
))]
pub(crate) fn set_baud_rate(termios: &mut Termios, baud_rate: u32) {
termios.c_cflag &= !nix::libc::CBAUD;
termios.c_cflag |= nix::libc::BOTHER;
termios.c_ispeed = baud_rate;
termios.c_ospeed = baud_rate;
}
#[cfg(any(
target_os = "dragonflybsd",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
pub(crate) fn set_baud_rate(termios: &mut Termios, baud_rate: u32) {
unsafe { libc::cfsetspeed(termios, baud_rate.into()) };
}
#[cfg(all(
target_os = "linux",
any(
target_env = "musl",
target_arch = "powerpc",
target_arch = "powerpc64"
)
))]
pub(crate) fn set_baud_rate(termios: &mut Termios, baud_rate: u32) {
use self::libc::{
B1000000, B1152000, B1500000, B2000000, B2500000, B3000000, B3500000, B4000000, B460800,
B500000, B576000, B921600,
};
use self::libc::{
B110, B115200, B1200, B134, B150, B1800, B19200, B200, B230400, B2400, B300, B38400, B4800,
B50, B57600, B600, B75, B9600,
};
let baud_rate = match baud_rate {
50 => B50,
75 => B75,
110 => B110,
134 => B134,
150 => B150,
200 => B200,
300 => B300,
600 => B600,
1200 => B1200,
1800 => B1800,
2400 => B2400,
4800 => B4800,
9600 => B9600,
19_200 => B19200,
38_400 => B38400,
57_600 => B57600,
115_200 => B115200,
230_400 => B230400,
460_800 => B460800,
500_000 => B500000,
576_000 => B576000,
921_600 => B921600,
1_000_000 => B1000000,
1_152_000 => B1152000,
1_500_000 => B1500000,
2_000_000 => B2000000,
2_500_000 => B2500000,
3_000_000 => B3000000,
3_500_000 => B3500000,
4_000_000 => B4000000,
_ => return,
};
let res = unsafe { libc::cfsetspeed(termios, baud_rate) };
nix::errno::Errno::result(res).expect("cfsetspeed failed");
}