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";
|
let command = command.clone() + "\r";
|
||||||
self.uart.write_str(&command).unwrap();
|
self.uart.write_str(&command).unwrap();
|
||||||
self.uart.flush().unwrap();
|
self.uart.flush().unwrap();
|
||||||
self.delay.delay_millis(500);
|
|
||||||
log::info!("Wrote command {}", command);
|
log::info!("Wrote command {}", command);
|
||||||
self.read_response(cmd, command, timeout)
|
self.read_response(cmd, command, timeout)
|
||||||
}
|
}
|
||||||
@ -82,7 +81,6 @@ impl<'a, 'd> ATCommands<'a, 'd> {
|
|||||||
self.flush_rx();
|
self.flush_rx();
|
||||||
self.uart.write_str(&(command.clone() + "\r")).unwrap();
|
self.uart.write_str(&(command.clone() + "\r")).unwrap();
|
||||||
self.uart.flush().unwrap();
|
self.uart.flush().unwrap();
|
||||||
self.delay.delay_millis(500);
|
|
||||||
log::info!("Wrote command {}", command);
|
log::info!("Wrote command {}", command);
|
||||||
self.flush_rx();
|
self.flush_rx();
|
||||||
|
|
||||||
@ -185,7 +183,9 @@ impl<'a, 'd> ATCommands<'a, 'd> {
|
|||||||
self.uart.read_ready()
|
self.uart.read_ready()
|
||||||
} {
|
} {
|
||||||
let length = self.uart.read(&mut buffer).unwrap();
|
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
|
let lines = self
|
||||||
@ -231,6 +231,13 @@ impl ATResponseParser {
|
|||||||
result.cloned()
|
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> {
|
pub fn expect(&mut self, text: String) -> Result<(), ATError> {
|
||||||
let line = if let Some(curr_line) = self.curr_line.take() {
|
let line = if let Some(curr_line) = self.curr_line.take() {
|
||||||
curr_line
|
curr_line
|
||||||
@ -246,6 +253,59 @@ impl ATResponseParser {
|
|||||||
Err(ATError::InvalidResponse)
|
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)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
@ -651,3 +711,122 @@ impl ATCommand for SendSMSCommand {
|
|||||||
Err(ATError::EOF)
|
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},
|
async_io::{ATPromise, KeypadButton, NumberInput, TextInput},
|
||||||
at_commands::{
|
at_commands::{
|
||||||
ATCommand, ATError, ATInformationCommand, CheckPinCommand, CheckPinResult, EnterPinCommand,
|
ATCommand, ATError, ATInformationCommand, CheckPinCommand, CheckPinResult, EnterPinCommand,
|
||||||
EnterPinResult, SMSFormat, SelectSMSFormatCommand, SendSMSCommand, SendSMSResponse,
|
EnterPinResult, ListSMSMessages, SMSFormat, SMSMessageStat, SelectSMSFormatCommand,
|
||||||
SetTECharsetCommand, SimpleATResponse, TECharset,
|
SendSMSCommand, SendSMSResponse, SetTECharsetCommand, SimpleATResponse, TECharset,
|
||||||
},
|
},
|
||||||
display::{Position, Rgb565},
|
display::{Position, Rgb565},
|
||||||
font::{HorizontalAlignment, VerticalAlignment},
|
font::{HorizontalAlignment, VerticalAlignment},
|
||||||
@ -337,7 +337,27 @@ impl State for MainMenuState {
|
|||||||
if let Some(option) = self.menu.poll(&mut data.io) {
|
if let Some(option) = self.menu.poll(&mut data.io) {
|
||||||
match option {
|
match option {
|
||||||
MainMenuItem::SendSMS => return Some(Box::new(PhoneNumberState::default())),
|
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
|
None
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user