make serial read/write non-blocking

This commit is contained in:
Vladan Popovic 2022-11-29 15:19:42 +01:00
parent b6e7e64e72
commit 018af71262
2 changed files with 96 additions and 122 deletions

View file

@ -7,7 +7,7 @@ use std::{
error::Error,
io::{Read, Write},
thread,
time::{Duration, Instant},
time::Duration,
sync::mpsc::Receiver,
};
@ -90,31 +90,52 @@ impl<UART: serial::Uart> Modem<UART> {
/// None, then the first line is returned. If a timeout is reached. The timeout is provided on
/// input via the `timeout` argument. The first argument `contains` is checked against every
/// line in the response.
fn read_response(&mut self, contains: Option<String>, timeout: Duration) -> Result<String> {
fn command_read_response(&mut self) -> Result<String> {
let mut response = String::new();
let start = Instant::now();
let match_text: String = contains.unwrap_or("\n".to_string());
loop {
let timeout = timeout.saturating_sub(start.elapsed());
let line = self.serial.read_line(timeout).map_err(|_| ModemError::ReadError)?;
print!("Read {} bytes from serial: {}", line.len(), line);
response.push_str(&line);
if line.contains("ERROR") || line.contains(&match_text) {
println!("Found match {} for line {} ; exiting response reader now ...", match_text, line);
println!("-----------------------------------------------------------");
break Ok(response.to_string())
let mut buf = vec![0; 1024];
let num_bytes = self.serial
.read(buf.as_mut_slice())
.map_err(|_| ModemError::ReadError)?;
response.push_str(std::str::from_utf8(&buf[0..num_bytes]).map_err(|_| ModemError::ReadError)?);
if num_bytes < buf.len() {
break
}
}
print!("Read {} bytes from serial: {}", response.len(), response);
Ok(response)
}
fn send_command(&mut self, cmd: Command) -> Result<String> {
println!("-----------------------------------------------------------");
println!("Sending {} ...", cmd.text);
println!("Sending to TX ({}) ...", cmd.text);
let _ = self.serial
.send_bytes(cmd.text.as_bytes(), Some('\r' as u8))
.map_err(|_| ModemError::SendDataError(format!("Error in send_command({:?})", cmd)))?;
self.read_response(cmd.contains, cmd.timeout)
.write_bytes(cmd.text.as_bytes())
.map_err(|_| ModemError::SendDataError(format!("Error in send_command({})", cmd.text)))?;
let _ = self.serial
.write(&['\r' as u8])
.map_err(|_| ModemError::SendDataError(format!("Error in send_command({})", cmd.text)))?;
self.command_read_response()
}
fn handle_prompt(&mut self) -> Result<()> {
let mut prompt_buf = vec![0; 3];
let prompt_len = self.serial.read(&mut prompt_buf).map_err(|_| ModemError::ReadError)?;
let prompt = std::str::from_utf8(prompt_buf.as_slice()).unwrap_or("");
if prompt_len != 3 && prompt != "\r\n>" {
let msg = format!("Prompt error, expected \\r\\n>, got {:?}", prompt);
Err(ModemError::SendDataError(msg))
} else {
Ok(())
}
}
fn tcp_manual_send_data(&mut self, buf: &[u8]) -> Result<String> {
@ -122,18 +143,15 @@ impl<UART: serial::Uart> Modem<UART> {
.write("AT+CIPSEND\r".as_bytes())
.map_err(|_| ModemError::SendDataError("Error in tcp_manual_send_data ... AT_CIPSEND\\r".to_string()))?;
let send_prompt: String = self.serial.rx.reset(Duration::from_millis(3000))
.map(char::from)
.take_while(|c| *c != '>').collect();
let _ = self.handle_prompt()?;
if send_prompt != "\r\n" {
let msg = format!("Prompt error, expected \\r\\n, got {:?}", send_prompt.as_bytes());
return Err(ModemError::SendDataError(msg));
}
self.serial
.send_bytes(buf, Some(26_u8)) // 26_u8 = Ctrl+z - to end sending data
.write_bytes(buf)
.map_err(|err| ModemError::SendDataError(format!("{:?}", err)))?;
self.read_response(Some("SEND OK".to_string()), Duration::from_millis(3000))
self.serial
.write(&[26_u8]) // 26_u8 = Ctrl+z - to end sending data
.map_err(|err| ModemError::SendDataError(format!("{:?}", err)))?;
self.command_read_response()
}
pub fn gprs_status(&mut self) -> Result<String> {
@ -280,7 +298,8 @@ impl<UART: serial::Uart> Modem<UART> {
let _ = self.send_command(Command::http_set_content("application/json"));
let _ = self.send_command(Command::http_set_ssl(true));
let _ = self.send_command(Command::http_post_len(content.len(), 100000));
let _ = self.serial.send_bytes(content, Some(26));
let _ = self.serial.write_bytes(content);
let _ = self.serial.write(&[26_u8]);
let _ = self.send_command(Command::http_post());
self.send_command(Command::http_read_response())
}
@ -322,20 +341,15 @@ impl<UART: serial::Uart> Modem<UART> {
fn file_write(&mut self, buf: &[u8], path: &str, append: bool, input_time_sec: usize) -> Result<()> {
let cmd = Command::fs_file_write(path, append, buf.len(), input_time_sec);
let _ = self.serial
.send_bytes(cmd.text.as_bytes(), Some('\r' as u8))
.write(cmd.text.as_bytes())
.map_err(|err| ModemError::SendDataError(format!("File write error ({:?})", err)))?;
let send_prompt: String = self.serial.rx.reset(Duration::from_millis(3000))
.map(char::from)
.take_while(|c| *c != '>').collect();
if send_prompt == "" {
return Err(ModemError::SendDataError("Prompt empty, expected: \\r\\n".to_string()));
}
let _ = self.handle_prompt()?;
self.serial
.send_bytes(buf, None)
.write(buf)
.map_err(|err| ModemError::SendDataError(format!("Error sending bytes via serial ({:?})", err)))?;
let _ = self.read_response(Some("OK".to_string()), Duration::from_millis(3000));
let _ = self.command_read_response();
Ok(())
}