339 lines
10 KiB
Rust
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
|
|
}
|
|
}
|