esp32-phone/src/async_io.rs
2026-05-29 21:56:23 +03:00

202 lines
5.5 KiB
Rust

use core::{cell::RefCell, marker::PhantomData};
use alloc::{
collections::{btree_map::BTreeMap, btree_set::BTreeSet},
rc::Rc,
string::String,
vec::Vec,
};
use critical_section::Mutex;
use crate::at_commands::{ATCommand, StubATCommand};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum KeypadButton {
Keypad1,
Keypad2,
Keypad3,
Keypad4,
Keypad5,
Keypad6,
Keypad7,
Keypad8,
Keypad9,
KeypadStar,
KeypadHash,
KeypadA,
KeypadB,
KeypadC,
KeypadD,
}
#[derive(Clone)]
pub struct Keypad {
was_pressed: Rc<Mutex<RefCell<BTreeSet<KeypadButton>>>>,
is_pressed: Rc<Mutex<RefCell<BTreeSet<KeypadButton>>>>,
presses: Rc<Mutex<RefCell<BTreeMap<KeypadButton, u32>>>>,
}
impl Default for Keypad {
fn default() -> Self {
Self {
was_pressed: Rc::new(Mutex::new(RefCell::new(Default::default()))),
is_pressed: Rc::new(Mutex::new(RefCell::new(Default::default()))),
presses: Rc::new(Mutex::new(RefCell::new(Default::default()))),
}
}
}
impl Keypad {
pub fn handle_presses(&self, presses: BTreeSet<KeypadButton>) {
critical_section::with(|cs| {
let mut was_pressed = self.was_pressed.borrow_ref_mut(cs);
let mut is_pressed = self.is_pressed.borrow_ref_mut(cs);
let mut num_presses = self.presses.borrow_ref_mut(cs);
*was_pressed = is_pressed.clone();
*is_pressed = presses;
for button in is_pressed.iter() {
if !was_pressed.contains(button) {
let num = num_presses.get(button).copied().unwrap_or(0);
num_presses.insert(*button, num + 1);
}
}
});
}
pub fn get_presses(&self, button: KeypadButton) -> u32 {
critical_section::with(|cs| {
let presses = self.presses.borrow_ref(cs);
presses.get(&button).copied().unwrap_or(0)
})
}
pub fn is_pressed(&self, button: KeypadButton) -> bool {
critical_section::with(|cs| {
let is_pressed = self.is_pressed.borrow_ref(cs);
is_pressed.contains(&button)
})
}
pub fn pressed_buttons(&self) -> BTreeSet<KeypadButton> {
critical_section::with(|cs| {
let is_pressed = self.is_pressed.borrow_ref(cs);
is_pressed.clone()
})
}
pub fn just_pressed_buttons(&self) -> BTreeSet<KeypadButton> {
critical_section::with(|cs| {
let presses = self.presses.borrow_ref(cs);
presses.keys().copied().collect()
})
}
pub fn clear(&self) {
critical_section::with(|cs| {
let mut presses = self.presses.borrow_ref_mut(cs);
presses.clear();
})
}
}
#[derive(Debug, Clone)]
pub enum ConstructedATCommand {
/// Single-part command
Single(String),
/// Two-part AT-command
AddInfo(String, String),
}
unsafe impl Send for ConstructedATCommand {}
unsafe impl Sync for ConstructedATCommand {}
#[derive(Clone)]
pub struct AsyncIO {
at_command: Rc<Mutex<RefCell<Option<ConstructedATCommand>>>>,
at_response: Rc<Mutex<RefCell<Option<String>>>>,
pub keypad: Keypad,
}
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))),
keypad: Keypad::default(),
}
}
}
unsafe impl Send for AsyncIO {}
unsafe impl Sync for AsyncIO {}
#[derive(Default, Clone)]
pub struct ATPromise<T: ATCommand> {
_data: PhantomData<T>,
}
impl<T: ATCommand> ATPromise<T> {
pub fn poll(&self, io: &mut AsyncIO) -> Option<Option<T::Response>> {
match io.poll_at_response() {
Some(response) => match response {
Some(response) => Some(Some(T::parse_response(response))),
None => Some(None),
},
None => Some(None),
}
}
pub fn downgrade(self) -> ATPromise<StubATCommand> {
ATPromise { _data: PhantomData }
}
}
impl AsyncIO {
pub fn send_at_command<Resp, T: ATCommand<Response = Resp>>(
&self,
command: T,
) -> Result<ATPromise<T>, ()> {
critical_section::with(|cs| {
let mut borrow = self.at_command.borrow_ref_mut(cs);
if borrow.is_some() {
return Err(());
}
*borrow = Some(command.execute());
Ok(ATPromise { _data: PhantomData })
})
}
pub unsafe fn check_at_command(&self) -> Option<ConstructedATCommand> {
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);
})
}
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
})
}
}