Giter Club home page Giter Club logo

serial-rs's Introduction

Serial

The serial port crates provide Rust interfaces for working with serial ports. Serial ports are defined as traits to support extension through custom implementations.

NOTE: With the release of serial v0.4, the implementation is now split into several crates. While the new organization is still experimental, the serial crate reexports many of the types so that it's mostly backward-compatible with v0.3.

Usage

In Libraries

Libraries should link to serial-core.

In Executables

Executables should choose a serial port implementation. A cross platform implementation is provided in the serial crate.

Contributors

License

Copyright © 2015 David Cuddeback

Distributed under the MIT License.

serial-rs's People

Contributors

apoloval avatar darkeye9 avatar dcuddeback avatar ropp avatar tessi avatar willem66745 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

serial-rs's Issues

Document how to close a serial port

There isn't a close() function and calling port.drop() isn't possible. I'm unclear if calling open() multiple times when it succeeds will keep the initial ports open or they will be closed automatically. If so, then this should be explicitly documented, otherwise a close() method should be added.

example in README is broken

port.configure is using a closure in the example, but the documentation shows it should receive a PortSettings struct

Does not seem to work with pseudo-terminals on OS X

I considered this library for a project, but I couldn't get it to work in my test environment using pseudo-terminals on OS X (e.g. /dev/ptyp3, /dev/ttyp3).

I was able to do what I needed just fine with pySerial, so I don't think my understanding of pseudo-terminals is lacking.

I have no idea if this would work for a real connection, but without a reliable way to test, I'd waste too much time. If this issue could be fixed, I may revisit the project.

Missed support for tcflush()

There is a call tcflush() in termios Unix interface that is quite useful when used in TCIFLUSH queue selector. It allows us to efficiently clear OS input buffer from possible garbage data appeared during RS232 line idle. it is quite common when the peripheral RS232 device works in transaction mode, i.e. it is listening for host requests and responding on each request, not initiating transfer on its own. In this case calling tcflush() before writing the request at host side is a good practice.

Permit numerical setting of baud rate

It would be welcome addition if all baud rates could be set with an integer via the BaudOther() type. Presently one must use Baud115200 instead of BaudOther(115200) but must use BaudOther(230400) instead of Baud230400. Is there a reason for this pattern?

Add SerialPort::get_configuration()

In lieu of #28 I'm creating this issue, since there's no way for me to reopen an issue. This is a suggestion to add the following function to the SerialPort trait:

fn get_configuration(&self) -> PortSettings

I don't believe it should return a Result or Option as this should return the default configuration as soon as the port is created/opened and I can't imagine a scenario where as long as the SerialPort object exists, this could return a valid instance.

This is important to round out the possible round-tripping of settings. Right now configure() exists as a way to import settings but there's no way to export settings. This allows for copying configuration settings for a SerialPort to a new one (a use case I have in my serial terminal that supports changing ports).

Supporting mio library

The mio library supports asynchronous I/O for UDP and higher-level protocols. I'd love to use it with serial-rs as well to support serial-to-UDP or serial-to-TCP applications easily. Have you looked at that framework at all?

read timeout with Arduino

I'm trying to use this library with an Arduino Nano. I am able to open the COM port on Windows (the Arduino resets itself when this happens) but I am unable to read anything from the port. I set the port timeout to 1000 milliseconds, but whenever I read I immediately get "operation timed out".
Any ideas?

Only works one time ?

Hi,
I'm using this command to setup 2 connected virtual ports:

socat -d -d pty,raw,echo=0,crnl pty,raw,echo=0,crnl

Then i run the test program, al goes fine.
I run the testingprogram again, i Got an error.
thread '

' panicked at 'called Result::unwrap() on an Err value: Error { repr: Os(16) }', /home/rustbuild/src/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libcore/result.rs:729

If i Kill the virtual COM ports and use the setup command again it works 1 time.
is the port not correctly closed or access is being reset?

// get exclusive access to device

  •    try!(ioctl::tiocexcl(port.fd));
    

Maybe this commit created the problem ?

Maintenance Status

Hi,
this useful crate is used in projects like linux-embedded-hal and others. Hence I stumbled upon it :)
There has however not been any activity for years now and there are a number of open PRs and Issues.
What's the maintenance status, are you planning to maintain it further?

If not so, I think it might be a good idea to report this crate as unmaintained in rustsec, to give people who run cargo audit a heads-up.

Let me know what you think :)

Unsafe pointer mutation

For the std::io::Write implementation on TTYPort, a *const ptr is cast to *mut:

libc::write(self.fd, buf.as_ptr() as *mut c_void, buf.len() as size_t)

This is unnecessary, as libc::write takes buf: *const c_void, so buf.as_ptr() as *const c_void would work fine.

For the std::io::Read implementation on TTYPort, similar but worse, as the pointer is mutated:

libc::read(self.fd, buf.as_ptr() as *mut c_void, buf.len() as size_t)

In this case, the solution is buf.as_mut_ptr() as *mut c_void. The documentation on slice.as_ptr():

The caller must also ensure that the memory the pointer (non-transitively) points to is never written to (except inside an UnsafeCell) using this pointer or any pointer derived from it. If you need to mutate the contents of the slice, use as_mut_ptr.

I haven't checked any other code, so there may be more.

Provide a `try_clone()` method for ports/devices

Some IO types of standard library as std::net::TcpStream support cloning. This is necessary to implement some non-trivial communication patterns in which one thread performs the reads and a different one performs the writes.

serial-rs lacks this functionality. It would be great to have a try_clone(&self) function in SerialPort and SerialDevice that makes possible to clone the port so copies can be used by different threads.

Have a NativePort type

I'd like to create a struct that is just a wrapper over a serial port:

use serial::SerialPort;
struct SomeStruct<S: SerialPort> {
    dev: S,
}

But in order to provide an open function, I'll have to duplicate the cfg logic that you already have:

#[cfg(unix)]
impl SomeStruct<serial::posix::TTYPort> {
    pub fn open() -> Result<Self>;
}

#[cfg(windows)]
impl SomeStruct<serial::windows::COMPort> {
    pub fn open() -> Result<Self>;
}

It'd be nice if serial provided a type alias for the native implementation of SerialDevice, so that I could do something like this:

use serial::NativeDevice;
impl SomeStruct<NativeDevice> {
    pub fn open() -> Result<Self>;
}

and it would work on all supported platforms.

error: use of deprecated `try` macro

From the example on the home page: https://github.com/dcuddeback/serial-rs/tree/master/serial

rustc -V --> rustc 1.72.1

   Compiling rust_serial v0.1.0 (C:\Users\r\GitHub\rust_serial)
error: use of deprecated `try` macro
  --> src\main.rs:18:5
   |
18 | /     try!(port.reconfigure(&|settings| {
19 | |         try!(settings.set_baud_rate(serial::Baud9600));
20 | |         settings.set_char_size(serial::Bits8);
21 | |         settings.set_parity(serial::ParityNone);
...  |
24 | |         Ok(())
25 | |     }));
   | |_______^
   |
   = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated
help: you can use the `?` operator instead

API for allowing different timings for settings-changes to take effect

Currently, settings (on Linux) are changed using tcsetattr in write_settings, passing in TCSANOW for optional_actions. This causes the new settings to take effect immediately, here's the code in question:

    fn write_settings(&mut self, settings: &TTYSettings) -> ::Result<()> {
        use self::termios::{tcsetattr, tcflush};
        use self::termios::{TCSANOW, TCIOFLUSH};


        // write settings to TTY
        if let Err(err) = tcsetattr(self.fd, TCSANOW, &settings.termios) {
            return Err(super::error::from_io_error(err));
        }

        if let Err(err) = tcflush(self.fd, TCIOFLUSH) {
            return Err(super::error::from_io_error(err));
        }

        Ok(())
    }

WIth the proposed pull request #42 , this (on Linux) changes to:

    #[cfg(target_os = "linux")]
    fn write_settings(&mut self, settings: &TTYSettings) -> ::Result<()> {
        let err = unsafe { ioctl::ioctl(self.fd, TCSETS2, &settings.termios) };

        if err != 0 {
            return Err(super::error::from_raw_os_error(err));
        }
        Ok(())
    }

Instead of tcsetattr, the TCSETS2 ioctl is used.


The issue here is that TCSANOW is hardcoded, which prevents using some of the useful alternative options (from man tcsetattr(3)):

arg meaning
TCSANOW the change occurs immediately.
TCSADRAIN the change occurs after all output written to fd has been transmitted. This option should be used when changing parameters that affect output.
TCSAFLUSH the change occurs after all output written to the object referred by fd has been transmitted, and all input that has been received but not read will be discarded before the change is made.

This parameter cannot be specified with the TCSETS2, instead, different IOCTLS must be used. The old equivalents are documented in tty_ioctl(4):

       TCSETS    const struct termios *argp
              Equivalent to tcsetattr(fd, TCSANOW, argp).
              Set the current serial port settings.

       TCSETSW   const struct termios *argp
              Equivalent to tcsetattr(fd, TCSADRAIN, argp).
              Allow the output buffer to drain, and set the current serial
              port settings.

       TCSETSF   const struct termios *argp
              Equivalent to tcsetattr(fd, TCSAFLUSH, argp).
              Allow the output buffer to drain, discard pending input, and
              set the current serial port settings.

Note the missing 2. An equivalent TCSETS2, TCSETSW2 and TCSETSF2 exist (some information about these can be found here); they work pretty much the same, except that they require a struct termios2 * instead of a struct termios *.


A feature that is currently missing in serial-rs is the ability to specifiy when the settings changes should take effect. This API needs to be designed and added to the trait first, I'll happily implemented it on Linux, but I'd like to avoid introducing core API changes that may be rejected.

Currently, a workaround exists: Calling flush() on the SerialPort and only then writing new settings. This will cause an additional gap in transmisison for as long as it takes to setup and transfer these settings into the kernel.


A usecase for this is implementing DMX512 using an RS485 serial port. The DMX512 has a lenient but weird structure, it basically is just a regular UART serial port at 250,000 baud (hence the other pull request for non-standard bitrates).

However, to begin transmission of a frame a DMX master must send a long BREAK by pulling the line low for a fairly long amount of time, then releasing it. This can easily be emulated on any UART by setting the bitrate to 57,000 baud, writing a 0x00 byte (7 bit), which will result in a 138 us BREAK (the minimum is 92 us). Directly after (but not during) the port should be switched to 250,000 baud and transmission can begin. In Pseudo-code:

  1. Set to low bitrate/7 bit.
  2. Send BREAK
  3. Set to high bitrate/8 bit
  4. Send data
  5. Drain
  6. Repeat for next packet.

Step 3. could be improved by preparing the new settings in advanced through TCSETSW2, hopefully causing minimal delay when switching bitrates.

public interface changes depending on operating system

Right now the open function returns a different type depending on if you compile for Linux / Windows.
This makes it more difficult to write cross-platform code using this library. A better approach would be to have a struct that represents a generic serial port . Then each operating system would provide a different implementation of the SerialPort trait for this common struct. This allows cross-platform code to be written using the generic serial port struct without caring how it was implemented, instead of having TTYPort, and COMPort.

Support non-blocking operation

I am using serial-rs on Linux (both Ubuntu and OpenWRT), so this mostly only applies to serial-unix.

I use the Calloop event loop for event-driven systems. Under the hood (on Linux), Calloop basically uses epoll() with whatever file descriptors it extracts from things that implement AsRawFd. The general contract of epoll() in edge-triggered mode (which is what I tend to use) is:

  • wait until epoll_await() tells you to write
  • try to write N bytes from a buffer
  • keep trying this until write() returns -1 and errno is EAGAIN
  • go back to epoll_await()

This relies on the fd being opened in non-blocking mode. In blocking mode, you will never get EAGAIN, write() will simply block until all bytes are written.

In tty.rs you do indeed open the fd as non-blocking. But very shortly after, you clear this flag. This makes it impossible to use serial and enjoy non-blocking writes.

So for example, if I try to write N bytes from a buffer, this call eventually comes down to your implementation of io::Write. You call ppoll() with the timeout and then attempt the write. But even if the timeout is zero, the write will potentially block until all bytes are written.

The workaround we have for this at the moment is to write one byte at a time. That way any time spent blocking on write() is quite short and potentially, but not always, detected beforehand by ppoll().

Versions: Rust 1.53, serial 0.4.0,
Tried on: Ubuntu 20.10 and 21.04, OpenWRT (ramips + musl).

Sized trait missing for SerialPort

This prevents creating helper functions for creating a serial port like: fn open_port(port_name: String, baud_rate: usize) -> serial::Result<SerialPort>()

Is there a reason Sized can't be implemented for this type? I might be missing something since I'm still new to Rust, but I think making a helper function for this will be a common use-case for users of this library.

Crate doesn't work for new target triples

In my case, I am using the Yocto meta-rust layer to build some code that in turn depends on this crate. Within this particular build system, the the target ends up being arm-poky-linux-gnueabi. The serial crate fails to compile with the following error:

.../serial-0.3.4/src/posix/tty.rs:2:1: 2:22 error: can't find crate for `termios` [E0463]
.../cargo_home/registry/src/github.com-88ac128001ac3a9a/serial-0.3.4/src/posix/tty.rs:2 extern crate termios;
                                                                                        ^~~~~~~~~~~~~~~~~~~~~

The cause of this is that the Cargo.toml for this package seems to be trying to guess at all the possible targets that might exist that would require specific dependencies.

There are better approaches for this in more recent version of Cargo (http://doc.crates.io/specifying-dependencies.html#platform-specific-dependencies). I'll open a PR shortly with an attempt to fix this issue.

Higher baud rates for macOS

Arbitrary baud rates—in particular 460800—are available on macOS using a special IOKit call. Kindly consider a special case ioctl call for them. Here is what pyserial does:

    IOSSIOSPEED = 0x80045402 
    class PlatformSpecific(PlatformSpecificBase):
        osx_version = os.uname()[2].split('.')
        # Tiger or above can support arbitrary serial speeds
        if int(osx_version[0]) >= 8:
            def _set_special_baudrate(self, baudrate):
                # use IOKit-specific call to set up high speeds
                buf = array.array('i', [baudrate])
                fcntl.ioctl(self.fd, IOSSIOSPEED, buf, 1)

Document the use cases for SerialPort::configure() versus SerialPort::reconfigure()

This also comes out of #28 since it split into a few different issues.

I'd like to suggest that the documentation make more clear the different between configure() and reconfigure() from the user's perspective. As a user of the serial library and looking at these functions and the documentation for them, I would think I'd want to use configure() for the initial configuration and reconfigure() for every configuration afterwards. But it's not clear that a) this is the recommended method and b) that this is the required way to use these. Especially since the example code only ever uses reconfigure().

Maybe it makes more sense to remove configure() and create a second function open_with_config() that takes the port name and the desired initial configuration. And then reconfigure() is always used after initialization. I think that'd make the interface smaller and more clear. This would also compliment #31 by making opening new ports reusing existing port settings require 1 less function call.

BaudOther(9600) fails where Baud9600 succeeds

I have a program I'm working on where I'd like to specify the baud rate from the command line. I'm using the BaudOther enum. I'm using an FTDI cable and if I use Baud9600 I can configure it properly but if I use BaudOther(9600) it fails. I'm not certain how to debug this further.

Add ARMv7 target

Hello!

Is there any reason armv7 is not available as a target? Could you add it?

$ rustc -v --version
rustc 1.9.0-beta.2 (87cb73304 2016-05-04)
binary: rustc
commit-hash: 87cb733048f0072199b66bb3c0efe61d52623900
commit-date: 2016-05-04
host: armv7-unknown-linux-gnueabihf
release: 1.9.0-beta.2

Thanks!

Multiple bluetooth connections

Hello there.
To begin with, I also posted a question on stackoverflow (but didnt get the answer).
I am not very competent in this article, but I will try to explain as good as I understand it.

In Qt, it's possible to open 2 (probably more) bluetooth connections same time, using QSerialPort (just having 2 instances of it).
In Rust, I also tried it, but it looks like it's impossible (after 1 connection is established, new one will close previous one). The thing is that it works just fine if I open 2 serials same time via usb connection (or mixing it with 1 BT connection).

rustc 1.9.0
OSX 10.11.5

Serial open forced to specify tiocexcl, serial-rs cannot work under WSL1

serial-rs use ioctl::tiocexcl(port.fd) to set exclusive access to device.

if let Err(err) = ioctl::tiocexcl(port.fd) {

Since WSL1 does not support tiocexcl, this will cause rust-rs to not work under WSL1. Whether it is possible to cancel the mandatory use of tiocexcl, so that users of serial-rs can freely choose.
Both minicom and pyserial do not enforce tiocexcl, they both work fine under WSL1. And the problem I actually encountered is esp-rs/espmonitor#47, I really hope serial-rs can support it.

Set timeout

This function set_timeout() seems to be required? If I want to set it to not timeout how should I set it?

Question: Raise RTS/DSR lines without handshaking

Is it possible to raise both the RTS and DSR lines independent of handshaking?

I need these lines to be high for a serial to TTL converter but my communication will be bi-directional while this is taking place.

serial::windows::com::COMPort does not implement Send trait

I'm writing an application using serial-rs, and I've found an obstacle trying to use it in a multithreading context.

The point is that I'm make a sort of serial port scanner. A listener thread will scan serial ports until a new device is connected. Then it creates a new thread and passes the SerialPort instance to it using move semantics.

In order to do that, SerialPort implementations must implement Send trait. The native implementation for Windows, serial::windows::com::COMPort if I'm not wrong, does not according to the following compilation error:

src\port\serial.rs:43:9: 43:18 error: the trait `core::marker::Send` is not implemented for the type `*mut *mut libc::c_void` [E0277]
src\port\serial.rs:43         Self::new(domain, proto::oacsp())
                              ^~~~~~~~~
src\port\serial.rs:43:9: 43:18 help: run `rustc --explain E0277` to see a detailed explanation
src\port\serial.rs:43:9: 43:18 note: `*mut *mut libc::c_void` cannot be sent between threads safely
src\port\serial.rs:43:9: 43:18 note: required because it appears within the type `serial::windows::com::COMPort`
src\port\serial.rs:43:9: 43:18 note: required because it appears within the type `proto::oacsp::output::MessageConsumer<serial::windows::com::COMPort>`
src\port\serial.rs:43:9: 43:18 note: required because it appears within the type `proto::oacsp::writer::EventWriter<proto::oacsp::output::MessageConsumer<serial::windows::com::COMPort>>`
src\port\serial.rs:43:9: 43:18 note: required by `port::serial::SerialPort::new` 

Moving the SerialPort instance from one thread to another should not be forbidden. Sharing it perhaps should not. Thus, Send + 'static should be implemented but Sync should not.

Need a way to send a serial BREAK

Hi,

I'm dealing with an interface that requires me to send a serial BREAK. Can you please add that functionality? On Linux, it's tcsendbreak(3).

Thanks!

how to detect available com ports?

How can I detect the available com ports on *nix and Windows? Is this possible with this crate? I haven't found a function.

I can check for com ports in Linux by looking at typical /dev/tty* patterns like /dev/ttyUSB*. But is there a system independent way?

I can't receive \x11 bytes of data

Everything is working fine, but the strange thing is that I can't receive \x11 bytes of data.
The data I receive is [EF, AA, 01, 00, 01, 01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, FF, 00, FF, 00, FF], but it should actually be [EF, AA, 01, 00, 11, 01, 01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, FF, 00, FF, 00, FF]

Clarity on cloning port settings to a new port

I'm writing code that will change the underlying port when the user requests it. That means I want to copy the current port settings, overwrite the current port reference I have with a new one of the new port, and apply the copied settings to the new port. It's unclear to me as to what the best way to do this is given the configure(), reconfigure() functions, and the read_settings() and write_settings() functions. I would have thought the following would work, but I think I'm misunderstanding the API somewhat as this doesn't give the expected behavior:

// port is an Option<Box<serial::SystemPort>>
if port.is_some() {
    println!("Changing port to {}", name);
    let old_port = port.unwrap();
    let new_settings = (*old_port).read_settings().unwrap();
    let mut p = Box::new(serial::open(&name).unwrap());
    p.write_settings(&new_settings).unwrap();
    port = Some(p);
}

Windows support

Is there a plan to offer Windows support for this library?

OS independed PortSettings

Right now it is impossible to use PortSettings as a os independent settings.

trait `From<PortSettings>` is not implemented for `TTYSettings`

What I mean is to pass PortSettings to write_settings()

Can you please provide such ?

Relicense under dual MIT/Apache-2.0

This issue was automatically generated. Feel free to close without ceremony if
you do not agree with re-licensing or if it is not possible for other reasons.
Respond to @cmr with any questions or concerns, or pop over to
#rust-offtopic on IRC to discuss.

You're receiving this because someone (perhaps the project maintainer)
published a crates.io package with the license as "MIT" xor "Apache-2.0" and
the repository field pointing here.

TL;DR the Rust ecosystem is largely Apache-2.0. Being available under that
license is good for interoperation. The MIT license as an add-on can be nice
for GPLv2 projects to use your code.

Why?

The MIT license requires reproducing countless copies of the same copyright
header with different names in the copyright field, for every MIT library in
use. The Apache license does not have this drawback. However, this is not the
primary motivation for me creating these issues. The Apache license also has
protections from patent trolls and an explicit contribution licensing clause.
However, the Apache license is incompatible with GPLv2. This is why Rust is
dual-licensed as MIT/Apache (the "primary" license being Apache, MIT only for
GPLv2 compat), and doing so would be wise for this project. This also makes
this crate suitable for inclusion and unrestricted sharing in the Rust
standard distribution and other projects using dual MIT/Apache, such as my
personal ulterior motive, the Robigalia project.

Some ask, "Does this really apply to binary redistributions? Does MIT really
require reproducing the whole thing?" I'm not a lawyer, and I can't give legal
advice, but some Google Android apps include open source attributions using
this interpretation. Others also agree with
it
.
But, again, the copyright notice redistribution is not the primary motivation
for the dual-licensing. It's stronger protections to licensees and better
interoperation with the wider Rust ecosystem.

How?

To do this, get explicit approval from each contributor of copyrightable work
(as not all contributions qualify for copyright, due to not being a "creative
work", e.g. a typo fix) and then add the following to your README:

## License

Licensed under either of

 * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
 * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.

and in your license headers, if you have them, use the following boilerplate
(based on that used in Rust):

// Copyright 2016 serial-rs developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

It's commonly asked whether license headers are required. I'm not comfortable
making an official recommendation either way, but the Apache license
recommends it in their appendix on how to use the license.

Be sure to add the relevant LICENSE-{MIT,APACHE} files. You can copy these
from the Rust repo for a plain-text
version.

And don't forget to update the license metadata in your Cargo.toml to:

license = "MIT/Apache-2.0"

I'll be going through projects which agree to be relicensed and have approval
by the necessary contributors and doing this changes, so feel free to leave
the heavy lifting to me!

Contributor checkoff

To agree to relicensing, comment with :

I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option.

Or, if you're a contributor, you can check the box in this repo next to your
name. My scripts will pick this exact phrase up and check your checkbox, but
I'll come through and manually review this issue later as well.

Status of project

There hasn't been any commits since July 9th to this project. I'm depending on this project for my gattii software and have been waiting for serial enumeration to stabilize, though there doesn't seem to be any progress here. Are you still actively developing this project where your work has just been private so far or is it safe to consider this abandoned?

read() only blocks once

If I run this example, it waits for the first character, then once that's been received it prints "Read []" very fast in a tight loop. It looks like ppoll() says fd has the POLLIN event but read() returns 0.

Have I done something wrong, or is this a bug? I'm using a USB Serial adapter with CentOS 7 and rustc 1.12.1.

extern crate serial;

use std::io::Read;
use std::time::Duration;
use serial::SerialPort;

fn main() {
    println!("Hello, world!");
    let mut port = serial::open("/dev/serial/by-id/usb-9710_7720-if00-port0").unwrap();
    port.set_timeout(Duration::from_secs(1)).unwrap();
    port.reconfigure(&|settings| {
        try!(settings.set_baud_rate(serial::Baud9600));
        settings.set_char_size(serial::Bits8);
        settings.set_parity(serial::ParityNone);
        settings.set_stop_bits(serial::Stop1);
        settings.set_flow_control(serial::FlowHardware);
        Ok(())
    }).unwrap();

    loop {
        let mut temp = Vec::with_capacity(50);
        match port.read(&mut temp) {
            Ok(len) => {
                unsafe { temp.set_len(len) };
                println!("Read {:?}", temp);
             }
             Err(why) => println!("Error: {}", why)
        }
    }
}

some device not support setting port to exclusive mode

Hi,

I was trying to use serial-rs on an openwrt device with MT7260 CPU. It seems that serial port on MT7260 does not support being set to exclusive mode. Here is the result of strace,

ioctl(3, TIOCEXCL, 0xfa00) = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TIOCNXCL, 0xa4) = -1 EFAULT (Bad address)

Maybe it would be better if setting exclusive be an option when opening a port.

Thanks

Full duplex read-write in two threads

I'd like to read from a port in one thread (in a blocking fashion) while handling writes in a second thread. I don't believe I can do this with a single SerialPort object that implements both Read and Write.

The way std::sync::mpsc solves the problem is to have two objects: an RX and a TX object.

Does that sound like a good approach? Is there another way to split my reads and writes between two threads?

Add a function to return all supported standard baud rates for the port

This doesn't need to include non-standard baud rates, but it would be nice for when the user needs to select a baud rate from a list (like in a GUI dropdown) if there was a way to get a list of all standard supported rates for the platform as a vector that can be easily used to populate such a dropdown.

How do I read more than one byte at a time?

This may very well be because I simply don't fully understand how the Read trait is supposed to work.

Running this code:

let mut buf: Vec<u8> = vec![0u8; 50];
println!("{}", port.read(&mut buf[0..50]).unwrap());

only '1' to the screen. buf contains the first byte received at index 0, and the original zeros are still at indices 1:49.

I would expect that the port should read 50 bytes into the given buffer, as there is no way to pass the number of bytes to read... ? What am I doing wrong here?

For reference, I'm sending this:

debug_assert!(port.write("*idn?\n".as_bytes()).unwrap() == 6);

over a usb -> rs232 converter, which sends back a 50-byte identification string (tested using pyserial).

Furthermore, I was able to read all bytes one by one and print them out using a for loop:

for _ in 0..50 {
    port.read(&mut buf[0..50]).unwrap();
    print!("{}", buf[0] as char);
}

but that isn't exactly a solution to the problem.

Crate issue on target mipsel

Compiling this crate for target "mipsel-unknown-linux-musl" yields a problem I've never seen before...

error[E0463]: can't find crate for termios --> /home//CARGO_HOME/git/checkouts/serial-rs-2342861c2cbe3710/9025963/src/posix/tty.rs:2:1 | 2 | extern crate termios; | ^^^^^^^^^^^^^^^^^^^^^ can't find crate

It looks like you're missing a line for the target in your Cargo.toml
"mipsel-unknown-linux-musl" might be a good idea to add.

Cross compiling for raspberry pi fails

The serial page on crates.io says all I need to do is run cargo build --target=arm-unknown-linux-gnueabihf, but this gives me a linking error. I've tried this on Debian 10 and Debian 10 WSL, though idk if that matters. I have also installed the arm toolchains just in case I needed them, and I have added the toolchain to rustup via rustup target add arm-unknown-linux-gnueabihf

I tried to make the error that was thrown a bit more readable, but this is kinda just how it was given to me.

error: linking with cc failed: exit code: 1 | = note: "cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-L"

"/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.14129l9bxizg2442.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.1875j8dfxlgqlf5h.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.1m5878lz8h4hcijx.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.1zcwirc13ifdw3gs.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.22pabdmp9fm7q95c.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.2332amo2mkcqryaq.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.23ej2x4yiu3w41dh.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.2cop2e9nc98xzpqo.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.2j8g22qebkg148cf.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.2v4txxtr5g16uzb0.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.312s734f5429yamr.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.3388ummpo24fa79f.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.3a6yjxq00ujuwagj.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.3bbjj0m9mjlu4z8l.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.3co1nlu6yhz31iay.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.3evw0i61ik97ltl9.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.3go1sj89zz17b5yj.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.3l0fvbwgyetftdz7.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.3ms02630skfk77yp.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.3no9eztw7r59t4u8.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.3o5a44gugc73u8df.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.40b2ccbqqvs3yd9f.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.461cu7irswgojral.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.47ry9gra4anumb8z.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.48w6sjisq9uttiz.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.4cfx8i5z21z4x43s.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.4e87r81fy5c5a9jo.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.4jjb25ip0r34k7li.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.4saion9cgxfq1bvy.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.5b5w4ohlaj1gc6wh.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.e96kyiuu1kgcivm.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.fucdinacgc5wxdk.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.iu74z1wlennt4k2.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.j1ozygtdld2ax57.rcgu.o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.laul64khxheesxy.rcgu.o" "-o" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.2u0upc8k7ozfcyfi.rcgu.o" "-Wl,--gc-sections" "-pie" "-Wl,-zrelro" "-Wl,-znow" "-nodefaultlibs" "-L" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps" "-L" "/home/penguin/sertest/target/debug/deps" "-L" "/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib" "-Wl,-Bstatic" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/libserial-230ebdc6c54e3cb0.rlib" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/libserial_unix-7ee3ecdf0f0e1fab.rlib" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/libioctl_rs-9dc00a93fde6a385.rlib" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/libtermios-f7ecb77c0cf495f7.rlib" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/liblibc-b75ed3b21a9d7b79.rlib" "/home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/libserial_core-dc02be8937eafa84.rlib" "-Wl,--start-group" "/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib/libstd-b6414ae168385702.rlib" "/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib/libpanic_unwind-efbc2c947951b8cc.rlib" "/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib/libhashbrown-b177382d9a04ffbe.rlib" "/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib/librustc_std_workspace_alloc-ba7d2244d33447d5.rlib" "/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib/libbacktrace-39569dc87e4ea301.rlib" "/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib/libbacktrace_sys-cd9e255bd82ddb5c.rlib" "/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib/librustc_demangle-f83165e777dccb8d.rlib" "/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib/libunwind-10b085de263b1750.rlib" "/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib/libcfg_if-9a4a22edf44da957.rlib" "/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib/liblibc-68fabc677efa98de.rlib" "/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib/liballoc-026dc0061b48e8b6.rlib" "/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib/librustc_std_workspace_core-7bf75bb619341145.rlib" "/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib/libcore-ef54709e300503ed.rlib" "-Wl,--end-group" "/home/penguin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/arm-unknown-linux-gnueabihf/lib/libcompiler_builtins-4ed27d8420cb4abc.rlib" "-Wl,-Bdynamic" "-lc" "-lutil" "-lutil" "-ldl" "-lrt" "-lpthread" "-lgcc_s" "-lc" "-lm" "-lrt" "-lpthread" "-lutil" "-lutil" = note: /usr/bin/ld: /home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.14129l9bxizg2442.rcgu.o: relocations in generic ELF (EM: 40) /usr/bin/ld: /home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.14129l9bxizg2442.rcgu.o: relocations in generic ELF (EM: 40) /usr/bin/ld: /home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.14129l9bxizg2442.rcgu.o: relocations in generic ELF (EM: 40) /usr/bin/ld: /home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.14129l9bxizg2442.rcgu.o: relocations in generic ELF (EM: 40) /usr/bin/ld: /home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.14129l9bxizg2442.rcgu.o: relocations in generic ELF (EM: 40) /usr/bin/ld: /home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.14129l9bxizg2442.rcgu.o: relocations in generic ELF (EM: 40) /usr/bin/ld: /home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.14129l9bxizg2442.rcgu.o: relocations in generic ELF (EM: 40) /usr/bin/ld: /home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.14129l9bxizg2442.rcgu.o: relocations in generic ELF (EM: 40) /usr/bin/ld: /home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.14129l9bxizg2442.rcgu.o: relocations in generic ELF (EM: 40) /usr/bin/ld: /home/penguin/sertest/target/arm-unknown-linux-gnueabihf/debug/deps/sertest-82c733b5c5682e12.14129l9bxizg2442.rcgu.o: error adding symbols: file in wrong format collect2: error: ld returned 1 exit status
error: aborting due to previous error
error: could not compile sertest.

COMPort::open should prepend port name with \\?\

At the moment, COMPort::open only works for COM1-COM9 unless \\?\ is prepended to the string, because the filenames COM1-COM9 are handled specially by the Win32 subsystem, whereas others aren't, causing COMPort::open to attempt to open a file instead.

In contrast, a path like \\?\COM10 specifies a verbatim path, which will work with any COM port.

Should use nix crate

I think this crate should use the nix crate.
They already provide safe bindings to termios and ioctl and we should avoid to split the effort.

I'm trying to use your crate on an Android application and I think it should be more easy with the nix crate as they provide support for Android (it seems there is a bug now on android either in libc or in nix, but it should be fixed).

I hope you'll be open for discussing this point.

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.