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,
|
mem::MaybeUninit,
|
||||||
};
|
};
|
||||||
|
|
||||||
use alloc::{borrow::ToOwned, boxed::Box, string::String, sync::Arc, vec::Vec};
|
use alloc::{
|
||||||
use critical_section::{CriticalSection, Mutex};
|
borrow::ToOwned,
|
||||||
use embassy_executor::Spawner;
|
boxed::Box,
|
||||||
|
format,
|
||||||
|
string::{String, ToString},
|
||||||
|
sync::Arc,
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
use critical_section::Mutex;
|
||||||
use esp_hal::{
|
use esp_hal::{
|
||||||
clock::{ClockConfig, CpuClock},
|
clock::CpuClock,
|
||||||
delay::Delay,
|
delay::Delay,
|
||||||
gpio::{InputConfig, Level, Output, OutputConfig},
|
gpio::{InputConfig, Level, Output, OutputConfig},
|
||||||
interrupt::software::SoftwareInterruptControl,
|
interrupt::software::SoftwareInterruptControl,
|
||||||
@ -31,6 +37,7 @@ use esp_hal::{
|
|||||||
use esp_backtrace as _;
|
use esp_backtrace as _;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
async_io::AsyncIO,
|
||||||
at_commands::ATCommands,
|
at_commands::ATCommands,
|
||||||
display::{Display, SetAddressMode},
|
display::{Display, SetAddressMode},
|
||||||
state::StateManager,
|
state::StateManager,
|
||||||
@ -39,6 +46,7 @@ use crate::{
|
|||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
|
mod async_io;
|
||||||
mod at_commands;
|
mod at_commands;
|
||||||
mod display;
|
mod display;
|
||||||
mod font;
|
mod font;
|
||||||
@ -127,15 +135,19 @@ fn main() -> ! {
|
|||||||
.with_rx(peripherals.GPIO16)
|
.with_rx(peripherals.GPIO16)
|
||||||
.with_tx(peripherals.GPIO17);
|
.with_tx(peripherals.GPIO17);
|
||||||
|
|
||||||
let at_commands = ATCommands {
|
let mut at_commands = ATCommands {
|
||||||
rst: sim_rst,
|
rst: sim_rst,
|
||||||
pwr_key: sim_pwr_key,
|
pwr_key: sim_pwr_key,
|
||||||
uart,
|
uart,
|
||||||
delay: Delay::new(),
|
delay: Delay::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
at_commands.init();
|
||||||
|
|
||||||
|
let async_io = AsyncIO::default();
|
||||||
|
|
||||||
let mut state_mgr = StateManager {
|
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()),
|
curr_state: Box::new(InitATState::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -157,10 +169,8 @@ fn main() -> ! {
|
|||||||
// let input_6 = Input::new(peripherals.GPIO26, pull_up_cfg);
|
// let input_6 = Input::new(peripherals.GPIO26, pull_up_cfg);
|
||||||
// let input_7 = Input::new(peripherals.GPIO27, 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<{ 30 * 1024 }> = esp_hal::system::Stack {
|
||||||
|
mem: MaybeUninit::new([0u8; 30 * 1024]),
|
||||||
static mut THREAD_2_STACK: Stack<1024> = esp_hal::system::Stack {
|
|
||||||
mem: MaybeUninit::new([0u8; 1024]),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
||||||
@ -174,35 +184,40 @@ fn main() -> ! {
|
|||||||
&mut THREAD_2_STACK
|
&mut THREAD_2_STACK
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
let messages = messages.clone();
|
let io = async_io.clone();
|
||||||
|| thread_2_main(messages)
|
|| thread_2_main(io, at_commands)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut test_delay = Delay::new();
|
let mut test_delay = Delay::new();
|
||||||
loop {
|
loop {
|
||||||
critical_section::with(|cs| {
|
state_mgr.update();
|
||||||
let mut borrowed = messages.borrow(cs).borrow_mut();
|
state_mgr.draw();
|
||||||
for message in borrowed.iter() {
|
|
||||||
log::info!("Received: {}", message);
|
|
||||||
}
|
|
||||||
borrowed.clear();
|
|
||||||
})
|
|
||||||
// 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
|
// 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>>>>) {
|
fn thread_2_main(async_io: AsyncIO, mut at_commands: ATCommands<'static, 'static>) {
|
||||||
let delay = Delay::new();
|
|
||||||
loop {
|
loop {
|
||||||
delay.delay_millis(1000);
|
if let Some(command) = unsafe { async_io.check_at_command() } {
|
||||||
log::info!("Sent message");
|
let response = match command {
|
||||||
critical_section::with(|cs| {
|
async_io::ATCommand::ATInformation => at_commands.raw_command("ATI".to_string()),
|
||||||
let mut borrowed = messages.borrow(cs).borrow_mut();
|
async_io::ATCommand::EnterPin(pin) => {
|
||||||
borrowed.push("Message!".to_owned());
|
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 esp_hal::{Blocking, delay::Delay};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
async_io::AsyncIO,
|
||||||
at_commands::ATCommands,
|
at_commands::ATCommands,
|
||||||
display::{Color, Display, Position, Rgb565},
|
display::{Color, Display, Position, Rgb565},
|
||||||
font::{FontRenderer, HorizontalAlignment, VerticalAlignment},
|
font::{FontRenderer, HorizontalAlignment, VerticalAlignment},
|
||||||
@ -34,8 +35,8 @@ pub enum DrawCommands {
|
|||||||
|
|
||||||
pub struct StateData<'a> {
|
pub struct StateData<'a> {
|
||||||
display: Display<'a, Blocking, Delay>,
|
display: Display<'a, Blocking, Delay>,
|
||||||
pub at_commands: ATCommands<'a, 'a>,
|
|
||||||
font_renderer: FontRenderer<'a>,
|
font_renderer: FontRenderer<'a>,
|
||||||
|
pub io: AsyncIO,
|
||||||
pub delay: Delay,
|
pub delay: Delay,
|
||||||
|
|
||||||
prev_commands: Vec<DrawCommands>,
|
prev_commands: Vec<DrawCommands>,
|
||||||
@ -43,13 +44,10 @@ pub struct StateData<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StateData<'a> {
|
impl<'a> StateData<'a> {
|
||||||
pub fn from(
|
pub fn from(display: Display<'a, Blocking, Delay>, io: AsyncIO) -> StateData<'a> {
|
||||||
display: Display<'a, Blocking, Delay>,
|
|
||||||
at_commands: ATCommands<'a, 'a>,
|
|
||||||
) -> StateData<'a> {
|
|
||||||
StateData {
|
StateData {
|
||||||
display,
|
display,
|
||||||
at_commands,
|
io,
|
||||||
font_renderer: FontRenderer::create(30),
|
font_renderer: FontRenderer::create(30),
|
||||||
delay: Delay::new(),
|
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::{
|
use crate::{
|
||||||
|
async_io::{ATCommand, SMSFormat},
|
||||||
display::{Position, Rgb565},
|
display::{Position, Rgb565},
|
||||||
state::{State, StateData, TextSettings},
|
state::{State, StateData, TextSettings},
|
||||||
};
|
};
|
||||||
@ -14,37 +19,45 @@ impl Default for InitATState {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner_state: 0,
|
inner_state: 0,
|
||||||
response: "Initializing AT..".to_owned(),
|
response: "Initializing AT..".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State for InitATState {
|
impl State for InitATState {
|
||||||
fn update(&mut self, data: &mut StateData) -> Option<Box<dyn State>> {
|
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 {
|
let res: Option<Box<dyn State>> = match self.inner_state {
|
||||||
0 => {
|
0 => {
|
||||||
data.at_commands.init();
|
data.io.send_at_command(ATCommand::ATInformation).unwrap();
|
||||||
self.response = data.at_commands.raw_command("ATI".to_owned());
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
self.response = data.at_commands.raw_command("AT+CMGF?".to_owned());
|
data.io
|
||||||
|
.send_at_command(ATCommand::EnterPin("1234".to_owned()))
|
||||||
|
.unwrap();
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
2 => {
|
2 => {
|
||||||
self.response = data.at_commands.raw_command("AT+CPIN=1234".to_owned());
|
data.io.send_at_command(ATCommand::CheckPin).unwrap();
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
self.response = data.at_commands.raw_command("AT+CPIN?".to_owned());
|
data.io
|
||||||
|
.send_at_command(ATCommand::ListTECharacterSets)
|
||||||
|
.unwrap();
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
4 => {
|
4 => {
|
||||||
self.response = data.at_commands.raw_command("AT+CMGF=1".to_owned());
|
data.io
|
||||||
None
|
.send_at_command(ATCommand::SelectSMSFormat(SMSFormat::TextMode))
|
||||||
}
|
.unwrap();
|
||||||
5 => {
|
|
||||||
self.response = data.at_commands.raw_command("AT+CSCS=?".to_owned());
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user