Skip to content

Instantly share code, notes, and snippets.

@aniline
Created February 17, 2019 15:25
Show Gist options
  • Save aniline/704c5d849d5f6767f1016c2e49efd0a1 to your computer and use it in GitHub Desktop.
Save aniline/704c5d849d5f6767f1016c2e49efd0a1 to your computer and use it in GitHub Desktop.
Serial read
///
/// Trivial serial read for sensor-y thingies.
/// Sends a new-line to 'trigger' whatever the thingy has to do.
///
/// Needs extern(al) crate termios and getopts (in case it was not obvious).
///
extern crate termios;
extern crate getopts;
use std::env;
use std::fs::{OpenOptions, File};
use std::io::{Write, BufReader, BufRead, Result as IOResult};
use std::os::unix::io::{ IntoRawFd, FromRawFd};
use std::path::Path;
use std::thread::sleep;
use std::time::Duration;
use termios::*;
use termios::os::linux::*;
use getopts::Options;
fn open_serial<P: AsRef<Path>>(p: P, b: speed_t) -> IOResult<File> {
let fd = OpenOptions::new().write(true).read(true).open(p)?.into_raw_fd();
let mut t = Termios::from_fd(fd)?;
t.c_iflag &= !INPCK;
t.c_lflag &= !ICANON;
t.c_cflag &= !(PARENB | CSIZE | CSTOPB);
t.c_cflag |= CS8;
t.c_cc[VMIN] = 1;
t.c_cc[VTIME] = 0;
cfsetspeed(&mut t, b)?;
tcsetattr(fd, TCSAFLUSH, &t)?;
Ok( unsafe { File::from_raw_fd(fd) } )
}
#[derive(Debug)]
struct Config {
pub serial_port: String,
pub send_newline: bool,
pub baud_rate: speed_t,
}
fn baud_from_str(baud_str: &str) -> Option<speed_t> {
let baud = baud_str.parse::<u32>().unwrap_or(115200);
match baud {
0 => Some(B0),
50 => Some(B50),
75 => Some(B75),
110 => Some(B110),
134 => Some(B134),
150 => Some(B150),
200 => Some(B200),
300 => Some(B300),
600 => Some(B600),
1200 => Some(B1200),
1800 => Some(B1800),
2400 => Some(B2400),
4800 => Some(B4800),
9600 => Some(B9600),
19200 => Some(B19200),
38400 => Some(B38400),
57600 => Some(B57600),
115200 => Some(B115200),
230400 => Some(B230400),
460800 => Some(B460800),
500000 => Some(B500000),
576000 => Some(B576000),
921600 => Some(B921600),
1000000 => Some(B1000000),
1152000 => Some(B1152000),
1500000 => Some(B1500000),
2000000 => Some(B2000000),
2500000 => Some(B2500000),
3000000 => Some(B3000000),
3500000 => Some(B3500000),
4000000 => Some(B4000000),
_ => None,
}
}
fn print_usage(progname: &str, opts: Options) {
let brief = format!("Usage: {} [options]", progname);
print!("{}", opts.usage(&brief));
}
impl Config {
pub fn from(m: Vec<String>) -> Result<Config, getopts::Fail> {
let mut opts = Options::new();
let progname = m[0].clone();
let def_serial = "/dev/ttyACM0";
let def_baud = "115200";
opts.optopt ("s", "serial port", "Serial port to use", "DEVICE");
opts.optopt ("b", "baud rate", "Default 115200" , "BAUDRATE");
opts.optflag ("n", "Send newline", "Send a new line after string specified (or empty string)" );
let matches = match opts.parse(&m[1..]) {
Ok(m) => { m },
Err(e) => {
println!("{}", e);
print_usage(&progname, opts);
return Err(e);
}
};
let serial_port = matches.opt_default("s", def_serial).unwrap_or(def_serial.to_string());
let baud_str = matches.opt_default("b", def_baud).unwrap_or(def_baud.to_string());
Ok(Config {
serial_port: serial_port,
send_newline: matches.opt_present("n"),
baud_rate: baud_from_str(&baud_str).unwrap_or(B115200),
})
}
}
fn main() {
let args: Vec<String> = env::args().collect();
if let Ok(config) = Config::from(args) {
let mut f = open_serial(config.serial_port, config.baud_rate).unwrap();
if config.send_newline {
f.write(b"\n").unwrap();
}
// TODO: config wait.
sleep(Duration::from_millis(200));
let mut line_reader = BufReader::new(f);
let mut buf = String::new();
match line_reader.read_line(&mut buf) {
Ok(_) => println!("{}", buf),
Err(e) => println!("Error reading {}", e)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment