diff --git a/src/async_io.rs b/src/async_io.rs index d70ce0f..bc6eef8 100644 --- a/src/async_io.rs +++ b/src/async_io.rs @@ -9,7 +9,7 @@ use alloc::{ }; use critical_section::Mutex; -use crate::at_commands::{ATCommand, SimpleATCommand, StubATCommand}; +use crate::at_commands::{ATCommand, ATParseError, ATResponseParser, SimpleATCommand}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum KeypadButton { @@ -117,7 +117,7 @@ unsafe impl Sync for ConstructedATCommand {} pub struct AsyncIO { at_command: Rc>>>>, handling_at_command: Rc>>, - at_response: Rc>>>, + at_response: Rc>>>>, pub keypad: Keypad, } @@ -141,19 +141,17 @@ pub struct ATPromise { } impl ATPromise { - pub fn poll(&self, io: &mut AsyncIO) -> Option> { + pub fn poll(&self, io: &mut AsyncIO) -> Option>> { match io.poll_at_response() { Some(response) => match response { - Some(response) => Some(Some(T::parse_response(response))), + Some(response) => Some(Some(T::parse_response(&mut ATResponseParser::from( + response, + )))), None => Some(None), }, None => Some(None), } } - - pub fn downgrade(self) -> ATPromise { - ATPromise { _data: PhantomData } - } } impl AsyncIO { @@ -181,7 +179,7 @@ impl AsyncIO { }) } - pub unsafe fn set_at_response(&self, response_str: String) { + pub unsafe fn set_at_response(&self, response_str: Vec) { critical_section::with(|cs| { *self.handling_at_command.borrow_ref_mut(cs) = false; let mut command = self.at_command.borrow_ref_mut(cs); @@ -191,7 +189,7 @@ impl AsyncIO { }) } - fn poll_at_response(&self) -> Option> { + fn poll_at_response(&self) -> Option>> { critical_section::with(|cs| { let command = self.at_command.borrow_ref(cs); let mut response = self.at_response.borrow_ref_mut(cs); diff --git a/src/at_commands.rs b/src/at_commands.rs index 101d724..c05cfdd 100644 --- a/src/at_commands.rs +++ b/src/at_commands.rs @@ -56,7 +56,7 @@ impl<'a, 'd> ATCommands<'a, 'd> { self.flush_rx(); } - pub fn raw_command(&mut self, command: String) -> String { + pub fn raw_command(&mut self, cmd: &T, command: String) -> Vec { self.uart.flush().unwrap(); self.flush_rx(); let command = command.clone() + "\r"; @@ -64,10 +64,15 @@ impl<'a, 'd> ATCommands<'a, 'd> { self.uart.flush().unwrap(); self.delay.delay_millis(500); log::info!("Wrote command {}", command); - self.read_response(command) + self.read_response(cmd, command) } - pub fn raw_two_part_command(&mut self, command: String, additional: String) -> String { + pub fn raw_two_part_command( + &mut self, + cmd: &T, + command: String, + additional: String, + ) -> Vec { self.uart.flush().unwrap(); self.flush_rx(); self.uart.write_str(&(command.clone() + "\r")).unwrap(); @@ -87,7 +92,7 @@ impl<'a, 'd> ATCommands<'a, 'd> { } self.uart.flush().unwrap(); - self.read_response(command) + self.read_response(cmd, command) } pub fn readline(&mut self) -> Option { @@ -99,18 +104,22 @@ impl<'a, 'd> ATCommands<'a, 'd> { } } - fn read_response(&mut self, start: String) -> String { + fn read_response(&mut self, cmd: &T, start: String) -> Vec { let mut response = None; while response.is_none() { self.flush_rx(); log::info!("{:?}", self.lines); - response = self.parse_response(&start); + response = self.parse_response(cmd, &start); } response.unwrap() } - fn parse_response(&mut self, start: &String) -> Option { + fn parse_response( + &mut self, + cmd: &T, + start: &String, + ) -> Option> { let start_idx = self .lines .iter() @@ -119,21 +128,35 @@ impl<'a, 'd> ATCommands<'a, 'd> { .map(|(i, _)| i); if let Some(start_idx) = start_idx { - let mut response = String::new(); + let mut response = Vec::new(); - for (i, line) in self.lines.iter().cloned().skip(start_idx).enumerate() { + for (i, line) in self.lines.clone().into_iter().skip(start_idx).enumerate() { if i == 0 { continue; } - if response.len() > 0 { - response += "\n"; - } - response += &line; - if RESPONSES.iter().any(|r| line.starts_with(r)) { - for _ in 0..=i { + response.push(line); + + let mut parser = ATResponseParser::from(response.clone()); + + match cmd.try_parse(&mut parser) { + Ok(_) => { + let mut output_lines = Vec::new(); + + // Remove first line, which is just the command echoed self.lines.remove(start_idx); + + for _ in 0..parser.lines { + output_lines.push(self.lines.remove(start_idx)); + } + return Some(output_lines); + } + Err(err) => { + log::info!("{:?}", err); + match err { + ATParseError::EOF => {} + ATParseError::InvalidResponse => panic!("Invalid response"), + } } - return Some(response); } } } @@ -166,33 +189,56 @@ impl<'a, 'd> ATCommands<'a, 'd> { } } +pub struct ATResponseParser { + text: Vec, + index: usize, + lines: usize, +} + +impl ATResponseParser { + pub fn from(text: Vec) -> ATResponseParser { + ATResponseParser { + text, + index: 0, + lines: 0, + } + } + + pub fn readline<'s>(&'s mut self) -> Option<&'s String> { + let result = self.text.get(self.index); + self.index += 1; + if let Some(_) = result { + self.lines += 1; + } + result + } +} + +#[derive(Clone, Copy, Debug)] +pub enum ATParseError { + EOF, + InvalidResponse, +} + pub trait ATCommand: Send + Sync { type Response: core::fmt::Debug; - fn execute(&self, at_commands: &mut ATCommands) -> String; - fn parse_response(text: String) -> Self::Response; + fn execute(&self, at_commands: &mut ATCommands) -> Vec; + fn parse_response(parser: &mut ATResponseParser) -> Result; } pub trait SimpleATCommand: Send + Sync { - fn execute(&self, at_commands: &mut ATCommands) -> String; + fn execute(&self, at_commands: &mut ATCommands) -> Vec; + fn try_parse(&self, parser: &mut ATResponseParser) -> Result<(), ATParseError>; } impl SimpleATCommand for T { - fn execute(&self, at_commands: &mut ATCommands) -> String { + fn execute(&self, at_commands: &mut ATCommands) -> Vec { self.execute(at_commands) } -} -#[derive(Debug, Clone)] -pub struct StubATCommand(()); -impl ATCommand for StubATCommand { - type Response = String; - - fn execute(&self, _: &mut ATCommands) -> String { - panic!("Should never be called") - } - - fn parse_response(text: String) -> Self::Response { - text + fn try_parse(&self, parser: &mut ATResponseParser) -> Result<(), ATParseError> { + let result = Self::parse_response(parser); + result.map(|_| ()) } } @@ -201,12 +247,17 @@ pub struct ATInformationCommand; impl ATCommand for ATInformationCommand { type Response = String; - fn execute(&self, at_commands: &mut ATCommands) -> String { - at_commands.raw_command("ATI".to_string()) + fn execute(&self, at_commands: &mut ATCommands) -> Vec { + at_commands.raw_command(self, "ATI".to_string()) } - fn parse_response(text: String) -> Self::Response { - text + fn parse_response(parser: &mut ATResponseParser) -> Result { + while let Some(line) = parser.readline() { + if line.starts_with("OK") { + return Ok("OK".to_owned()); + } + } + Err(ATParseError::EOF) } } @@ -215,12 +266,17 @@ pub struct EnterPinCommand(pub String); impl ATCommand for EnterPinCommand { type Response = String; - fn execute(&self, at_commands: &mut ATCommands) -> String { - at_commands.raw_command(format!("AT+CPIN={}", self.0)) + fn execute(&self, at_commands: &mut ATCommands) -> Vec { + at_commands.raw_command(self, format!("AT+CPIN={}", self.0)) } - fn parse_response(text: String) -> Self::Response { - text + fn parse_response(parser: &mut ATResponseParser) -> Result { + while let Some(line) = parser.readline() { + if line.starts_with("OK") { + return Ok("OK".to_owned()); + } + } + Err(ATParseError::EOF) } } @@ -229,12 +285,17 @@ pub struct CheckPinCommand; impl ATCommand for CheckPinCommand { type Response = String; - fn execute(&self, at_commands: &mut ATCommands) -> String { - at_commands.raw_command("AT+CPIN?".to_string()) + fn execute(&self, at_commands: &mut ATCommands) -> Vec { + at_commands.raw_command(self, "AT+CPIN?".to_string()) } - fn parse_response(text: String) -> Self::Response { - text + fn parse_response(parser: &mut ATResponseParser) -> Result { + while let Some(line) = parser.readline() { + if line.starts_with("OK") { + return Ok("OK".to_owned()); + } + } + Err(ATParseError::EOF) } } @@ -249,12 +310,17 @@ pub struct SelectSMSFormatCommand(pub SMSFormat); impl ATCommand for SelectSMSFormatCommand { type Response = String; - fn execute(&self, at_commands: &mut ATCommands) -> String { - at_commands.raw_command(format!("AT+CMGF={}", self.0 as u8)) + fn execute(&self, at_commands: &mut ATCommands) -> Vec { + at_commands.raw_command(self, format!("AT+CMGF={}", self.0 as u8)) } - fn parse_response(text: String) -> Self::Response { - text + fn parse_response(parser: &mut ATResponseParser) -> Result { + while let Some(line) = parser.readline() { + if line.starts_with("OK") { + return Ok("OK".to_owned()); + } + } + Err(ATParseError::EOF) } } @@ -263,12 +329,17 @@ pub struct CheckSMSFormatCommand; impl ATCommand for CheckSMSFormatCommand { type Response = String; - fn execute(&self, at_commands: &mut ATCommands) -> String { - at_commands.raw_command("AT+CMGF?".to_string()) + fn execute(&self, at_commands: &mut ATCommands) -> Vec { + at_commands.raw_command(self, "AT+CMGF?".to_string()) } - fn parse_response(text: String) -> Self::Response { - text + fn parse_response(parser: &mut ATResponseParser) -> Result { + while let Some(line) = parser.readline() { + if line.starts_with("OK") { + return Ok("OK".to_owned()); + } + } + Err(ATParseError::EOF) } } @@ -277,12 +348,17 @@ pub struct ListTECharacterSetsCommand; impl ATCommand for ListTECharacterSetsCommand { type Response = String; - fn execute(&self, at_commands: &mut ATCommands) -> String { - at_commands.raw_command("AT+CSCS=?".to_string()) + fn execute(&self, at_commands: &mut ATCommands) -> Vec { + at_commands.raw_command(self, "AT+CSCS=?".to_string()) } - fn parse_response(text: String) -> Self::Response { - text + fn parse_response(parser: &mut ATResponseParser) -> Result { + while let Some(line) = parser.readline() { + if line.starts_with("OK") { + return Ok("OK".to_owned()); + } + } + Err(ATParseError::EOF) } } @@ -310,12 +386,17 @@ pub struct SetTECharsetCommand(pub TECharset); impl ATCommand for SetTECharsetCommand { type Response = String; - fn execute(&self, at_commands: &mut ATCommands) -> String { - at_commands.raw_command(format!("AT+CSCS=\"{}\"", self.0.into_str())) + fn execute(&self, at_commands: &mut ATCommands) -> Vec { + at_commands.raw_command(self, format!("AT+CSCS=\"{}\"", self.0.into_str())) } - fn parse_response(text: String) -> Self::Response { - text + fn parse_response(parser: &mut ATResponseParser) -> Result { + while let Some(line) = parser.readline() { + if line.starts_with("OK") { + return Ok("OK".to_owned()); + } + } + Err(ATParseError::EOF) } } @@ -328,14 +409,20 @@ pub struct SendSMSCommand { impl ATCommand for SendSMSCommand { type Response = String; - fn execute(&self, at_commands: &mut ATCommands) -> String { + fn execute(&self, at_commands: &mut ATCommands) -> Vec { at_commands.raw_two_part_command( + self, format!("AT+CMGS=\"{}\"", self.destination), self.message.clone(), ) } - fn parse_response(text: String) -> Self::Response { - text + fn parse_response(parser: &mut ATResponseParser) -> Result { + while let Some(line) = parser.readline() { + if line.starts_with("OK") { + return Ok("OK".to_owned()); + } + } + Err(ATParseError::EOF) } }