#[macro_use]
extern crate bitflags;
extern crate libc;
use libc::c_ulong;
use std::{mem, io};
use std::os::unix::io::{AsRawFd, RawFd};
const TIOCSRS485: c_ulong = 0x542f;
const TIOCGRS485: c_ulong = 0x542e;
bitflags! {
pub struct Rs485Flags: u32 {
const SER_RS485_ENABLED = (1 << 0);
const SER_RS485_RTS_ON_SEND = (1 << 1);
const SER_RS485_RTS_AFTER_SEND = (1 << 2);
const SER_RS485_RX_DURING_TX = (1 << 4);
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct SerialRs485 {
flags: Rs485Flags,
delay_rts_before_send: u32,
delay_rts_after_send: u32,
_padding: [u32; 5],
}
impl SerialRs485 {
#[inline]
pub fn new() -> SerialRs485 {
unsafe { mem::zeroed() }
}
#[inline]
pub fn from_fd(fd: RawFd) -> io::Result<SerialRs485> {
let mut conf = SerialRs485::new();
let rval = unsafe { libc::ioctl(fd, TIOCGRS485, &mut conf as *mut SerialRs485) };
if rval == -1 {
return Err(io::Error::last_os_error());
}
Ok(conf)
}
#[inline]
pub fn set_enabled<'a>(&'a mut self, enabled: bool) -> &'a mut Self {
if enabled {
self.flags |= SER_RS485_ENABLED;
} else {
self.flags &= !SER_RS485_ENABLED;
}
self
}
#[inline]
pub fn set_rts_on_send<'a>(&'a mut self, rts_on_send: bool) -> &'a mut Self {
if rts_on_send {
self.flags |= SER_RS485_RTS_ON_SEND;
} else {
self.flags &= !SER_RS485_RTS_ON_SEND;
}
self
}
#[inline]
pub fn set_rts_after_send<'a>(&'a mut self, rts_after_send: bool) -> &'a mut Self {
if rts_after_send {
self.flags |= SER_RS485_RTS_AFTER_SEND;
} else {
self.flags &= !SER_RS485_RTS_AFTER_SEND;
}
self
}
#[inline]
pub fn delay_rts_before_send_ms<'a>(&'a mut self, delay_rts_before_send: u32) -> &'a mut Self {
self.delay_rts_before_send = delay_rts_before_send;
self
}
#[inline]
pub fn delay_rts_after_send_ms<'a>(&'a mut self, delay_rts_after_send: u32) -> &'a mut Self {
self.delay_rts_after_send = delay_rts_after_send;
self
}
pub fn set_rx_during_tx<'a>(&'a mut self, set_rx_during_tx: bool) -> &'a mut Self {
if set_rx_during_tx {
self.flags |= SER_RS485_RX_DURING_TX
} else {
self.flags &= !SER_RS485_RX_DURING_TX;
}
self
}
#[inline]
pub fn set_on_fd(&self, fd: RawFd) -> io::Result<()> {
let rval = unsafe { libc::ioctl(fd, TIOCSRS485, self as *const SerialRs485) };
if rval == -1 {
return Err(io::Error::last_os_error());
}
Ok(())
}
}
pub trait Rs485 {
fn get_rs485_conf(&self) -> io::Result<SerialRs485>;
fn set_rs485_conf(&self, conf: &SerialRs485) -> io::Result<()>;
fn update_rs485_conf<F: FnOnce(&mut SerialRs485) -> ()>(&self, f: F) -> io::Result<()>;
}
impl<T: AsRawFd> Rs485 for T {
#[inline]
fn get_rs485_conf(&self) -> io::Result<SerialRs485> {
SerialRs485::from_fd(self.as_raw_fd())
}
#[inline]
fn set_rs485_conf(&self, conf: &SerialRs485) -> io::Result<()> {
conf.set_on_fd(self.as_raw_fd())
}
#[inline]
fn update_rs485_conf<F: FnOnce(&mut SerialRs485) -> ()>(&self, f: F) -> io::Result<()> {
let mut conf = self.get_rs485_conf()?;
f(&mut conf);
self.set_rs485_conf(&conf)
}
}