From 8891b8b6bf38e25e97cc4a9dca0897897a18e385 Mon Sep 17 00:00:00 2001 From: Leonora Tindall Date: Sat, 28 Dec 2019 08:29:09 -0800 Subject: [PATCH] Basic SerialPort wrapper No real functionality, just a basic version info check to make sure that the device being communicated with is actually the RN2903. --- .gitignore | 2 + Cargo.lock | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 10 +++ src/lib.rs | 116 ++++++++++++++++++++++++++++ src/main.rs | 6 ++ 5 files changed, 346 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/lib.rs create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53eaa21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..80586a0 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,212 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "CoreFoundation-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "mach 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "IOKit-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "CoreFoundation-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "mach 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "aho-corasick" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc" +version = "1.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libudev" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libudev-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libudev-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mach" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mach" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memchr" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "nix" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pkg-config" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quick-error" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "regex" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rn2903" +version = "0.1.0" +dependencies = [ + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serialport 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serialport" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "CoreFoundation-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "IOKit-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libudev 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum CoreFoundation-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e9889e6db118d49d88d84728d0e964d973a5680befb5f85f55141beea5c20b" +"checksum IOKit-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "99696c398cbaf669d2368076bdb3d627fb0ce51a26899d7c61228c5c0af3bf4a" +"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +"checksum libudev 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea626d3bdf40a1c5aee3bcd4f40826970cae8d80a8fec934c82a63840094dcfe" +"checksum libudev-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" +"checksum mach 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2fd13ee2dd61cc82833ba05ade5a30bb3d63f7ced605ef827063c63078302de9" +"checksum mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1" +"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" +"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" +"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" +"checksum serialport 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8d3ecaf58010bedccae17be55d4ed6f2ecde5646fc48ce8c66ea2d35a1419c" +"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..5faa176 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rn2903" +version = "0.1.0" +authors = ["Leonora Tindall "] +edition = "2018" + +[dependencies] +serialport = "3.3" +quick-error = "1" + diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..813653f --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,116 @@ +// One of the critical aspects of this library is error handling. Because it is intended +// to communicate with an external device, any operation could discover a disconnection +// from the RN2903 serial link, so everything which does such communication will return +// a `Result`. +#[macro_use] extern crate quick_error; +use std::io; + +quick_error! { + #[derive(Debug)] + pub enum Error { + /// The connection to the RN2903 was impossible for some reason. Perhaps an + /// invalid port was specified, or this program does not have permission to + /// access the specified port. + ConnectionFailed(err: serialport::Error) { + cause(err) + description(err.description()) + from() + } + /// The device to which the serial link is connected does not appear to be + /// a RN2903, because it did not respond to `sys get ver` correctly. + WrongDevice(version: String) { + description("failed to verify connected module") + display("Could not verify version string. Expected a RN2903 firmware revision, got '{}'", + version) + } + /// The program has become disconnected from the RN2903 module due to an I/O + /// error. It is possible the device was physically disconnected, or that the + /// host operating system closed the serial port for some reason. + Disconnected(err: io::Error) { + cause(err) + description(err.description()) + from() + } + } +} + +/// Universal `Result` wrapper for the RN2903 interface. +type Result = std::result::Result; + +// It's first necessary to actually connect to the module. To this end, the library +// exports all the configuration information needed to configure a serial port to +// communicate correctly with an RN2903. + +use serialport::prelude::*; +use std::io::prelude::*; +use core::convert::AsRef; +use std::ffi::OsStr; +use std::thread; +use core::time::Duration; + +/// Returns a `serialport::SerialPortSettings` corresponding to the default settings of +/// an RNB2903. Use this to configure your serial port. +/// +/// Information obtained from Microchip document 40001811 revision B. Timeout is by +/// default set to a very long time; this is sometimes modified on the `SerialPort` itself +/// during certain operations. +pub fn serial_config() -> SerialPortSettings { + SerialPortSettings { + baud_rate: 57600, + data_bits: DataBits::Eight, + flow_control: FlowControl::None, + parity: Parity::None, + stop_bits: StopBits::One, + timeout: Duration::new(1, 0) + } +} + +// Once connected to a serial port, the library needs to verify that it is actually +// connected to a RN2903 and not some other serial device. To this end, the `Rn2903` +// wrapper struct's `::new()` function checks the output of the `sys get ver` command, +// which is well-specified. + +/// A handle to a serial link connected to a RN2903 module. +/// +/// This library guarantees safety regardless of the state of the RN2903. +pub struct Rn2903 { + port: Box, +} + +impl Rn2903 { + /// Open a new connection to a module at the given path or port name, with the + /// default settings. + pub fn new_at>(port_name: S) -> Result { + let sp = serialport::open_with_settings(&port_name, &serial_config())?; + Self::new(sp) + } + + /// Open a new connection to a module over the given serial connection. + pub fn new(mut port: Box) -> Result { + let mut buf = [0; 35]; + port.write_all(b"sys get ver\x0D\x0A")?; + port.flush()?; + thread::sleep(Duration::from_millis(12)); + port.read(&mut buf)?; + if &buf[0..6] != b"RN2903" { + Err(Error::WrongDevice((&*String::from_utf8_lossy(&buf)).into())) + } else { + Ok(Self { + port + }) + } + } + + /// Query the module for its firmware version information. + /// + /// Returns a `String` like `RN2903 1.0.3 Aug 8 2017 15:11:09` + pub fn system_version(&mut self) -> Result { + let mut buf = [0; 35]; + self.port.write_all(b"sys get ver\x0D\x0A")?; + self.port.flush()?; + thread::sleep(Duration::from_millis(12)); + self.port.read(&mut buf)?; + Ok((&*String::from_utf8_lossy(&buf).trim_end()).into()) + } +} + diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..5db461a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,6 @@ +use rn2903::Rn2903; + +fn main() { + let mut device = Rn2903::new_at("/dev/ttyUSB0").expect("Could not open device. Error"); + println!("Successfully connected. Version: {}", device.system_version().expect("Could not read from device. Error:")); +}