Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Unable to read data on windows. Fixes #29 #94

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Update tests and examples to the new API.
zstewar1 committed Feb 23, 2022
commit 09174fcb44bbeaac007f25bb0e2db1e754cfbc97
9 changes: 5 additions & 4 deletions examples/clear_input_buffer.rs
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@ use std::time::Duration;

use clap::{App, AppSettings, Arg};

use serialport::ClearBuffer;
use serialport::{SerialPort, ClearBuffer};

fn main() {
let matches = App::new("Serialport Example - Clear Input Buffer")
@@ -76,9 +76,10 @@ fn run(port_name: &str, baud_rate: &str) -> Result<(), Box<dyn Error>> {
.parse::<u32>()
.map_err(|_| format!("Invalid baud rate '{}' specified", baud_rate))?;

let port = serialport::new(port_name, rate)
let port = SerialPort::builder()
.baud_rate(rate)
.timeout(Duration::from_millis(10))
.open()
.open(port_name)
.map_err(|ref e| format!("Port '{}' not available: {}", &port_name, e))?;

let chan_clear_buf = input_service();
@@ -124,7 +125,7 @@ fn input_service() -> mpsc::Receiver<()> {
break;
}
Ok(_) => tx.send(()).unwrap(), // Signal main to clear the buffer
Err(e) => panic!(e),
Err(e) => panic!("{}", e),
}
}
});
9 changes: 5 additions & 4 deletions examples/clear_output_buffer.rs
Original file line number Diff line number Diff line change
@@ -15,15 +15,15 @@
//

use std::error::Error;
use std::io::{self, Read};
use std::panic::panic_any;
use std::io::{self, Read, Write};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use clap::{App, AppSettings, Arg, ArgMatches};

use serialport::ClearBuffer;
use serialport::{SerialPort,ClearBuffer};

const DEFAULT_BLOCK_SIZE: &str = "128";

@@ -68,9 +68,10 @@ fn run(port_name: &str, baud_rate: &str, block_size: usize) -> Result<(), Box<dy
.parse::<u32>()
.map_err(|_| format!("Invalid baud rate '{}' specified", baud_rate))?;

let mut port = serialport::new(port_name, rate)
let mut port = SerialPort::builder()
.baud_rate(rate)
.timeout(Duration::from_millis(10))
.open()
.open(port_name)
.map_err(|ref e| format!("Port '{}' not available: {}", &port_name, e))?;

let chan_clear_buf = input_service();
7 changes: 4 additions & 3 deletions examples/duplex.rs
Original file line number Diff line number Diff line change
@@ -11,15 +11,16 @@
//! To test this, have a physical or virtual loopback device connected as the
//! only port in the system.

use std::io::Write;
use std::io::{Write, Read};
use std::time::Duration;
use std::{io, thread};

use serialport::SerialPort;

fn main() {
// Open the first serialport available.
let port_name = &serialport::available_ports().expect("No serial port")[0].port_name;
let mut port = serialport::new(port_name, 9600)
.open()
let mut port = SerialPort::builder().open(port_name)
.expect("Failed to open serial port");

// Clone the port
20 changes: 10 additions & 10 deletions examples/hardware_check.rs
Original file line number Diff line number Diff line change
@@ -15,13 +15,13 @@
//! 3) With two ports physically connected to each other
//! `cargo run --example hardware_check /dev/ttyUSB0 /dev/ttyUSB1`

use std::io::Write;
use std::io::{Write, Read};
use std::str;
use std::time::Duration;

use clap::{App, AppSettings, Arg};

use serialport::{ClearBuffer, DataBits, FlowControl, Parity, SerialPort, StopBits};
use serialport::{SerialPort, ClearBuffer, DataBits, FlowControl, Parity, StopBits};

fn main() {
let matches = App::new("Serialport Example - Hardware Check")
@@ -53,28 +53,28 @@ fn main() {
}

// Run single-port tests on port1
let mut port1 = match serialport::new(port1_name, 9600).open() {
let mut port1 = match SerialPort::builder().open(port1_name) {
Err(e) => {
eprintln!("Failed to open \"{}\". Error: {}", port1_name, e);
::std::process::exit(1);
}
Ok(p) => p,
};
test_single_port(&mut *port1, port1_loopback);
test_single_port(&mut port1, port1_loopback);

if port2_name != "" {
// Run single-port tests on port2
let mut port2 = match serialport::new(port2_name, 9600).open() {
let mut port2 = match SerialPort::builder().open(port2_name) {
Err(e) => {
eprintln!("Failed to open \"{}\". Error: {}", port2_name, e);
::std::process::exit(1);
}
Ok(p) => p,
};
test_single_port(&mut *port2, false);
test_single_port(&mut port2, false);

// Test loopback pair
test_dual_ports(&mut *port1, &mut *port2);
test_dual_ports(&mut port1, &mut port2);
}
}

@@ -186,7 +186,7 @@ macro_rules! call_query_method_check {
};
}

fn test_single_port(port: &mut dyn serialport::SerialPort, loopback: bool) {
fn test_single_port(port: &mut SerialPort, loopback: bool) {
println!("Testing '{}':", port.name().unwrap());

// Test setting standard baud rates
@@ -262,7 +262,7 @@ fn test_single_port(port: &mut dyn serialport::SerialPort, loopback: bool) {
}
}

fn test_dual_ports(port1: &mut dyn serialport::SerialPort, port2: &mut dyn serialport::SerialPort) {
fn test_dual_ports(port1: &mut SerialPort, port2: &mut SerialPort) {
println!(
"Testing paired ports '{}' and '{}':",
port1.name().unwrap(),
@@ -420,7 +420,7 @@ fn test_dual_ports(port1: &mut dyn serialport::SerialPort, port2: &mut dyn seria
}
}

fn set_defaults(port: &mut dyn serialport::SerialPort) {
fn set_defaults(port: &mut SerialPort) {
port.set_baud_rate(9600).unwrap();
port.set_data_bits(DataBits::Eight).unwrap();
port.set_flow_control(FlowControl::Software).unwrap();
6 changes: 4 additions & 2 deletions examples/pseudo_terminal.rs
Original file line number Diff line number Diff line change
@@ -8,9 +8,11 @@ fn main() {
use std::thread;
use std::time;

use serialport::{SerialPort, TTYPort};
use serialport::SerialPort;
use serialport::posix::SerialPortExt;

let (mut master, mut slave) = TTYPort::pair().expect("Unable to create pseudo-terminal pair");
let (mut master, mut slave) = SerialPort::pair()
.expect("Unable to create pseudo-terminal pair");

// Master ptty has no associated path on the filesystem.
println!(
9 changes: 6 additions & 3 deletions examples/receive_data.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::io::{self, Write};
use std::io::{self, Write, Read};
use std::time::Duration;

use clap::{App, AppSettings, Arg};

use serialport::SerialPort;

fn main() {
let matches = App::new("Serialport Example - Receive Data")
.about("Reads data from a serial port and echoes it to stdout")
@@ -24,9 +26,10 @@ fn main() {
let port_name = matches.value_of("port").unwrap();
let baud_rate = matches.value_of("baud").unwrap().parse::<u32>().unwrap();

let port = serialport::new(port_name, baud_rate)
let port = SerialPort::builder()
.baud_rate(baud_rate)
.timeout(Duration::from_millis(10))
.open();
.open(port_name);

match port {
Ok(mut port) => {
7 changes: 4 additions & 3 deletions examples/transmit.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ use std::time::Duration;

use clap::{App, AppSettings, Arg};

use serialport::{DataBits, StopBits};
use serialport::{SerialPort, DataBits, StopBits};

fn main() {
let matches = App::new("Serialport Example - Heartbeat")
@@ -67,11 +67,12 @@ fn main() {
let rate = matches.value_of("rate").unwrap().parse::<u32>().unwrap();
let string = matches.value_of("string").unwrap();

let builder = serialport::new(port_name, baud_rate)
let builder = SerialPort::builder()
.baud_rate(baud_rate)
.stop_bits(stop_bits)
.data_bits(data_bits);
println!("{:?}", &builder);
let mut port = builder.open().unwrap_or_else(|e| {
let mut port = builder.open(port_name).unwrap_or_else(|e| {
eprintln!("Failed to open \"{}\". Error: {}", port_name, e);
::std::process::exit(1);
});
69 changes: 31 additions & 38 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -218,48 +218,53 @@ pub struct SerialPortBuilder {

impl SerialPortBuilder {
/// Construct a new `SerialPortBuilder` with the default settings.
pub fn new(baud_rate: u32) -> Self {
SerialPortBuilder {
baud_rate,
data_bits: DataBits::Eight,
flow_control: FlowControl::None,
parity: Parity::None,
stop_bits: StopBits::One,
timeout: Duration::from_millis(0),
}
pub fn new() -> Self {
Default::default()
}

/// Set the baud rate in symbols-per-second
/// Set the baud rate in symbols-per-second.
///
/// Default: `9600`
pub fn baud_rate(mut self, baud_rate: u32) -> Self {
self.baud_rate = baud_rate;
self
}

/// Set the number of bits used to represent a character sent on the line
///
/// Default: `DataBits::Eight`
pub fn data_bits(mut self, data_bits: DataBits) -> Self {
self.data_bits = data_bits;
self
}

/// Set the type of signalling to use for controlling data transfer
///
/// Default: `FlowControl::None`
pub fn flow_control(mut self, flow_control: FlowControl) -> Self {
self.flow_control = flow_control;
self
}

/// Set the type of parity to use for error checking
///
/// Default: `Parity::None`
pub fn parity(mut self, parity: Parity) -> Self {
self.parity = parity;
self
}

/// Set the number of bits to use to signal the end of a character
///
/// Default: `StopBits::One`
pub fn stop_bits(mut self, stop_bits: StopBits) -> Self {
self.stop_bits = stop_bits;
self
}

/// Set the amount of time to wait to receive data before timing out
///
/// Default: `Duration::from_millis(0)`
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
@@ -273,6 +278,19 @@ impl SerialPortBuilder {
}
}

impl Default for SerialPortBuilder {
fn default() -> Self {
SerialPortBuilder {
baud_rate: 9600,
data_bits: DataBits::Eight,
flow_control: FlowControl::None,
parity: Parity::None,
stop_bits: StopBits::One,
timeout: Duration::from_millis(0),
}
}
}

/// A trait for serial port devices
///
/// This trait is all that's necessary to implement a new serial port driver
@@ -281,14 +299,9 @@ impl SerialPortBuilder {
pub struct SerialPort(sys::SerialPort);

impl SerialPort {
/// Open a `SerialPort` at the given path with the given baud rate and default settings.
pub fn open(path: impl AsRef<Path>, baud_rate: u32) -> Result<Self> {
SerialPortBuilder::new(baud_rate).open(path)
}

/// Get a builder for a serial port with the given baud_rate.
pub fn builder(baud_rate: u32) -> SerialPortBuilder {
SerialPortBuilder::new(baud_rate)
/// Get a builder for a serial port with the default settings.
pub fn builder() -> SerialPortBuilder {
Default::default()
}

// Port settings getters
@@ -583,26 +596,6 @@ impl io::Write for &SerialPort {
}
}

#[cfg(unix)]
impl posix::SerialPortExt for SerialPort {
fn pair() -> Result<(Self, Self)> {
let (master, slave) = <sys::SerialPort as posix::SerialPortExt>::pair()?;
Ok((SerialPort(master), SerialPort(slave)))
}

fn exclusive(&self) -> bool {
posix::SerialPortExt::exclusive(&self.0)
}

fn set_exclusive(&mut self, exclusive: bool) -> Result<()> {
posix::SerialPortExt::set_exclusive(&mut self.0, exclusive)
}

fn send_break(&self, duration: posix::BreakDuration) -> Result<()> {
posix::SerialPortExt::send_break(&self.0, duration)
}
}

/// Contains all possible USB information about a `SerialPort`
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UsbPortInfo {
2 changes: 1 addition & 1 deletion src/posix.rs
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ pub trait SerialPortExt {
/// ## Examples
///
/// ```
/// use serialport::SerialPort;
/// use serialport::{SerialPort, posix::SerialPortExt};
///
/// let (master, slave) = SerialPort::pair().unwrap();
/// ```
2 changes: 1 addition & 1 deletion src/sys/posix/enumerate.rs
Original file line number Diff line number Diff line change
@@ -348,7 +348,7 @@ cfg_if! {
if let Some(devnode) = d.devnode() {
if let Some(path) = devnode.to_str() {
if let Some(driver) = p.driver() {
if driver == "serial8250" && crate::SerialPort::open(path, 9600).is_err() {
if driver == "serial8250" && crate::SerialPort::builder().open(path).is_err() {
continue;
}
}
39 changes: 38 additions & 1 deletion src/sys/posix/tty.rs
Original file line number Diff line number Diff line change
@@ -488,6 +488,12 @@ impl AsRawFd for SerialPort {
}
}

impl AsRawFd for crate::SerialPort {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}

impl IntoRawFd for SerialPort {
fn into_raw_fd(self) -> RawFd {
// Pull just the file descriptor out. We also prevent the destructor
@@ -499,6 +505,12 @@ impl IntoRawFd for SerialPort {
}
}

impl IntoRawFd for crate::SerialPort {
fn into_raw_fd(self) -> RawFd {
self.0.into_raw_fd()
}
}

/// Get the baud speed for a port from its file descriptor
#[cfg(any(target_os = "ios", target_os = "macos"))]
fn get_termios_speed(fd: RawFd) -> u32 {
@@ -528,6 +540,12 @@ impl FromRawFd for SerialPort {
}
}

impl FromRawFd for crate::SerialPort {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
crate::SerialPort(SerialPort::from_raw_fd(fd))
}
}

impl io::Read for &SerialPort {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if let Err(e) = super::poll::wait_read_fd(self.fd, self.timeout) {
@@ -569,7 +587,7 @@ impl SerialPortExt for SerialPort {
/// ## Examples
///
/// ```
/// use serialport::SerialPort;
/// use serialport::{SerialPort, posix::SerialPortExt};
///
/// let (master, slave) = SerialPort::pair().unwrap();
/// ```
@@ -692,6 +710,25 @@ impl SerialPortExt for SerialPort {
}
}

impl SerialPortExt for crate::SerialPort {
fn pair() -> Result<(Self, Self)> {
let (master, slave) = SerialPort::pair()?;
Ok((crate::SerialPort(master), crate::SerialPort(slave)))
}

fn exclusive(&self) -> bool {
self.0.exclusive()
}

fn set_exclusive(&mut self, exclusive: bool) -> Result<()> {
self.0.set_exclusive(exclusive)
}

fn send_break(&self, duration: BreakDuration) -> Result<()> {
self.0.send_break(duration)
}
}

#[test]
fn test_ttyport_into_raw_fd() {
// `master` must be used here as Dropping it causes slave to be deleted by the OS.
23 changes: 10 additions & 13 deletions tests/test_serialport.rs
Original file line number Diff line number Diff line change
@@ -16,42 +16,39 @@ fn test_listing_ports() {
fn test_opening_found_ports() {
let ports = serialport::available_ports().unwrap();
for p in ports {
let _port = serialport::new(p.port_name, 9600).open();
let _port = SerialPort::builder().open(p.port_name);
}
}

#[test]
fn test_opening_port() {
let _port = serialport::new("/dev/ttyUSB0", 9600).open();
}

#[test]
fn test_opening_native_port() {
let _port = serialport::new("/dev/ttyUSB0", 9600).open_native();
let _port = SerialPort::builder().open("/dev/ttyUSB0");
}

#[test]
fn test_configuring_ports() {
let _port = serialport::new("/dev/ttyUSB0", 9600)
let _port = SerialPort::builder()
.baud_rate(9600)
.data_bits(DataBits::Five)
.flow_control(FlowControl::None)
.parity(Parity::None)
.stop_bits(StopBits::One)
.timeout(Duration::from_millis(1))
.open();
.open("/dev/ttyUSB0");
}

#[test]
fn test_duplicating_port_config() {
let port1_config = serialport::new("/dev/ttyUSB0", 9600)
let port1_config = SerialPort::builder()
.baud_rate(9600)
.data_bits(DataBits::Five)
.flow_control(FlowControl::None)
.parity(Parity::None)
.stop_bits(StopBits::One)
.timeout(Duration::from_millis(1));

let port2_config = port1_config.clone().path("/dev/ttyUSB1").baud_rate(115_200);
let port2_config = port1_config.clone().baud_rate(115_200);

let _port1 = port1_config.open();
let _port1 = port2_config.open();
let _port1 = port1_config.open("/dev/ttyUSB0");
let _port1 = port2_config.open("/dev/ttyUSB1");
}
7 changes: 4 additions & 3 deletions tests/test_try_clone.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#![cfg(unix)]
extern crate serialport;

use serialport::{SerialPort, TTYPort};
use serialport::SerialPort;
use serialport::posix::SerialPortExt;
use std::io::{Read, Write};

// Test that cloning a port works as expected
#[test]
fn test_try_clone() {
let (master, mut slave) = TTYPort::pair().expect("Unable to create ptty pair");
let (master, mut slave) = SerialPort::pair().expect("Unable to create ptty pair");

// Create the clone in an inner scope to test that dropping a clone doesn't close the original
// port
@@ -36,7 +37,7 @@ fn test_try_clone() {
fn test_try_clone_move() {
use std::thread;

let (master, mut slave) = TTYPort::pair().expect("Unable to create ptty pair");
let (master, mut slave) = SerialPort::pair().expect("Unable to create ptty pair");

let mut clone = master.try_clone().expect("Failed to clone the slave");
let loopback = thread::spawn(move || {
21 changes: 11 additions & 10 deletions tests/test_tty.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Tests for the `posix::TTYPort` struct.
//! Tests for the `posix::SerialPort` struct.
#![cfg(unix)]

extern crate serialport;
@@ -8,12 +8,13 @@ use std::os::unix::prelude::*;
use std::str;
use std::time::Duration;

use serialport::{SerialPort, TTYPort};
use serialport::SerialPort;
use serialport::posix::SerialPortExt;

#[test]
fn test_ttyport_pair() {
// FIXME: Create a mutex across all tests for using `TTYPort::pair()` as it's not threadsafe
let (mut master, mut slave) = TTYPort::pair().expect("Unable to create ptty pair");
// FIXME: Create a mutex across all tests for using `SerialPort::pair()` as it's not threadsafe
let (mut master, mut slave) = SerialPort::pair().expect("Unable to create ptty pair");
master
.set_timeout(Duration::from_millis(10))
.expect("Unable to set timeout on the master");
@@ -70,8 +71,8 @@ fn test_ttyport_timeout() {
let result_thread = result.clone();

std::thread::spawn(move || {
// FIXME: Create a mutex across all tests for using `TTYPort::pair()` as it's not threadsafe
let (mut master, _slave) = TTYPort::pair().expect("Unable to create ptty pair");
// FIXME: Create a mutex across all tests for using `SerialPort::pair()` as it's not threadsafe
let (mut master, _slave) = SerialPort::pair().expect("Unable to create ptty pair");
master.set_timeout(Duration::new(1, 0)).unwrap();

let mut buffer = [0u8];
@@ -98,9 +99,9 @@ fn test_ttyport_set_standard_baud() {
// `master` must be used here as Dropping it causes slave to be deleted by the OS.
// TODO: Convert this to a statement-level attribute once
// https://github.com/rust-lang/rust/issues/15701 is on stable.
// FIXME: Create a mutex across all tests for using `TTYPort::pair()` as it's not threadsafe
// FIXME: Create a mutex across all tests for using `SerialPort::pair()` as it's not threadsafe
#![allow(unused_variables)]
let (master, mut slave) = TTYPort::pair().expect("Unable to create ptty pair");
let (master, mut slave) = SerialPort::pair().expect("Unable to create ptty pair");

slave.set_baud_rate(9600).unwrap();
assert_eq!(slave.baud_rate().unwrap(), 9600);
@@ -124,9 +125,9 @@ fn test_ttyport_set_nonstandard_baud() {
// `master` must be used here as Dropping it causes slave to be deleted by the OS.
// TODO: Convert this to a statement-level attribute once
// https://github.com/rust-lang/rust/issues/15701 is on stable.
// FIXME: Create a mutex across all tests for using `TTYPort::pair()` as it's not threadsafe
// FIXME: Create a mutex across all tests for using `SerialPort::pair()` as it's not threadsafe
#![allow(unused_variables)]
let (master, mut slave) = TTYPort::pair().expect("Unable to create ptty pair");
let (master, mut slave) = SerialPort::pair().expect("Unable to create ptty pair");

slave.set_baud_rate(10000).unwrap();
assert_eq!(slave.baud_rate().unwrap(), 10000);