Implement incredibly primitive parser
This commit is contained in:
parent
6cf3e1dbe5
commit
e21002744a
@ -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);
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user