202 lines
5.5 KiB
Rust
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
|
|
})
|
|
}
|
|
}
|