Reimplement AT init state as async
This commit is contained in:
parent
5475bb6cf9
commit
15bffd04a8
89
src/async_io.rs
Normal file
89
src/async_io.rs
Normal file
@ -0,0 +1,89 @@
|
||||
use core::cell::RefCell;
|
||||
|
||||
use alloc::{rc::Rc, string::String};
|
||||
use critical_section::Mutex;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ATCommand {
|
||||
/// ATI
|
||||
ATInformation,
|
||||
/// AT+CPIN=num
|
||||
EnterPin(String),
|
||||
/// AT+CPIN?
|
||||
CheckPin,
|
||||
/// AT+CMGF=num
|
||||
SelectSMSFormat(SMSFormat),
|
||||
/// AT+CMGF?
|
||||
CheckSMSFormat,
|
||||
/// AT+CSCS=?
|
||||
ListTECharacterSets,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum SMSFormat {
|
||||
PDUMode = 0,
|
||||
TextMode = 1,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AsyncIO {
|
||||
at_command: Rc<Mutex<RefCell<Option<ATCommand>>>>,
|
||||
at_response: Rc<Mutex<RefCell<Option<String>>>>,
|
||||
}
|
||||
|
||||
impl Default for AsyncIO {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
at_command: Rc::new(Mutex::new(RefCell::new(None))),
|
||||
at_response: Rc::new(Mutex::new(RefCell::new(None))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for AsyncIO {}
|
||||
unsafe impl Sync for AsyncIO {}
|
||||
|
||||
impl AsyncIO {
|
||||
pub fn send_at_command(&self, command: ATCommand) -> Result<(), ()> {
|
||||
critical_section::with(|cs| {
|
||||
let mut borrow = self.at_command.borrow_ref_mut(cs);
|
||||
if borrow.is_some() {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
*borrow = Some(command);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub unsafe fn check_at_command(&self) -> Option<ATCommand> {
|
||||
critical_section::with(|cs| {
|
||||
let borrow = self.at_command.borrow_ref(cs);
|
||||
borrow.clone()
|
||||
})
|
||||
}
|
||||
|
||||
pub unsafe fn set_at_response(&self, response_str: String) {
|
||||
critical_section::with(|cs| {
|
||||
let mut command = self.at_command.borrow_ref_mut(cs);
|
||||
let mut response = self.at_response.borrow_ref_mut(cs);
|
||||
command.take();
|
||||
*response = Some(response_str);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn poll_at_response(&self) -> Option<Option<String>> {
|
||||
critical_section::with(|cs| {
|
||||
let command = self.at_command.borrow_ref(cs);
|
||||
let mut response = self.at_response.borrow_ref_mut(cs);
|
||||
if command.is_some() {
|
||||
return Some(None);
|
||||
}
|
||||
if let Some(resp) = response.take() {
|
||||
return Some(Some(resp));
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
73
src/main.rs
73
src/main.rs
@ -12,11 +12,17 @@ use core::{
|
||||
mem::MaybeUninit,
|
||||
};
|
||||
|
||||
use alloc::{borrow::ToOwned, boxed::Box, string::String, sync::Arc, vec::Vec};
|
||||
use critical_section::{CriticalSection, Mutex};
|
||||
use embassy_executor::Spawner;
|
||||
use alloc::{
|
||||
borrow::ToOwned,
|
||||
boxed::Box,
|
||||
format,
|
||||
string::{String, ToString},
|
||||
sync::Arc,
|
||||
vec::Vec,
|
||||
};
|
||||
use critical_section::Mutex;
|
||||
use esp_hal::{
|
||||
clock::{ClockConfig, CpuClock},
|
||||
clock::CpuClock,
|
||||
delay::Delay,
|
||||
gpio::{InputConfig, Level, Output, OutputConfig},
|
||||
interrupt::software::SoftwareInterruptControl,
|
||||
@ -31,6 +37,7 @@ use esp_hal::{
|
||||
use esp_backtrace as _;
|
||||
|
||||
use crate::{
|
||||
async_io::AsyncIO,
|
||||
at_commands::ATCommands,
|
||||
display::{Display, SetAddressMode},
|
||||
state::StateManager,
|
||||
@ -39,6 +46,7 @@ use crate::{
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod async_io;
|
||||
mod at_commands;
|
||||
mod display;
|
||||
mod font;
|
||||
@ -127,15 +135,19 @@ fn main() -> ! {
|
||||
.with_rx(peripherals.GPIO16)
|
||||
.with_tx(peripherals.GPIO17);
|
||||
|
||||
let at_commands = ATCommands {
|
||||
let mut at_commands = ATCommands {
|
||||
rst: sim_rst,
|
||||
pwr_key: sim_pwr_key,
|
||||
uart,
|
||||
delay: Delay::new(),
|
||||
};
|
||||
|
||||
at_commands.init();
|
||||
|
||||
let async_io = AsyncIO::default();
|
||||
|
||||
let mut state_mgr = StateManager {
|
||||
data: state::StateData::from(display, at_commands),
|
||||
data: state::StateData::from(display, async_io.clone()),
|
||||
curr_state: Box::new(InitATState::default()),
|
||||
};
|
||||
|
||||
@ -157,10 +169,8 @@ fn main() -> ! {
|
||||
// let input_6 = Input::new(peripherals.GPIO26, pull_up_cfg);
|
||||
// let input_7 = Input::new(peripherals.GPIO27, pull_up_cfg);
|
||||
|
||||
let messages = Arc::new(Mutex::new(RefCell::new(Vec::<String>::new())));
|
||||
|
||||
static mut THREAD_2_STACK: Stack<1024> = esp_hal::system::Stack {
|
||||
mem: MaybeUninit::new([0u8; 1024]),
|
||||
static mut THREAD_2_STACK: Stack<{ 30 * 1024 }> = esp_hal::system::Stack {
|
||||
mem: MaybeUninit::new([0u8; 30 * 1024]),
|
||||
};
|
||||
|
||||
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
||||
@ -174,35 +184,40 @@ fn main() -> ! {
|
||||
&mut THREAD_2_STACK
|
||||
},
|
||||
{
|
||||
let messages = messages.clone();
|
||||
|| thread_2_main(messages)
|
||||
let io = async_io.clone();
|
||||
|| thread_2_main(io, at_commands)
|
||||
},
|
||||
);
|
||||
|
||||
let mut test_delay = Delay::new();
|
||||
loop {
|
||||
critical_section::with(|cs| {
|
||||
let mut borrowed = messages.borrow(cs).borrow_mut();
|
||||
for message in borrowed.iter() {
|
||||
log::info!("Received: {}", message);
|
||||
}
|
||||
borrowed.clear();
|
||||
})
|
||||
// state_mgr.update();
|
||||
// state_mgr.draw();
|
||||
state_mgr.update();
|
||||
state_mgr.draw();
|
||||
}
|
||||
|
||||
// for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v1.1.0/examples
|
||||
}
|
||||
|
||||
fn thread_2_main(messages: Arc<Mutex<RefCell<Vec<String>>>>) {
|
||||
let delay = Delay::new();
|
||||
fn thread_2_main(async_io: AsyncIO, mut at_commands: ATCommands<'static, 'static>) {
|
||||
loop {
|
||||
delay.delay_millis(1000);
|
||||
log::info!("Sent message");
|
||||
critical_section::with(|cs| {
|
||||
let mut borrowed = messages.borrow(cs).borrow_mut();
|
||||
borrowed.push("Message!".to_owned());
|
||||
})
|
||||
if let Some(command) = unsafe { async_io.check_at_command() } {
|
||||
let response = match command {
|
||||
async_io::ATCommand::ATInformation => at_commands.raw_command("ATI".to_string()),
|
||||
async_io::ATCommand::EnterPin(pin) => {
|
||||
at_commands.raw_command(format!("AT+CPIN={}", pin))
|
||||
}
|
||||
async_io::ATCommand::CheckPin => at_commands.raw_command("AT+CPIN?".to_string()),
|
||||
async_io::ATCommand::SelectSMSFormat(smsformat) => {
|
||||
at_commands.raw_command(format!("AT+CMGF={}", smsformat as u8))
|
||||
}
|
||||
async_io::ATCommand::CheckSMSFormat => {
|
||||
at_commands.raw_command("AT+CMGF?".to_string())
|
||||
}
|
||||
async_io::ATCommand::ListTECharacterSets => {
|
||||
at_commands.raw_command("AT+CSCS=?".to_string())
|
||||
}
|
||||
};
|
||||
unsafe { async_io.set_at_response(response) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
src/state.rs
10
src/state.rs
@ -2,6 +2,7 @@ use alloc::{boxed::Box, string::String, vec::Vec};
|
||||
use esp_hal::{Blocking, delay::Delay};
|
||||
|
||||
use crate::{
|
||||
async_io::AsyncIO,
|
||||
at_commands::ATCommands,
|
||||
display::{Color, Display, Position, Rgb565},
|
||||
font::{FontRenderer, HorizontalAlignment, VerticalAlignment},
|
||||
@ -34,8 +35,8 @@ pub enum DrawCommands {
|
||||
|
||||
pub struct StateData<'a> {
|
||||
display: Display<'a, Blocking, Delay>,
|
||||
pub at_commands: ATCommands<'a, 'a>,
|
||||
font_renderer: FontRenderer<'a>,
|
||||
pub io: AsyncIO,
|
||||
pub delay: Delay,
|
||||
|
||||
prev_commands: Vec<DrawCommands>,
|
||||
@ -43,13 +44,10 @@ pub struct StateData<'a> {
|
||||
}
|
||||
|
||||
impl<'a> StateData<'a> {
|
||||
pub fn from(
|
||||
display: Display<'a, Blocking, Delay>,
|
||||
at_commands: ATCommands<'a, 'a>,
|
||||
) -> StateData<'a> {
|
||||
pub fn from(display: Display<'a, Blocking, Delay>, io: AsyncIO) -> StateData<'a> {
|
||||
StateData {
|
||||
display,
|
||||
at_commands,
|
||||
io,
|
||||
font_renderer: FontRenderer::create(30),
|
||||
delay: Delay::new(),
|
||||
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
use alloc::{borrow::ToOwned, boxed::Box, string::String};
|
||||
use alloc::{
|
||||
borrow::ToOwned,
|
||||
boxed::Box,
|
||||
string::{String, ToString},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
async_io::{ATCommand, SMSFormat},
|
||||
display::{Position, Rgb565},
|
||||
state::{State, StateData, TextSettings},
|
||||
};
|
||||
@ -14,37 +19,45 @@ impl Default for InitATState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
inner_state: 0,
|
||||
response: "Initializing AT..".to_owned(),
|
||||
response: "Initializing AT..".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl State for InitATState {
|
||||
fn update(&mut self, data: &mut StateData) -> Option<Box<dyn State>> {
|
||||
if let Some(response) = data.io.poll_at_response() {
|
||||
match response {
|
||||
Some(response) => self.response = response,
|
||||
None => {}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
let res: Option<Box<dyn State>> = match self.inner_state {
|
||||
0 => {
|
||||
data.at_commands.init();
|
||||
self.response = data.at_commands.raw_command("ATI".to_owned());
|
||||
data.io.send_at_command(ATCommand::ATInformation).unwrap();
|
||||
None
|
||||
}
|
||||
1 => {
|
||||
self.response = data.at_commands.raw_command("AT+CMGF?".to_owned());
|
||||
data.io
|
||||
.send_at_command(ATCommand::EnterPin("1234".to_owned()))
|
||||
.unwrap();
|
||||
None
|
||||
}
|
||||
2 => {
|
||||
self.response = data.at_commands.raw_command("AT+CPIN=1234".to_owned());
|
||||
data.io.send_at_command(ATCommand::CheckPin).unwrap();
|
||||
None
|
||||
}
|
||||
3 => {
|
||||
self.response = data.at_commands.raw_command("AT+CPIN?".to_owned());
|
||||
data.io
|
||||
.send_at_command(ATCommand::ListTECharacterSets)
|
||||
.unwrap();
|
||||
None
|
||||
}
|
||||
4 => {
|
||||
self.response = data.at_commands.raw_command("AT+CMGF=1".to_owned());
|
||||
None
|
||||
}
|
||||
5 => {
|
||||
self.response = data.at_commands.raw_command("AT+CSCS=?".to_owned());
|
||||
data.io
|
||||
.send_at_command(ATCommand::SelectSMSFormat(SMSFormat::TextMode))
|
||||
.unwrap();
|
||||
None
|
||||
}
|
||||
_ => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user