Read messages
This commit is contained in:
parent
9c582a4de1
commit
4c0f284b62
@ -66,7 +66,6 @@ impl<'a, 'd> ATCommands<'a, 'd> {
|
||||
let command = command.clone() + "\r";
|
||||
self.uart.write_str(&command).unwrap();
|
||||
self.uart.flush().unwrap();
|
||||
self.delay.delay_millis(500);
|
||||
log::info!("Wrote command {}", command);
|
||||
self.read_response(cmd, command, timeout)
|
||||
}
|
||||
@ -82,7 +81,6 @@ impl<'a, 'd> ATCommands<'a, 'd> {
|
||||
self.flush_rx();
|
||||
self.uart.write_str(&(command.clone() + "\r")).unwrap();
|
||||
self.uart.flush().unwrap();
|
||||
self.delay.delay_millis(500);
|
||||
log::info!("Wrote command {}", command);
|
||||
self.flush_rx();
|
||||
|
||||
@ -185,7 +183,9 @@ impl<'a, 'd> ATCommands<'a, 'd> {
|
||||
self.uart.read_ready()
|
||||
} {
|
||||
let length = self.uart.read(&mut buffer).unwrap();
|
||||
self.buffer += str::from_utf8(&buffer[..length]).unwrap();
|
||||
for character in &buffer[..length] {
|
||||
self.buffer += str::from_utf8(&[character.clone()]).unwrap_or("?")
|
||||
}
|
||||
}
|
||||
|
||||
let lines = self
|
||||
@ -231,6 +231,13 @@ impl ATResponseParser {
|
||||
result.cloned()
|
||||
}
|
||||
|
||||
pub fn params(&mut self) -> Option<Params> {
|
||||
self.readline().map(|l| Params {
|
||||
raw_params: l.to_owned(),
|
||||
idx: 0,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn expect(&mut self, text: String) -> Result<(), ATError> {
|
||||
let line = if let Some(curr_line) = self.curr_line.take() {
|
||||
curr_line
|
||||
@ -246,6 +253,59 @@ impl ATResponseParser {
|
||||
Err(ATError::InvalidResponse)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peek(&self) -> Option<String> {
|
||||
if let Some(curr_line) = &self.curr_line {
|
||||
return Some(curr_line.clone());
|
||||
}
|
||||
if let Some(text) = self.text.get(self.index) {
|
||||
Some(text.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Params {
|
||||
raw_params: String,
|
||||
idx: u32,
|
||||
}
|
||||
|
||||
impl Params {
|
||||
pub fn read_raw(&mut self) -> Option<String> {
|
||||
if self.idx > 0 {
|
||||
self.raw_params = self.raw_params.strip_prefix(",").unwrap().to_owned()
|
||||
}
|
||||
|
||||
let returned;
|
||||
|
||||
if let Some(rest) = self.raw_params.strip_prefix("\"") {
|
||||
let mut parts = rest.split("\"");
|
||||
returned = parts.next().unwrap().to_owned();
|
||||
self.raw_params = parts.collect::<Vec<_>>().join("\"")
|
||||
} else {
|
||||
let mut parts = self.raw_params.split(",");
|
||||
returned = parts.next().unwrap().to_owned();
|
||||
self.raw_params = parts.collect::<Vec<_>>().join(",")
|
||||
}
|
||||
Some(returned)
|
||||
}
|
||||
|
||||
pub fn read_u32(&mut self) -> Option<u32> {
|
||||
if let Some(part) = self.read_raw() {
|
||||
u32::from_str_radix(&part, 10).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_string(&mut self) -> Option<String> {
|
||||
if let Some(part) = self.read_raw() {
|
||||
Some(part)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@ -651,3 +711,122 @@ impl ATCommand for SendSMSCommand {
|
||||
Err(ATError::EOF)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ListSMSMessagesResponse {
|
||||
Ok(Vec<SMSMessageListing>),
|
||||
Error(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SMSMessageListing {
|
||||
index: u32,
|
||||
stat: SMSMessageStat,
|
||||
from_addr: String,
|
||||
to_addr: String,
|
||||
timestamp: String,
|
||||
text: String,
|
||||
}
|
||||
|
||||
impl ATResponse for ListSMSMessagesResponse {
|
||||
fn is_error(&self) -> bool {
|
||||
match self {
|
||||
ListSMSMessagesResponse::Error(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SMSMessageStat {
|
||||
RecUnread,
|
||||
RecRead,
|
||||
StoUnsent,
|
||||
StoSent,
|
||||
All,
|
||||
}
|
||||
|
||||
impl SMSMessageStat {
|
||||
pub fn into_str(&self) -> String {
|
||||
match self {
|
||||
SMSMessageStat::RecUnread => "REC UNREAD",
|
||||
SMSMessageStat::RecRead => "REC READ",
|
||||
SMSMessageStat::StoUnsent => "STO UNSENT",
|
||||
SMSMessageStat::StoSent => "STO SENT",
|
||||
SMSMessageStat::All => "ALL",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
|
||||
pub fn from(text: &str) -> SMSMessageStat {
|
||||
match text {
|
||||
"REC UNREAD" => Self::RecUnread,
|
||||
"REC READ" => Self::RecRead,
|
||||
"STO UNSENT" => Self::StoUnsent,
|
||||
"STO SENT" => Self::StoSent,
|
||||
_ => Self::All,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ListSMSMessages {
|
||||
pub stat: SMSMessageStat,
|
||||
}
|
||||
|
||||
impl ATCommand for ListSMSMessages {
|
||||
type Response = ListSMSMessagesResponse;
|
||||
|
||||
fn execute(&self, at_commands: &mut ATCommands) -> Result<Vec<String>, ATError> {
|
||||
at_commands.raw_command(
|
||||
self,
|
||||
format!("AT+CMGL=\"{}\"", self.stat.into_str()),
|
||||
Duration::from_millis(5000),
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_response(parser: &mut ATResponseParser) -> Result<Self::Response, ATError> {
|
||||
let mut messages = Vec::new();
|
||||
while let Ok(_) = parser.expect("+CMGL: ".to_owned()) {
|
||||
let mut params = parser.params().unwrap();
|
||||
let idx = params.read_u32().unwrap();
|
||||
let stat = SMSMessageStat::from(¶ms.read_string().unwrap());
|
||||
let from_addr = params.read_string().unwrap();
|
||||
let to_addr = params.read_string().unwrap();
|
||||
let timestamp = params.read_string().unwrap();
|
||||
|
||||
let mut message = String::new();
|
||||
|
||||
while let Some(line) = parser.peek() {
|
||||
if line.starts_with("OK") || line.starts_with("+CMGL: ") {
|
||||
break;
|
||||
}
|
||||
message += &parser.readline().unwrap();
|
||||
}
|
||||
|
||||
messages.push(SMSMessageListing {
|
||||
index: idx,
|
||||
stat,
|
||||
from_addr,
|
||||
to_addr,
|
||||
timestamp,
|
||||
text: message,
|
||||
});
|
||||
}
|
||||
|
||||
log::info!("Messages so far: {:?}", messages);
|
||||
|
||||
while let Some(line) = parser.readline() {
|
||||
if line.starts_with("OK") {
|
||||
return Ok(ListSMSMessagesResponse::Ok(messages));
|
||||
}
|
||||
if line.starts_with("+CMS ERROR: ") {
|
||||
return Ok(ListSMSMessagesResponse::Error(
|
||||
line.strip_prefix("+CMS ERROR: ").unwrap().to_owned(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Err(ATError::EOF)
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,8 +12,8 @@ use crate::{
|
||||
async_io::{ATPromise, KeypadButton, NumberInput, TextInput},
|
||||
at_commands::{
|
||||
ATCommand, ATError, ATInformationCommand, CheckPinCommand, CheckPinResult, EnterPinCommand,
|
||||
EnterPinResult, SMSFormat, SelectSMSFormatCommand, SendSMSCommand, SendSMSResponse,
|
||||
SetTECharsetCommand, SimpleATResponse, TECharset,
|
||||
EnterPinResult, ListSMSMessages, SMSFormat, SMSMessageStat, SelectSMSFormatCommand,
|
||||
SendSMSCommand, SendSMSResponse, SetTECharsetCommand, SimpleATResponse, TECharset,
|
||||
},
|
||||
display::{Position, Rgb565},
|
||||
font::{HorizontalAlignment, VerticalAlignment},
|
||||
@ -337,7 +337,27 @@ impl State for MainMenuState {
|
||||
if let Some(option) = self.menu.poll(&mut data.io) {
|
||||
match option {
|
||||
MainMenuItem::SendSMS => return Some(Box::new(PhoneNumberState::default())),
|
||||
MainMenuItem::ReadSMS => {}
|
||||
MainMenuItem::ReadSMS => {
|
||||
return Some(Box::new(ATCommandState::with(
|
||||
"Loading messages".to_owned(),
|
||||
ListSMSMessages {
|
||||
stat: SMSMessageStat::All,
|
||||
},
|
||||
|resp| match resp {
|
||||
Ok(messages) => {
|
||||
log::info!("{:?}", messages);
|
||||
Box::new(TextState {
|
||||
text: format!("Messages read"),
|
||||
after: MainMenuState::default(),
|
||||
})
|
||||
}
|
||||
Err(err) => Box::new(TextState {
|
||||
text: format!("Error:\n{:?}", err),
|
||||
after: MainMenuState::default(),
|
||||
}),
|
||||
},
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
|
||||
Loading…
Reference in New Issue
Block a user