Commit 3ced6a2b authored by Paul Florence's avatar Paul Florence
Browse files

Implementation of `try_clone` for posix.

parent 0d0ab645
Pipeline #15151919 passed with stages
in 14 minutes and 45 seconds
......@@ -737,6 +737,14 @@ pub trait SerialPort: Send + io::Read + io::Write {
/// * `NoDevice` if the device was disconnected.
/// * `Io` for any other type of I/O error.
fn read_carrier_detect(&mut self) -> ::Result<bool>;
// Misc methods
/// Attempts to clone the SerialPort. This allow you to write and read simultaneously from the
/// same serial connection.
///
fn try_clone(&mut self) -> ::Result<Box<SerialPort>>;
//
}
#[derive(Debug,Clone,PartialEq,Eq)]
......
......@@ -5,6 +5,7 @@ use std::ffi::OsStr;
use std::io;
#[cfg(target_os = "macos")]
use std::mem;
use std::sync::Arc;
use std::os::unix::prelude::*;
use std::path::Path;
use std::time::Duration;
......@@ -44,6 +45,23 @@ fn close(fd: RawFd){
let _ = unistd::close(fd);
}
/// Holds a file descriptor, and call `close` on it when it goes out of scope.
struct FdCloser {
pub fd : RawFd
}
impl FdCloser {
fn new(fd : RawFd) -> FdCloser{
FdCloser{fd:fd}
}
}
impl Drop for FdCloser {
fn drop(&mut self) {
close(self.fd);
}
}
/// A TTY-based serial port implementation.
///
/// The port will be closed when the value is dropped. However, this struct
......@@ -51,6 +69,7 @@ fn close(fd: RawFd){
/// the cross-platform `serialport::open()` or
/// `serialport::open_with_settings()`.
pub struct TTYPort {
closer : Arc<FdCloser>,
fd: RawFd,
termios: nix::sys::termios::Termios,
timeout: Duration,
......@@ -142,7 +161,9 @@ impl TTYPort {
e
})?;
let fd_closer = FdCloser::new(fd.clone());
let mut port = TTYPort {
closer : Arc::new(fd_closer),
fd: fd,
termios: termios,
timeout: Duration::from_millis(100),
......@@ -275,11 +296,14 @@ impl TTYPort {
// Open the slave port using default settings
let slave_tty = TTYPort::open(Path::new(&ptty_name), &Default::default())?;
let fd = next_pty_fd.into_raw_fd();
let fd_closer = FdCloser::new(fd.clone());
// Manually construct the master port here because the
// `tcgetattr()` doesn't work on Mac, Solaris, and maybe other
// BSDs when used on the master port.
let master_tty = TTYPort {
fd: next_pty_fd.into_raw_fd(),
closer : Arc::new(fd_closer),
fd: fd,
termios: slave_tty.termios.clone(),
timeout: Duration::from_millis(100),
exclusive: true,
......@@ -425,11 +449,13 @@ impl TTYPort {
}
}
/*
impl Drop for TTYPort {
fn drop(&mut self) {
close(self.fd);
}
}
*/
impl AsRawFd for TTYPort {
fn as_raw_fd(&self) -> RawFd {
......@@ -441,7 +467,7 @@ impl IntoRawFd for TTYPort {
fn into_raw_fd(self) -> RawFd {
// Pull just the file descriptor out. Let the
// rest of the member fields drop.
let TTYPort { fd, .. } = self;
let TTYPort { fd, closer,.. } = self;
fd
}
}
......@@ -458,10 +484,12 @@ impl FromRawFd for TTYPort {
Err(_) => false,
};
let fd_closer = FdCloser::new(fd.clone());
// It is not trivial to get the file path corresponding to a file descriptor.
// We'll punt and set it None here.
TTYPort {
closer : Arc::new(fd_closer),
fd: fd,
termios: termios,
timeout: Duration::from_millis(100),
......@@ -714,6 +742,18 @@ impl SerialPort for TTYPort {
fn read_carrier_detect(&mut self) -> ::Result<bool> {
self.read_pin(ioctl::DATA_CARRIER_DETECT)
}
fn try_clone(&mut self) -> ::Result<Box<SerialPort>> {
let fd_cloned : i32 = fcntl(self.fd,nix::fcntl::F_DUPFD(self.fd))?;
Ok(Box::new(TTYPort {
closer : Arc::clone(&self.closer),
fd : fd_cloned,
termios : self.termios.clone(),
exclusive : self.exclusive,
port_name : self.port_name.clone(),
timeout : self.timeout,
}))
}
}
/// Retrieves the udev property value named by `key`. If the value exists, then it will be
......
......@@ -416,6 +416,11 @@ impl SerialPort for COMPort {
self.write_settings()
}
// TODO : Implement me
fn try_clone(&mut self) {
unimplemented!()
}
}
// According to the MSDN docs, we should use SetupDiGetClassDevs, SetupDiEnumDeviceInfo
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment