208 lines
5.9 KiB
Rust
208 lines
5.9 KiB
Rust
use core::{cell::RefCell, marker::PhantomData};
|
|
|
|
use alloc::{
|
|
boxed::Box,
|
|
collections::{btree_map::BTreeMap, btree_set::BTreeSet},
|
|
rc::Rc,
|
|
string::String,
|
|
vec::Vec,
|
|
};
|
|
use critical_section::Mutex;
|
|
use esp_hal::delay::Delay;
|
|
|
|
use crate::at_commands::{ATCommand, ATParseError, 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_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<Box<dyn SimpleATCommand>>>>>,
|
|
handling_at_command: Rc<Mutex<RefCell<bool>>>,
|
|
at_response: Rc<Mutex<RefCell<Option<Vec<String>>>>>,
|
|
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<Option<Result<T::Response, ATParseError>>> {
|
|
match io.poll_at_response() {
|
|
Some(response) => match response {
|
|
Some(response) => {
|
|
let mut parser = ATResponseParser::from(response);
|
|
Some(Some(T::parse_response(&mut parser)))
|
|
}
|
|
None => Some(None),
|
|
},
|
|
None => Some(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: Vec<String>) {
|
|
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<Option<Vec<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() || *self.handling_at_command.borrow_ref(cs) {
|
|
return Some(None);
|
|
}
|
|
if let Some(resp) = response.take() {
|
|
return Some(Some(resp));
|
|
}
|
|
None
|
|
})
|
|
}
|
|
}
|