use std::boxed::Box;
use std::str;
use std::time::Duration;
use serialport;
use crate::utils;
use crate::error::{Result, Error};
pub mod settings;
mod loopback;
use loopback::Loopback;
pub struct Serial {
port: Box<dyn serialport::SerialPort>,
read_buffer: Vec<u8>
}
impl Serial {
pub fn open(port_name: &str) -> Result<Serial> {
let settings: settings::Settings = Default::default();
Serial::open_with_settings(port_name, settings)
}
pub fn open_with_settings(port_name: &str, settings: settings::Settings) -> Result<Serial> {
let serial_port_settings = settings.into();
if port_name == "loopback" {
let port = Loopback::open(serial_port_settings);
return Ok(Serial {
port,
read_buffer: vec![0; 1000]
});
}
match serialport::open_with_settings(&port_name, &serial_port_settings) {
Ok(port) => {
Ok(Serial { port, read_buffer: vec![0; 1000] })
},
Err(e) => Err(Error::from(e))
}
}
pub fn settings(&self) -> settings::Settings {
return self.port.settings().into();
}
pub fn name(&self) -> Option<String> {
return self.port.name();
}
pub fn set_baud_rate(&mut self, baud_rate: u32) -> Result<()> {
match self.port.set_baud_rate(baud_rate) {
Ok(_) => Ok(()),
Err(e) => Err(Error::from(e))
}
}
pub fn baud_rate(&self) -> Result<u32> {
match self.port.baud_rate() {
Ok(value) => Ok(value),
Err(e) => Err(Error::from(e))
}
}
pub fn set_data_bits(&mut self, data_bits: settings::DataBits) -> Result<()> {
match self.port.set_data_bits(data_bits.into()) {
Ok(_) => Ok(()),
Err(e) => Err(Error::from(e))
}
}
pub fn data_bits(&self) -> Result<settings::DataBits> {
match self.port.data_bits() {
Ok(value) => Ok(settings::DataBits::from(value)),
Err(e) => Err(Error::from(e))
}
}
pub fn set_parity(&mut self, parity: settings::Parity) -> Result<()> {
match self.port.set_parity(parity.into()) {
Ok(_) => Ok(()),
Err(e) => Err(Error::from(e))
}
}
pub fn parity(&self) -> Result<settings::Parity> {
match self.port.parity() {
Ok(value) => Ok(settings::Parity::from(value)),
Err(e) => Err(Error::from(e))
}
}
pub fn set_stop_bits(&mut self, stop_bits: settings::StopBits) -> Result<()> {
match self.port.set_stop_bits(stop_bits.into()) {
Ok(_) => Ok(()),
Err(e) => Err(Error::from(e))
}
}
pub fn stop_bits(&self) -> Result<settings::StopBits> {
match self.port.stop_bits() {
Ok(value) => Ok(settings::StopBits::from(value)),
Err(e) => Err(Error::from(e))
}
}
pub fn set_flow_control(&mut self, flow_control: settings::FlowControl) -> Result<()> {
match self.port.set_flow_control(flow_control.into()) {
Ok(_) => Ok(()),
Err(e) => Err(Error::from(e))
}
}
pub fn flow_control(&self) -> Result<settings::FlowControl> {
match self.port.flow_control() {
Ok(value) => Ok(settings::FlowControl::from(value)),
Err(e) => Err(Error::from(e))
}
}
pub fn set_timeout(&mut self, timeout: u64) -> Result<()> {
match self.port.set_timeout(Duration::from_millis(timeout)) {
Ok(_) => Ok(()),
Err(e) => Err(Error::from(e))
}
}
pub fn timeout(&self) -> u64 {
return self.port.timeout().as_millis() as u64;
}
pub fn write(&mut self, text: &str) -> Result<usize> {
match self.port.write(text.as_bytes()) {
Ok(count) => Ok(count),
Err(e) => Err(Error::from(e))
}
}
pub fn write_format(&mut self, text: &str, text_format: utils::TextFormat) -> Result<usize> {
let bytes = match text_format {
utils::TextFormat::Binary => utils::bytes_from_binary_string(text)?,
utils::TextFormat::Octal => utils::bytes_from_octal_string(text)?,
utils::TextFormat::Decimal => utils::bytes_from_decimal_string(text)?,
utils::TextFormat::Hex => utils::bytes_from_hex_string(text)?,
_ => {
let mut bytes = Vec::new();
bytes.extend_from_slice(text.as_bytes());
bytes
}
};
match self.port.write(bytes.as_slice()) {
Ok(count) => Ok(count),
Err(e) => Err(Error::from(e))
}
}
pub fn read(&mut self) -> Result<&[u8]> {
let length = match self.port.read(&mut self.read_buffer) {
Ok(length) => length,
Err(e) => return Err(Error::from(e))
};
Ok(&self.read_buffer[..length])
}
pub fn read_str(&mut self) -> Result<String> {
self.read_str_with_format(utils::TextFormat::Text)
}
pub fn read_str_until(&mut self, desired: &str) -> Result<String> {
let mut result = String::new();
loop {
match self.read_str() {
Ok(chunk) => result += &chunk,
Err(e) => return Err(Error::from(e))
}
if result.contains(desired) {
break;
}
}
Ok(result)
}
pub fn read_min_str(&mut self, min_length: usize) -> Result<String> {
self.read_min_str_with_format(min_length, utils::TextFormat::Text)
}
pub fn read_min_str_until(&mut self, min_length: usize, desired: &str) -> Result<String> {
let mut result = String::new();
loop {
match self.read_str() {
Ok(chunk) => result += &chunk,
Err(e) if e.is_timeout() => {
if result.len() >= min_length && result.contains(desired) {
break;
}
return Err(Error::from(e));
},
Err(e) => return Err(Error::from(e))
}
if result.len() >= min_length && result.contains(desired) {
break;
}
}
Ok(result)
}
pub fn read_str_with_format(&mut self, format: utils::TextFormat) -> Result<String> {
let data = self.read()?;
utils::radix_string(data, &format)
}
pub fn read_min_str_with_format(&mut self, min_length: usize, format: utils::TextFormat) -> Result<String> {
let mut response = String::new();
loop {
match self.read() {
Ok(bytes) => {
let new_text = utils::radix_string(bytes, &format)?;
response.push_str(new_text.as_str());
if response.len() >= min_length {
break;
}
},
Err(e) if e.is_timeout() => {
if response.len() < min_length {
return Err(e);
}
break;
},
Err(e) => return Err(e)
}
}
Ok(response)
}
pub fn read_with_timeout(&mut self, timeout: Duration) -> Result<&[u8]> {
let old_timeout = self.port.timeout();
if let Err(e) = self.port.set_timeout(timeout) {
return Err(Error::from(e));
}
let length = self.port.read(&mut self.read_buffer)?;
if let Err(e) = self.port.set_timeout(old_timeout) {
return Err(Error::from(e));
}
Ok(&self.read_buffer[..length])
}
pub fn read_str_with_timeout(&mut self, timeout: Duration) -> Result<String> {
let old_timeout = self.port.timeout();
if let Err(e) = self.port.set_timeout(timeout) {
return Err(Error::from(e));
}
let length = self.port.read(&mut self.read_buffer)?;
if let Err(e) = self.port.set_timeout(old_timeout) {
return Err(Error::from(e));
}
match str::from_utf8(&self.read_buffer[..length]) {
Ok(text) => Ok(text.to_string()),
Err(e) => Err(Error::from(e))
}
}
pub fn read_min_str_with_timeout(&mut self, min_length: usize, timeout: Duration) -> Result<String> {
self.read_min_str_with_format_and_timeout(min_length, utils::TextFormat::Text, timeout)
}
pub fn read_str_until_with_timeout(&mut self, desired: &str, timeout: Duration) -> Result<String> {
let mut result = String::new();
loop {
match self.read_str_with_timeout(timeout) {
Ok(chunk) => result += &chunk,
Err(e) => return Err(Error::from(e))
}
if result.contains(desired) {
break;
}
}
Ok(result)
}
pub fn read_str_with_format_and_timeout(&mut self, format: utils::TextFormat, timeout: Duration) -> Result<String> {
let old_timeout = self.port.timeout();
if let Err(e) = self.port.set_timeout(timeout) {
return Err(Error::from(e));
}
let length = self.port.read(&mut self.read_buffer)?;
let data = &self.read_buffer[..length];
if let Err(e) = self.port.set_timeout(old_timeout) {
return Err(Error::from(e));
}
utils::radix_string(data, &format)
}
pub fn read_min_str_with_format_and_timeout(&mut self, min_length: usize, format: utils::TextFormat, timeout: Duration) -> Result<String> {
let old_timeout = self.port.timeout();
if let Err(e) = self.port.set_timeout(timeout) {
return Err(Error::from(e));
}
let mut response = String::new();
loop {
match self.read() {
Ok(bytes) => {
let new_text = utils::radix_string(bytes, &format)?;
response.push_str(new_text.as_str());
if response.len() >= min_length {
break;
}
},
Err(e) if e.is_timeout() => {
if response.len() < min_length {
if let Err(e) = self.port.set_timeout(old_timeout) {
return Err(Error::from(e));
}
return Err(e);
}
break;
},
Err(e) => {
if let Err(e) = self.port.set_timeout(old_timeout) {
return Err(Error::from(e));
}
return Err(e);
}
}
}
if let Err(e) = self.port.set_timeout(old_timeout) {
return Err(Error::from(e));
}
Ok(response)
}
pub fn check(&mut self, text: &str, desired_response: &str) -> Result<(bool, String)> {
let settings: CheckSettings = Default::default();
self.check_with_settings(text, desired_response, &settings)
}
pub fn check_read(&mut self, desired_response: &str) -> Result<(bool, String)> {
let settings: CheckSettings = Default::default();
self.check_read_with_settings(desired_response, &settings)
}
pub fn check_with_settings(&mut self, text: &str, desired_response: &str, settings: &CheckSettings) -> Result<(bool, String)> {
self.write_format(text, settings.input_format)?;
self.check_read_with_settings(desired_response, settings)
}
pub fn check_read_with_settings(&mut self, desired_response: &str, settings: &CheckSettings) -> Result<(bool, String)> {
let mut response = String::new();
let compare = if settings.output_format == utils::TextFormat::Hex {
desired_response.to_uppercase()
} else {
desired_response.to_string()
};
loop {
match self.read() {
Ok(bytes) => {
let mut new_text = utils::radix_string(bytes, &settings.output_format)?;
if settings.ignore_case {
new_text = new_text.to_lowercase();
}
response.push_str(new_text.as_str());
if compare == response {
break;
}
if compare.starts_with(response.as_str()) == false {
break;
}
},
Err(e) if e.is_timeout() => {
if response.len() == 0 {
return Err(e);
}
break;
},
Err(e) => return Err(e)
}
}
Ok((compare == response, response))
}
}
pub struct CheckSettings {
pub ignore_case: bool,
pub input_format: utils::TextFormat,
pub output_format: utils::TextFormat
}
impl Default for CheckSettings {
fn default() -> CheckSettings {
CheckSettings {
ignore_case: false,
input_format: utils::TextFormat::Text,
output_format: utils::TextFormat::Text
}
}
}