From c56fa32b2cbebe7e2e9b009d9cb85e56c6673e8b Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Wed, 10 Mar 2021 02:52:39 -0800 Subject: [PATCH] Use rust serial crate for reading from serial Incomplete - can successfully initiate contact w/ radio but can't read data --- Cargo.toml | 1 + src/radio.rs | 4 +-- src/serial.rs | 90 +++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 83 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6e558e2..a6c395f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ crate-type = ["staticlib"] libc = "0.2" getopts = "0.2" chrono = "0.4" +serial = "0.4" [build-dependencies] bindgen = "0.53.1" diff --git a/src/radio.rs b/src/radio.rs index 5ef0ee2..62786ae 100644 --- a/src/radio.rs +++ b/src/radio.rs @@ -44,8 +44,6 @@ extern { fn hid_init(vid: c_int, pid: c_int) -> c_int; fn hid_identify() -> *const c_char; fn hid_close(); - - fn serial_close(); } @@ -127,7 +125,7 @@ pub fn disconnect() { dfu_reboot(); dfu_close(); hid_close(); - serial_close(); + crate::serial::close(); } } diff --git a/src/serial.rs b/src/serial.rs index 5a3b47f..de9f2c8 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -1,9 +1,12 @@ -use std::ffi::{CStr, CString}; +use std::ffi::{CStr}; use libc::{c_char}; +use std::process::exit; +use std::time::Duration; extern { fn find_path(vid: libc::c_int, pid: libc::c_int) -> *const c_char; fn serial_identify(s: *const c_char) -> *const c_char; + fn serial_close(); } /// Connect to the specified device. @@ -23,17 +26,86 @@ pub fn serial_init(vid: u32, pid: u32, trace_flag: bool) -> Option { Some(dev_path) } +fn send_receive(port: &mut dyn serial::SerialPort, command: &[u8], reply_len: usize, trace: bool) -> Vec { + if trace { + eprintln!("----Send [{}] {:?}", command.len(), command); + } + + match port.write(&command) { + Ok(n) => { + if trace { + eprintln!("Wrote {} bytes over serial", n); + } + }, + Err(e) => { + eprintln!("Serial write error: {}", e); + exit(-1); + } + }; + + let mut buf: Vec = vec![0; reply_len]; + match port.read(&mut buf) { + Ok(n) if n == reply_len => { + if trace { + eprintln!("----Received [{}] {:?}", reply_len, buf); + } + }, + Ok(n) => { + eprintln!("Serial: read {} bytes, expected {}", n, reply_len); + } + Err(e) => { + eprintln!("Serial read error: {}", e); + exit(-1); + } + }; + buf +} + /// Query and return the device identification string. /// On error, return None. pub fn identify(dev_path: &str) -> Option { - let dev_path_c = CString::new(dev_path).unwrap(); - let ptr = dev_path_c.as_ptr() as *mut c_char; - unsafe { - let output = serial_identify(ptr); - if output.is_null() { - None - } else { - Some(CStr::from_ptr(output).to_str().unwrap().to_string()) + use serial::prelude::*; + + let mut port = match serial::open(dev_path) { + Ok(port) => port, + Err(err) => { + println!("{}", err); + exit(-1); } + }; + + port.reconfigure(&|settings: &mut dyn SerialPortSettings| { + settings.set_baud_rate(serial::BaudRate::Baud115200)?; + settings.set_char_size(serial::CharSize::Bits8); + Ok(()) + }).unwrap(); + port.set_timeout(Duration::new(1,0)).unwrap(); + + let program_cmd = b"PROGRAM"; + let program_cmd_2 = b"\x02"; + + let program_ack = b"QX\x06"; + let command_ack: u8 = b'\x06'; + + let output = send_receive(&mut port, program_cmd, 3, true); + if output != program_ack { + eprintln!("serial identify: wrong PRG acknowledge {:?}, expected {:?}", output, program_ack); + } + + // Expected output should be something like: + // 49 44 38 36 38 55 56 45 00 56 31 30 32 00 00 06 + // I D 8 6 8 U V E V 1 0 2 + let output = send_receive(&mut port, program_cmd_2, 16, true); + if (output[0] != 'I' as u8) || (output[15] != command_ack) { + eprintln!("serial identify: wrong PRG2 reply {:?} expected 'I'...'\\6'", output); + } + + return Some(String::from_utf8(output[1..7].to_vec()).unwrap()) +} + +/// Close the serial port. +pub fn close() { + unsafe { + serial_close(); } }