Implement incredibly primitive parser

This commit is contained in:
Sofia 2026-05-30 18:15:24 +03:00
parent 6cf3e1dbe5
commit e21002744a
2 changed files with 158 additions and 73 deletions

View File

@ -9,7 +9,7 @@ use alloc::{
}; };
use critical_section::Mutex; 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)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum KeypadButton { pub enum KeypadButton {
@ -117,7 +117,7 @@ unsafe impl Sync for ConstructedATCommand {}
pub struct AsyncIO { pub struct AsyncIO {
at_command: Rc<Mutex<RefCell<Option<Box<dyn SimpleATCommand>>>>>, at_command: Rc<Mutex<RefCell<Option<Box<dyn SimpleATCommand>>>>>,
handling_at_command: Rc<Mutex<RefCell<bool>>>, handling_at_command: Rc<Mutex<RefCell<bool>>>,
at_response: Rc<Mutex<RefCell<Option<String>>>>, at_response: Rc<Mutex<RefCell<Option<Vec<String>>>>>,
pub keypad: Keypad, pub keypad: Keypad,
} }
@ -141,19 +141,17 @@ pub struct ATPromise<T: ATCommand> {
} }
impl<T: ATCommand> ATPromise<T> { impl<T: ATCommand> ATPromise<T> {
pub fn poll(&self, io: &mut AsyncIO) -> Option<Option<T::Response>> { pub fn poll(&self, io: &mut AsyncIO) -> Option<Option<Result<T::Response, ATParseError>>> {
match io.poll_at_response() { match io.poll_at_response() {
Some(response) => match 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),
}, },
None => Some(None), None => Some(None),
} }
} }
pub fn downgrade(self) -> ATPromise<StubATCommand> {
ATPromise { _data: PhantomData }
}
} }
impl AsyncIO { 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<String>) {
critical_section::with(|cs| { critical_section::with(|cs| {
*self.handling_at_command.borrow_ref_mut(cs) = false; *self.handling_at_command.borrow_ref_mut(cs) = false;
let mut command = self.at_command.borrow_ref_mut(cs); let mut command = self.at_command.borrow_ref_mut(cs);
@ -191,7 +189,7 @@ impl AsyncIO {
}) })
} }
fn poll_at_response(&self) -> Option<Option<String>> { fn poll_at_response(&self) -> Option<Option<Vec<String>>> {
critical_section::with(|cs| { critical_section::with(|cs| {
let command = self.at_command.borrow_ref(cs); let command = self.at_command.borrow_ref(cs);
let mut response = self.at_response.borrow_ref_mut(cs); let mut response = self.at_response.borrow_ref_mut(cs);

View File

@ -56,7 +56,7 @@ impl<'a, 'd> ATCommands<'a, 'd> {
self.flush_rx(); self.flush_rx();
} }
pub fn raw_command(&mut self, command: String) -> String { pub fn raw_command<T: SimpleATCommand>(&mut self, cmd: &T, command: String) -> Vec<String> {
self.uart.flush().unwrap(); self.uart.flush().unwrap();
self.flush_rx(); self.flush_rx();
let command = command.clone() + "\r"; let command = command.clone() + "\r";
@ -64,10 +64,15 @@ impl<'a, 'd> ATCommands<'a, 'd> {
self.uart.flush().unwrap(); self.uart.flush().unwrap();
self.delay.delay_millis(500); self.delay.delay_millis(500);
log::info!("Wrote command {}", command); 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<T: SimpleATCommand>(
&mut self,
cmd: &T,
command: String,
additional: String,
) -> Vec<String> {
self.uart.flush().unwrap(); self.uart.flush().unwrap();
self.flush_rx(); self.flush_rx();
self.uart.write_str(&(command.clone() + "\r")).unwrap(); self.uart.write_str(&(command.clone() + "\r")).unwrap();
@ -87,7 +92,7 @@ impl<'a, 'd> ATCommands<'a, 'd> {
} }
self.uart.flush().unwrap(); self.uart.flush().unwrap();
self.read_response(command) self.read_response(cmd, command)
} }
pub fn readline(&mut self) -> Option<String> { pub fn readline(&mut self) -> Option<String> {
@ -99,18 +104,22 @@ impl<'a, 'd> ATCommands<'a, 'd> {
} }
} }
fn read_response(&mut self, start: String) -> String { fn read_response<T: SimpleATCommand>(&mut self, cmd: &T, start: String) -> Vec<String> {
let mut response = None; let mut response = None;
while response.is_none() { while response.is_none() {
self.flush_rx(); self.flush_rx();
log::info!("{:?}", self.lines); log::info!("{:?}", self.lines);
response = self.parse_response(&start); response = self.parse_response(cmd, &start);
} }
response.unwrap() response.unwrap()
} }
fn parse_response(&mut self, start: &String) -> Option<String> { fn parse_response<T: SimpleATCommand>(
&mut self,
cmd: &T,
start: &String,
) -> Option<Vec<String>> {
let start_idx = self let start_idx = self
.lines .lines
.iter() .iter()
@ -119,21 +128,35 @@ impl<'a, 'd> ATCommands<'a, 'd> {
.map(|(i, _)| i); .map(|(i, _)| i);
if let Some(start_idx) = start_idx { 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 { if i == 0 {
continue; continue;
} }
if response.len() > 0 { response.push(line);
response += "\n";
} let mut parser = ATResponseParser::from(response.clone());
response += &line;
if RESPONSES.iter().any(|r| line.starts_with(r)) { match cmd.try_parse(&mut parser) {
for _ in 0..=i { Ok(_) => {
let mut output_lines = Vec::new();
// Remove first line, which is just the command echoed
self.lines.remove(start_idx); 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<String>,
index: usize,
lines: usize,
}
impl ATResponseParser {
pub fn from(text: Vec<String>) -> 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 { pub trait ATCommand: Send + Sync {
type Response: core::fmt::Debug; type Response: core::fmt::Debug;
fn execute(&self, at_commands: &mut ATCommands) -> String; fn execute(&self, at_commands: &mut ATCommands) -> Vec<String>;
fn parse_response(text: String) -> Self::Response; fn parse_response(parser: &mut ATResponseParser) -> Result<Self::Response, ATParseError>;
} }
pub trait SimpleATCommand: Send + Sync { pub trait SimpleATCommand: Send + Sync {
fn execute(&self, at_commands: &mut ATCommands) -> String; fn execute(&self, at_commands: &mut ATCommands) -> Vec<String>;
fn try_parse(&self, parser: &mut ATResponseParser) -> Result<(), ATParseError>;
} }
impl<T: ATCommand> SimpleATCommand for T { impl<T: ATCommand> SimpleATCommand for T {
fn execute(&self, at_commands: &mut ATCommands) -> String { fn execute(&self, at_commands: &mut ATCommands) -> Vec<String> {
self.execute(at_commands) self.execute(at_commands)
} }
}
#[derive(Debug, Clone)] fn try_parse(&self, parser: &mut ATResponseParser) -> Result<(), ATParseError> {
pub struct StubATCommand(()); let result = Self::parse_response(parser);
impl ATCommand for StubATCommand { result.map(|_| ())
type Response = String;
fn execute(&self, _: &mut ATCommands) -> String {
panic!("Should never be called")
}
fn parse_response(text: String) -> Self::Response {
text
} }
} }
@ -201,12 +247,17 @@ pub struct ATInformationCommand;
impl ATCommand for ATInformationCommand { impl ATCommand for ATInformationCommand {
type Response = String; type Response = String;
fn execute(&self, at_commands: &mut ATCommands) -> String { fn execute(&self, at_commands: &mut ATCommands) -> Vec<String> {
at_commands.raw_command("ATI".to_string()) at_commands.raw_command(self, "ATI".to_string())
} }
fn parse_response(text: String) -> Self::Response { fn parse_response(parser: &mut ATResponseParser) -> Result<Self::Response, ATParseError> {
text 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 { impl ATCommand for EnterPinCommand {
type Response = String; type Response = String;
fn execute(&self, at_commands: &mut ATCommands) -> String { fn execute(&self, at_commands: &mut ATCommands) -> Vec<String> {
at_commands.raw_command(format!("AT+CPIN={}", self.0)) at_commands.raw_command(self, format!("AT+CPIN={}", self.0))
} }
fn parse_response(text: String) -> Self::Response { fn parse_response(parser: &mut ATResponseParser) -> Result<Self::Response, ATParseError> {
text 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 { impl ATCommand for CheckPinCommand {
type Response = String; type Response = String;
fn execute(&self, at_commands: &mut ATCommands) -> String { fn execute(&self, at_commands: &mut ATCommands) -> Vec<String> {
at_commands.raw_command("AT+CPIN?".to_string()) at_commands.raw_command(self, "AT+CPIN?".to_string())
} }
fn parse_response(text: String) -> Self::Response { fn parse_response(parser: &mut ATResponseParser) -> Result<Self::Response, ATParseError> {
text 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 { impl ATCommand for SelectSMSFormatCommand {
type Response = String; type Response = String;
fn execute(&self, at_commands: &mut ATCommands) -> String { fn execute(&self, at_commands: &mut ATCommands) -> Vec<String> {
at_commands.raw_command(format!("AT+CMGF={}", self.0 as u8)) at_commands.raw_command(self, format!("AT+CMGF={}", self.0 as u8))
} }
fn parse_response(text: String) -> Self::Response { fn parse_response(parser: &mut ATResponseParser) -> Result<Self::Response, ATParseError> {
text 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 { impl ATCommand for CheckSMSFormatCommand {
type Response = String; type Response = String;
fn execute(&self, at_commands: &mut ATCommands) -> String { fn execute(&self, at_commands: &mut ATCommands) -> Vec<String> {
at_commands.raw_command("AT+CMGF?".to_string()) at_commands.raw_command(self, "AT+CMGF?".to_string())
} }
fn parse_response(text: String) -> Self::Response { fn parse_response(parser: &mut ATResponseParser) -> Result<Self::Response, ATParseError> {
text 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 { impl ATCommand for ListTECharacterSetsCommand {
type Response = String; type Response = String;
fn execute(&self, at_commands: &mut ATCommands) -> String { fn execute(&self, at_commands: &mut ATCommands) -> Vec<String> {
at_commands.raw_command("AT+CSCS=?".to_string()) at_commands.raw_command(self, "AT+CSCS=?".to_string())
} }
fn parse_response(text: String) -> Self::Response { fn parse_response(parser: &mut ATResponseParser) -> Result<Self::Response, ATParseError> {
text 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 { impl ATCommand for SetTECharsetCommand {
type Response = String; type Response = String;
fn execute(&self, at_commands: &mut ATCommands) -> String { fn execute(&self, at_commands: &mut ATCommands) -> Vec<String> {
at_commands.raw_command(format!("AT+CSCS=\"{}\"", self.0.into_str())) at_commands.raw_command(self, format!("AT+CSCS=\"{}\"", self.0.into_str()))
} }
fn parse_response(text: String) -> Self::Response { fn parse_response(parser: &mut ATResponseParser) -> Result<Self::Response, ATParseError> {
text 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 { impl ATCommand for SendSMSCommand {
type Response = String; type Response = String;
fn execute(&self, at_commands: &mut ATCommands) -> String { fn execute(&self, at_commands: &mut ATCommands) -> Vec<String> {
at_commands.raw_two_part_command( at_commands.raw_two_part_command(
self,
format!("AT+CMGS=\"{}\"", self.destination), format!("AT+CMGS=\"{}\"", self.destination),
self.message.clone(), self.message.clone(),
) )
} }
fn parse_response(text: String) -> Self::Response { fn parse_response(parser: &mut ATResponseParser) -> Result<Self::Response, ATParseError> {
text while let Some(line) = parser.readline() {
if line.starts_with("OK") {
return Ok("OK".to_owned());
}
}
Err(ATParseError::EOF)
} }
} }