use ffi::{Handle, AsHandle};
use error::{invalid_argument};
use core::{IoContext, AsIoContext, IoEvent};
use async::{Handler};
use nio::{AsIoEvent, cancel, read, write, async_read, async_write};
use streams::Stream;
use serial_port::{SerialPortOption};
#[cfg(target_os = "linux")] use super::linux::setup;
#[cfg(target_os = "macos")] use super::macos::setup;
use std::io;
use std::ffi::CString;
use libc::{self, O_RDWR, O_NOCTTY, O_NDELAY, O_NONBLOCK, O_CLOEXEC};
use termios::{Termios, tcsendbreak};
pub trait AsTermios {
fn as_ios(&self) -> &Termios;
fn as_mut_ios(&mut self) -> &mut Termios;
}
pub struct SerialPort {
ios: Termios,
ev: IoEvent,
}
impl SerialPort {
pub fn new<T>(ctx: &IoContext, device: T) -> io::Result<SerialPort>
where T: AsRef<str>
{
let fd = match CString::new(device.as_ref()) {
Ok(device) => libc_try!(libc::open(
device.as_bytes_with_nul().as_ptr() as *const i8,
O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK | O_CLOEXEC)
),
_ => return Err(invalid_argument()),
};
let ev = IoEvent::new(fd, ctx); Ok(SerialPort {
ios: try!(setup(fd)),
ev: ev,
})
}
pub fn cancel(&self) {
cancel(self)
}
pub fn get_option<C>(&self) -> C
where C: SerialPortOption,
{
C::load(self)
}
pub fn send_break(&self) -> io::Result<()> {
tcsendbreak(self.as_handle(), 0)
}
pub fn set_option<C>(&mut self, cmd: C) -> io::Result<()>
where C: SerialPortOption,
{
cmd.store(self)
}
}
impl AsHandle for SerialPort {
fn as_handle(&self) -> Handle {
self.ev.as_handle()
}
}
unsafe impl Send for SerialPort { }
unsafe impl AsIoContext for SerialPort {
fn as_ctx(&self) -> &IoContext {
self.ev.as_ctx()
}
}
impl Stream<io::Error> for SerialPort {
fn async_read_some<F>(&self, buf: &mut [u8], handler: F) -> F::Output
where F: Handler<usize, io::Error>
{
async_read(self, buf, handler)
}
fn async_write_some<F>(&self, buf: &[u8], handler: F) -> F::Output
where F: Handler<usize, io::Error>
{
async_write(self, buf, handler)
}
fn read_some(&self, buf: &mut [u8]) -> io::Result<usize> {
read(self, buf)
}
fn write_some(&self, buf: &[u8]) -> io::Result<usize> {
write(self, buf)
}
}
impl AsIoEvent for SerialPort {
fn as_ev(&self) -> &IoEvent {
&self.ev
}
}
impl AsTermios for SerialPort {
fn as_ios(&self) -> &Termios {
&self.ios
}
fn as_mut_ios(&mut self) -> &mut Termios {
&mut self.ios
}
}
#[test]
#[ignore]
fn test_serial_port() {
use serial_port::*;
let ctx = &IoContext::new().unwrap();
let mut serial_port = SerialPort::new(ctx, "/dev/ttyS0").unwrap();
serial_port.set_option(BaudRate::B9600).unwrap();
}