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>>>, is_pressed: Rc>>>, presses: Rc>>>, } 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) { 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 { critical_section::with(|cs| { let is_pressed = self.is_pressed.borrow_ref(cs); is_pressed.clone() }) } pub fn just_pressed_buttons(&self) -> BTreeSet { 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>>>, at_response: Rc>>>, 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 { _data: PhantomData, } impl ATPromise { pub fn poll(&self, io: &mut AsyncIO) -> Option> { 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 { ATPromise { _data: PhantomData } } } impl AsyncIO { pub fn send_at_command>( &self, command: T, ) -> Result, ()> { 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 { 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> { 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 }) } }