1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use Error;
use Result;
use libc;
use mio;
use mio::unix::EventedFd;
use serial::{self, BaudRate, SerialPort};
use std::io::{self, Read, Write};
use std::os::unix::io::AsRawFd;

pub struct SerialTransport {
    port: serial::SystemPort,
}

impl SerialTransport {
    pub fn new(path: &str, baudrate: BaudRate) -> Result<SerialTransport> {
        let mut port =
            serial::open(path)
                .map_err(|_| Error::Transport(format!("Fail to open serial device '{}'", path)))?;
        port.reconfigure(&|settings| {
                             settings.set_baud_rate(baudrate)?;
                             settings.set_char_size(serial::Bits8);
                             settings.set_parity(serial::ParityNone);
                             settings.set_stop_bits(serial::Stop1);
                             settings.set_flow_control(serial::FlowNone);
                             Ok(())
                         })
            .map_err(|e| Error::Transport(format!("Fail to configure serial port: {}", e)))?;
        Ok(SerialTransport { port: port })
    }
}

impl Read for SerialTransport {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let fd = self.port.as_raw_fd();
        let len = unsafe {
            libc::read(fd,
                       buf.as_ptr() as *mut libc::c_void,
                       buf.len() as libc::size_t)
        };

        if len >= 0 {
            Ok(len as usize)
        } else {
            Err(io::Error::last_os_error())
        }
    }
}

impl Write for SerialTransport {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let fd = self.port.as_raw_fd();
        let len = unsafe {
            libc::write(fd,
                        buf.as_ptr() as *mut libc::c_void,
                        buf.len() as libc::size_t)
        };

        if len >= 0 {
            Ok(len as usize)
        } else {
            Err(io::Error::last_os_error())
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        self.port.flush()
    }
}

impl mio::Evented for SerialTransport {
    fn register(&self,
                poll: &mio::Poll,
                token: mio::Token,
                interest: mio::Ready,
                opts: mio::PollOpt)
                -> io::Result<()> {
        EventedFd(&self.port.as_raw_fd()).register(poll, token, interest, opts)
    }

    fn reregister(&self,
                  poll: &mio::Poll,
                  token: mio::Token,
                  interest: mio::Ready,
                  opts: mio::PollOpt)
                  -> io::Result<()> {
        EventedFd(&self.port.as_raw_fd()).reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &mio::Poll) -> io::Result<()> {
        EventedFd(&self.port.as_raw_fd()).deregister(poll)
    }
}