use std::error::Error as StdError;
use std::fmt;
use std::io;
use std::time::Duration;
pub use BaudRate::*;
pub use CharSize::*;
pub use Parity::*;
pub use StopBits::*;
pub use FlowControl::*;
pub mod prelude {
pub use {SerialPort, SerialPortSettings};
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug,Clone,Copy,PartialEq,Eq)]
pub enum ErrorKind {
NoDevice,
InvalidInput,
Io(io::ErrorKind),
}
#[derive(Debug)]
pub struct Error {
kind: ErrorKind,
description: String,
}
impl Error {
pub fn new<T: Into<String>>(kind: ErrorKind, description: T) -> Self {
Error {
kind: kind,
description: description.into(),
}
}
pub fn kind(&self) -> ErrorKind {
self.kind
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> std::result::Result<(), fmt::Error> {
fmt.write_str(&self.description)
}
}
impl StdError for Error {
fn description(&self) -> &str {
&self.description
}
}
impl From<io::Error> for Error {
fn from(io_error: io::Error) -> Error {
Error::new(ErrorKind::Io(io_error.kind()), format!("{}", io_error))
}
}
impl From<Error> for io::Error {
fn from(error: Error) -> io::Error {
let kind = match error.kind {
ErrorKind::NoDevice => io::ErrorKind::NotFound,
ErrorKind::InvalidInput => io::ErrorKind::InvalidInput,
ErrorKind::Io(kind) => kind,
};
io::Error::new(kind, error.description)
}
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub enum BaudRate {
Baud110,
Baud300,
Baud600,
Baud1200,
Baud2400,
Baud4800,
Baud9600,
Baud19200,
Baud38400,
Baud57600,
Baud115200,
BaudOther(usize),
}
impl BaudRate {
pub fn from_speed(speed: usize) -> BaudRate {
match speed {
110 => BaudRate::Baud110,
300 => BaudRate::Baud300,
600 => BaudRate::Baud600,
1200 => BaudRate::Baud1200,
2400 => BaudRate::Baud2400,
4800 => BaudRate::Baud4800,
9600 => BaudRate::Baud9600,
19200 => BaudRate::Baud19200,
38400 => BaudRate::Baud38400,
57600 => BaudRate::Baud57600,
115200 => BaudRate::Baud115200,
n => BaudRate::BaudOther(n),
}
}
pub fn speed(&self) -> usize {
match *self {
BaudRate::Baud110 => 110,
BaudRate::Baud300 => 300,
BaudRate::Baud600 => 600,
BaudRate::Baud1200 => 1200,
BaudRate::Baud2400 => 2400,
BaudRate::Baud4800 => 4800,
BaudRate::Baud9600 => 9600,
BaudRate::Baud19200 => 19200,
BaudRate::Baud38400 => 38400,
BaudRate::Baud57600 => 57600,
BaudRate::Baud115200 => 115200,
BaudRate::BaudOther(n) => n,
}
}
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub enum CharSize {
Bits5,
Bits6,
Bits7,
Bits8,
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub enum Parity {
ParityNone,
ParityOdd,
ParityEven,
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub enum StopBits {
Stop1,
Stop2,
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub enum FlowControl {
FlowNone,
FlowSoftware,
FlowHardware,
}
pub trait SerialDevice: io::Read + io::Write {
type Settings: SerialPortSettings;
fn read_settings(&self) -> ::Result<Self::Settings>;
fn write_settings(&mut self, settings: &Self::Settings) -> ::Result<()>;
fn timeout(&self) -> Duration;
fn set_timeout(&mut self, timeout: Duration) -> ::Result<()>;
fn set_rts(&mut self, level: bool) -> ::Result<()>;
fn set_dtr(&mut self, level: bool) -> ::Result<()>;
fn read_cts(&mut self) -> ::Result<bool>;
fn read_dsr(&mut self) -> ::Result<bool>;
fn read_ri(&mut self) -> ::Result<bool>;
fn read_cd(&mut self) -> ::Result<bool>;
}
pub trait SerialPort: io::Read + io::Write {
fn timeout(&self) -> Duration;
fn set_timeout(&mut self, timeout: Duration) -> ::Result<()>;
fn configure(&mut self, settings: &PortSettings) -> ::Result<()>;
fn reconfigure(&mut self, setup: &Fn(&mut SerialPortSettings) -> ::Result<()>) -> ::Result<()>;
fn set_rts(&mut self, level: bool) -> ::Result<()>;
fn set_dtr(&mut self, level: bool) -> ::Result<()>;
fn read_cts(&mut self) -> ::Result<bool>;
fn read_dsr(&mut self) -> ::Result<bool>;
fn read_ri(&mut self) -> ::Result<bool>;
fn read_cd(&mut self) -> ::Result<bool>;
}
impl<T> SerialPort for T
where T: SerialDevice
{
fn timeout(&self) -> Duration {
T::timeout(self)
}
fn set_timeout(&mut self, timeout: Duration) -> ::Result<()> {
T::set_timeout(self, timeout)
}
fn configure(&mut self, settings: &PortSettings) -> ::Result<()> {
let mut device_settings = try!(T::read_settings(self));
try!(device_settings.set_baud_rate(settings.baud_rate));
device_settings.set_char_size(settings.char_size);
device_settings.set_parity(settings.parity);
device_settings.set_stop_bits(settings.stop_bits);
device_settings.set_flow_control(settings.flow_control);
T::write_settings(self, &device_settings)
}
fn reconfigure(&mut self, setup: &Fn(&mut SerialPortSettings) -> ::Result<()>) -> ::Result<()> {
let mut device_settings = try!(T::read_settings(self));
try!(setup(&mut device_settings));
T::write_settings(self, &device_settings)
}
fn set_rts(&mut self, level: bool) -> ::Result<()> {
T::set_rts(self, level)
}
fn set_dtr(&mut self, level: bool) -> ::Result<()> {
T::set_dtr(self, level)
}
fn read_cts(&mut self) -> ::Result<bool> {
T::read_cts(self)
}
fn read_dsr(&mut self) -> ::Result<bool> {
T::read_dsr(self)
}
fn read_ri(&mut self) -> ::Result<bool> {
T::read_ri(self)
}
fn read_cd(&mut self) -> ::Result<bool> {
T::read_cd(self)
}
}
pub trait SerialPortSettings {
fn baud_rate(&self) -> Option<BaudRate>;
fn char_size(&self) -> Option<CharSize>;
fn parity(&self) -> Option<Parity>;
fn stop_bits(&self) -> Option<StopBits>;
fn flow_control(&self) -> Option<FlowControl>;
fn set_baud_rate(&mut self, baud_rate: BaudRate) -> ::Result<()>;
fn set_char_size(&mut self, char_size: CharSize);
fn set_parity(&mut self, parity: Parity);
fn set_stop_bits(&mut self, stop_bits: StopBits);
fn set_flow_control(&mut self, flow_control: FlowControl);
}
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
pub struct PortSettings {
pub baud_rate: BaudRate,
pub char_size: CharSize,
pub parity: Parity,
pub stop_bits: StopBits,
pub flow_control: FlowControl,
}
impl SerialPortSettings for PortSettings {
fn baud_rate(&self) -> Option<BaudRate> {
Some(self.baud_rate)
}
fn char_size(&self) -> Option<CharSize> {
Some(self.char_size)
}
fn parity(&self) -> Option<Parity> {
Some(self.parity)
}
fn stop_bits(&self) -> Option<StopBits> {
Some(self.stop_bits)
}
fn flow_control(&self) -> Option<FlowControl> {
Some(self.flow_control)
}
fn set_baud_rate(&mut self, baud_rate: BaudRate) -> ::Result<()> {
self.baud_rate = baud_rate;
Ok(())
}
fn set_char_size(&mut self, char_size: CharSize) {
self.char_size = char_size;
}
fn set_parity(&mut self, parity: Parity) {
self.parity = parity;
}
fn set_stop_bits(&mut self, stop_bits: StopBits) {
self.stop_bits = stop_bits;
}
fn set_flow_control(&mut self, flow_control: FlowControl) {
self.flow_control = flow_control;
}
}
#[cfg(test)]
mod tests {
use super::*;
fn default_port_settings() -> PortSettings {
PortSettings {
baud_rate: BaudRate::Baud9600,
char_size: CharSize::Bits8,
parity: Parity::ParityNone,
stop_bits: StopBits::Stop1,
flow_control: FlowControl::FlowNone,
}
}
#[test]
fn port_settings_manipulates_baud_rate() {
let mut settings: PortSettings = default_port_settings();
settings.set_baud_rate(Baud115200).unwrap();
assert_eq!(settings.baud_rate(), Some(Baud115200));
}
#[test]
fn port_settings_manipulates_char_size() {
let mut settings: PortSettings = default_port_settings();
settings.set_char_size(Bits7);
assert_eq!(settings.char_size(), Some(Bits7));
}
#[test]
fn port_settings_manipulates_parity() {
let mut settings: PortSettings = default_port_settings();
settings.set_parity(ParityEven);
assert_eq!(settings.parity(), Some(ParityEven));
}
#[test]
fn port_settings_manipulates_stop_bits() {
let mut settings: PortSettings = default_port_settings();
settings.set_stop_bits(Stop2);
assert_eq!(settings.stop_bits(), Some(Stop2));
}
#[test]
fn port_settings_manipulates_flow_control() {
let mut settings: PortSettings = default_port_settings();
settings.set_flow_control(FlowSoftware);
assert_eq!(settings.flow_control(), Some(FlowSoftware));
}
}