Implement incredibly primitive parser
This commit is contained in:
parent
6cf3e1dbe5
commit
e21002744a
@ -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<Mutex<RefCell<Option<Box<dyn SimpleATCommand>>>>>,
|
||||
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,
|
||||
}
|
||||
|
||||
@ -141,19 +141,17 @@ pub struct ATPromise<T: ATCommand> {
|
||||
}
|
||||
|
||||
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() {
|
||||
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<StubATCommand> {
|
||||
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<String>) {
|
||||
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<Option<String>> {
|
||||
fn poll_at_response(&self) -> Option<Option<Vec<String>>> {
|
||||
critical_section::with(|cs| {
|
||||
let command = self.at_command.borrow_ref(cs);
|
||||
let mut response = self.at_response.borrow_ref_mut(cs);
|
||||
|
||||
@ -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<T: SimpleATCommand>(&mut self, cmd: &T, command: String) -> Vec<String> {
|
||||
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<T: SimpleATCommand>(
|
||||
&mut self,
|
||||
cmd: &T,
|
||||
command: String,
|
||||
additional: String,
|
||||
) -> Vec<String> {
|
||||
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<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;
|
||||
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<String> {
|
||||
fn parse_response<T: SimpleATCommand>(
|
||||
&mut self,
|
||||
cmd: &T,
|
||||
start: &String,
|
||||
) -> Option<Vec<String>> {
|
||||
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<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 {
|
||||
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<String>;
|
||||
fn parse_response(parser: &mut ATResponseParser) -> Result<Self::Response, ATParseError>;
|
||||
}
|
||||
|
||||
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 {
|
||||
fn execute(&self, at_commands: &mut ATCommands) -> String {
|
||||
fn execute(&self, at_commands: &mut ATCommands) -> Vec<String> {
|
||||
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<String> {
|
||||
at_commands.raw_command(self, "ATI".to_string())
|
||||
}
|
||||
|
||||
fn parse_response(text: String) -> Self::Response {
|
||||
text
|
||||
fn parse_response(parser: &mut ATResponseParser) -> Result<Self::Response, ATParseError> {
|
||||
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<String> {
|
||||
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<Self::Response, ATParseError> {
|
||||
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<String> {
|
||||
at_commands.raw_command(self, "AT+CPIN?".to_string())
|
||||
}
|
||||
|
||||
fn parse_response(text: String) -> Self::Response {
|
||||
text
|
||||
fn parse_response(parser: &mut ATResponseParser) -> Result<Self::Response, ATParseError> {
|
||||
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<String> {
|
||||
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<Self::Response, ATParseError> {
|
||||
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<String> {
|
||||
at_commands.raw_command(self, "AT+CMGF?".to_string())
|
||||
}
|
||||
|
||||
fn parse_response(text: String) -> Self::Response {
|
||||
text
|
||||
fn parse_response(parser: &mut ATResponseParser) -> Result<Self::Response, ATParseError> {
|
||||
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<String> {
|
||||
at_commands.raw_command(self, "AT+CSCS=?".to_string())
|
||||
}
|
||||
|
||||
fn parse_response(text: String) -> Self::Response {
|
||||
text
|
||||
fn parse_response(parser: &mut ATResponseParser) -> Result<Self::Response, ATParseError> {
|
||||
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<String> {
|
||||
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<Self::Response, ATParseError> {
|
||||
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<String> {
|
||||
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<Self::Response, ATParseError> {
|
||||
while let Some(line) = parser.readline() {
|
||||
if line.starts_with("OK") {
|
||||
return Ok("OK".to_owned());
|
||||
}
|
||||
}
|
||||
Err(ATParseError::EOF)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user