esp32-phone/src/async_io.rs
2026-06-02 13:17:08 +03:00

339 lines
10 KiB
Rust

use core::{cell::RefCell, char, marker::PhantomData};
use alloc::vec;
use alloc::{
boxed::Box,
collections::{btree_map::BTreeMap, btree_set::BTreeSet},
rc::Rc,
string::{String, ToString},
vec::Vec,
};
use critical_section::Mutex;
use crate::at_commands::{ATCommand, ATError, ATResponseParser, SimpleATCommand};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum KeypadButton {
Keypad1,
Keypad2,
Keypad3,
Keypad4,
Keypad5,
Keypad6,
Keypad7,
Keypad8,
Keypad9,
Keypad0,
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(cs).clone();
*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);
log::info!("{:?}", *button);
num_presses.insert(*button, num + 1);
}
}
*self.presses.borrow_ref_mut(cs) = num_presses;
});
}
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(Clone)]
pub struct AsyncIO {
at_command: Rc<Mutex<RefCell<Option<Box<dyn SimpleATCommand>>>>>,
handling_at_command: Rc<Mutex<RefCell<bool>>>,
at_response: Rc<Mutex<RefCell<Option<Result<Vec<String>, ATError>>>>>,
pub keypad: Keypad,
}
impl Default for AsyncIO {
fn default() -> Self {
Self {
at_command: Rc::new(Mutex::new(RefCell::new(None))),
handling_at_command: Rc::new(Mutex::new(RefCell::new(false))),
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, Debug)]
pub struct ATPromise<T: ATCommand> {
_data: PhantomData<T>,
}
impl<T: ATCommand> ATPromise<T> {
pub fn poll(&self, io: &mut AsyncIO) -> Option<Result<T::Response, ATError>> {
match io.poll_at_response() {
Some(response) => {
log::info!("Response: {:?}", response);
match response {
Ok(response) => {
let mut parser = ATResponseParser::from(response);
Some(T::parse_response(&mut parser))
}
Err(err) => Some(Err(err)),
}
}
None => None,
}
}
}
impl AsyncIO {
pub fn send_at_command<Resp, T: ATCommand<Response = Resp> + 'static>(
&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(Box::new(command));
Ok(ATPromise { _data: PhantomData })
})
}
pub unsafe fn check_at_command(self) -> Option<Box<dyn SimpleATCommand>> {
critical_section::with(|cs| {
let mut borrow = self.at_command.borrow_ref_mut(cs);
*self.handling_at_command.borrow_ref_mut(cs) = true;
borrow.take()
})
}
pub unsafe fn set_at_response(&self, response_str: Result<Vec<String>, ATError>) {
critical_section::with(|cs| {
*self.handling_at_command.borrow_ref_mut(cs) = false;
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<Result<Vec<String>, ATError>> {
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 None;
}
if let Some(resp) = response.take() {
return Some(resp);
}
None
})
}
}
#[derive(Default, Clone)]
pub struct NumberInput {
written: String,
}
impl NumberInput {
pub fn poll(&mut self, io: &mut AsyncIO) -> bool {
let mut wrote = false;
for button in io.keypad.just_pressed_buttons() {
let character = match button {
KeypadButton::Keypad1 => Some('1'),
KeypadButton::Keypad2 => Some('2'),
KeypadButton::Keypad3 => Some('3'),
KeypadButton::Keypad4 => Some('4'),
KeypadButton::Keypad5 => Some('5'),
KeypadButton::Keypad6 => Some('6'),
KeypadButton::Keypad7 => Some('7'),
KeypadButton::Keypad8 => Some('8'),
KeypadButton::Keypad9 => Some('9'),
KeypadButton::Keypad0 => Some('0'),
_ => None,
};
if let Some(character) = character {
self.written += &character.to_string();
wrote = true;
}
}
wrote
}
pub fn read<'s>(&'s self) -> &'s String {
&self.written
}
}
impl KeypadButton {
pub fn get_chars(&self) -> Option<Vec<char>> {
match self {
KeypadButton::Keypad1 => Some(vec![' ', '1']),
KeypadButton::Keypad2 => Some(vec!['a', 'b', 'c', '2']),
KeypadButton::Keypad3 => Some(vec!['d', 'e', 'f', '3']),
KeypadButton::Keypad4 => Some(vec!['g', 'h', 'i', '4']),
KeypadButton::Keypad5 => Some(vec!['j', 'k', 'l', '5']),
KeypadButton::Keypad6 => Some(vec!['m', 'n', 'o', '6']),
KeypadButton::Keypad7 => Some(vec!['p', 'q', 'r', 's', '7']),
KeypadButton::Keypad8 => Some(vec!['t', 'u', 'v', '8']),
KeypadButton::Keypad9 => Some(vec!['w', 'x', 'y', 'z', '9']),
KeypadButton::Keypad0 => Some(vec![' ', '0']),
KeypadButton::KeypadStar => Some(vec!['*']),
KeypadButton::KeypadHash => Some(vec!['#']),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub struct LastPressed {
key: KeypadButton,
idx: usize,
}
impl LastPressed {
pub fn increment(&mut self) {
let chars = self.key.get_chars();
if let Some(chars) = chars {
self.idx = (self.idx + 1) % chars.len()
}
}
pub fn get_char(&self) -> char {
self.key.get_chars().unwrap()[self.idx]
}
}
static TEXT_KEYS: [KeypadButton; 13] = [
KeypadButton::Keypad0,
KeypadButton::Keypad1,
KeypadButton::Keypad2,
KeypadButton::Keypad3,
KeypadButton::Keypad4,
KeypadButton::Keypad5,
KeypadButton::Keypad6,
KeypadButton::Keypad7,
KeypadButton::Keypad8,
KeypadButton::Keypad9,
KeypadButton::Keypad0,
KeypadButton::KeypadStar,
KeypadButton::KeypadHash,
];
#[derive(Debug, Default, Clone)]
pub struct TextInput {
written: String,
last_pressed: Option<LastPressed>,
}
impl TextInput {
pub fn poll(&mut self, io: &mut AsyncIO) -> bool {
let mut wrote = false;
for button in io.keypad.just_pressed_buttons() {
if let Some(mut last_pressed) = self.last_pressed.take() {
if last_pressed.key == button {
last_pressed.increment();
self.last_pressed = Some(last_pressed);
wrote = true;
} else if TEXT_KEYS.contains(&button) {
self.written += &last_pressed.get_char().to_string();
self.last_pressed = Some(LastPressed {
key: button,
idx: 0,
});
wrote = true;
} else if button == KeypadButton::KeypadA {
self.written += &last_pressed.get_char().to_string();
wrote = true;
}
} else if TEXT_KEYS.contains(&button) {
self.last_pressed = Some(LastPressed {
key: button,
idx: 0,
});
wrote = true;
}
}
wrote
}
pub fn read(&self) -> String {
let mut written = self.written.clone();
if let Some(last_pressed) = &self.last_pressed {
written += &last_pressed.get_char().to_string();
}
written
}
}