Add text input
This commit is contained in:
parent
da2eb1baad
commit
b6517d2ee6
119
src/async_io.rs
119
src/async_io.rs
@ -1,5 +1,6 @@
|
|||||||
use core::{cell::RefCell, char, marker::PhantomData};
|
use core::{cell::RefCell, char, marker::PhantomData};
|
||||||
|
|
||||||
|
use alloc::vec;
|
||||||
use alloc::{
|
use alloc::{
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
collections::{btree_map::BTreeMap, btree_set::BTreeSet},
|
collections::{btree_map::BTreeMap, btree_set::BTreeSet},
|
||||||
@ -8,7 +9,6 @@ use alloc::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use critical_section::Mutex;
|
use critical_section::Mutex;
|
||||||
use esp_hal::delay::Delay;
|
|
||||||
|
|
||||||
use crate::at_commands::{ATCommand, ATParseError, ATResponseParser, SimpleATCommand};
|
use crate::at_commands::{ATCommand, ATParseError, ATResponseParser, SimpleATCommand};
|
||||||
|
|
||||||
@ -54,16 +54,19 @@ impl Keypad {
|
|||||||
critical_section::with(|cs| {
|
critical_section::with(|cs| {
|
||||||
let mut was_pressed = self.was_pressed.borrow_ref_mut(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 is_pressed = self.is_pressed.borrow_ref_mut(cs);
|
||||||
let mut num_presses = self.presses.borrow_ref_mut(cs);
|
let mut num_presses = self.presses.borrow_ref(cs).clone();
|
||||||
|
|
||||||
*was_pressed = is_pressed.clone();
|
*was_pressed = is_pressed.clone();
|
||||||
*is_pressed = presses;
|
*is_pressed = presses;
|
||||||
for button in is_pressed.iter() {
|
for button in is_pressed.iter() {
|
||||||
if !was_pressed.contains(button) {
|
if !was_pressed.contains(button) {
|
||||||
let num = num_presses.get(button).copied().unwrap_or(0);
|
let num = num_presses.get(button).copied().unwrap_or(0);
|
||||||
|
log::info!("{:?}", *button);
|
||||||
num_presses.insert(*button, num + 1);
|
num_presses.insert(*button, num + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*self.presses.borrow_ref_mut(cs) = num_presses;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,17 +106,6 @@ impl Keypad {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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)]
|
#[derive(Clone)]
|
||||||
pub struct AsyncIO {
|
pub struct AsyncIO {
|
||||||
at_command: Rc<Mutex<RefCell<Option<Box<dyn SimpleATCommand>>>>>,
|
at_command: Rc<Mutex<RefCell<Option<Box<dyn SimpleATCommand>>>>>,
|
||||||
@ -240,3 +232,104 @@ impl NumberInput {
|
|||||||
&self.written
|
&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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -4,8 +4,6 @@ use alloc::{borrow::ToOwned, format};
|
|||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
use esp_hal::{Blocking, delay::Delay, gpio::Output, uart::Uart};
|
use esp_hal::{Blocking, delay::Delay, gpio::Output, uart::Uart};
|
||||||
|
|
||||||
use crate::async_io::ConstructedATCommand;
|
|
||||||
|
|
||||||
static RESPONSES: [&'static str; 3] = ["OK", "ERROR", "DOWNLOAD"];
|
static RESPONSES: [&'static str; 3] = ["OK", "ERROR", "DOWNLOAD"];
|
||||||
|
|
||||||
pub struct ATCommands<'a, 'd> {
|
pub struct ATCommands<'a, 'd> {
|
||||||
|
|||||||
@ -256,10 +256,6 @@ fn thread_2_main(
|
|||||||
delay.delay_millis(5);
|
delay.delay_millis(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
if buttons_pressed.len() > 0 {
|
|
||||||
log::info!("{:?}", buttons_pressed)
|
|
||||||
}
|
|
||||||
|
|
||||||
async_io.keypad.handle_presses(buttons_pressed);
|
async_io.keypad.handle_presses(buttons_pressed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ use alloc::{
|
|||||||
use esp_hal::time::{Duration, Instant};
|
use esp_hal::time::{Duration, Instant};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
async_io::{ATPromise, KeypadButton, NumberInput},
|
async_io::{ATPromise, KeypadButton, NumberInput, TextInput},
|
||||||
at_commands::{
|
at_commands::{
|
||||||
ATCommand, ATInformationCommand, ATParseError, CheckPinCommand, CheckPinResult,
|
ATCommand, ATInformationCommand, ATParseError, CheckPinCommand, CheckPinResult,
|
||||||
EnterPinCommand, EnterPinResult, SMSFormat, SelectSMSFormatCommand, SendSMSCommand,
|
EnterPinCommand, EnterPinResult, SMSFormat, SelectSMSFormatCommand, SendSMSCommand,
|
||||||
@ -307,35 +307,37 @@ impl State for PhoneNumberState {
|
|||||||
|
|
||||||
pub struct MessageState {
|
pub struct MessageState {
|
||||||
number: String,
|
number: String,
|
||||||
input: NumberInput,
|
input: TextInput,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State for MessageState {
|
impl State for MessageState {
|
||||||
fn update(&mut self, data: &mut StateData) -> Option<Box<dyn State>> {
|
fn update(&mut self, data: &mut StateData) -> Option<Box<dyn State>> {
|
||||||
self.input.poll(&mut data.io);
|
if !self.input.poll(&mut data.io) {
|
||||||
|
if data.io.keypad.get_presses(KeypadButton::KeypadA) > 0 {
|
||||||
if data.io.keypad.get_presses(KeypadButton::KeypadA) > 0 {
|
Some(Box::new(ATCommandState::with(
|
||||||
Some(Box::new(ATCommandState::with(
|
"Sending SMS..".to_owned(),
|
||||||
"Sending SMS..".to_owned(),
|
SendSMSCommand {
|
||||||
SendSMSCommand {
|
destination: self.number.clone(),
|
||||||
destination: self.number.clone(),
|
message: self.input.read().clone(),
|
||||||
message: self.input.read().clone(),
|
},
|
||||||
},
|
|resp| match resp.unwrap() {
|
||||||
|resp| match resp.unwrap() {
|
SendSMSResponse::MessageRefrence(refrence) => Box::new(TextState {
|
||||||
SendSMSResponse::MessageRefrence(refrence) => Box::new(TextState {
|
text: format!("SMS sent\nRef: {}", refrence),
|
||||||
text: format!("SMS sent\nRef: {}", refrence),
|
after: PhoneNumberState::default(),
|
||||||
after: PhoneNumberState::default(),
|
}),
|
||||||
}),
|
SendSMSResponse::Error => Box::new(TextState {
|
||||||
SendSMSResponse::Error => Box::new(TextState {
|
text: "ERROR!".to_owned(),
|
||||||
text: "ERROR!".to_owned(),
|
after: PhoneNumberState::default(),
|
||||||
after: PhoneNumberState::default(),
|
}),
|
||||||
}),
|
SendSMSResponse::ErrorMessage(msg) => Box::new(TextState {
|
||||||
SendSMSResponse::ErrorMessage(msg) => Box::new(TextState {
|
text: format!("Error:\n{}", msg),
|
||||||
text: format!("Error:\n{}", msg),
|
after: PhoneNumberState::default(),
|
||||||
after: PhoneNumberState::default(),
|
}),
|
||||||
}),
|
},
|
||||||
},
|
)))
|
||||||
)))
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user