kitfort-esp32-mod/firmware/src/hid.rs
2025-03-08 02:15:05 +03:00

111 lines
No EOL
3.2 KiB
Rust

use anyhow::{Error, Result};
use std::{num::{NonZero, NonZeroU32}, sync::Arc};
use esp_idf_svc::{hal::{gpio::{Input, InputPin, InterruptType, Output, OutputPin, PinDriver}, task::notification::{Notification, Notifier}}, sys::EspError};
pub trait Indicator {
fn set_state(&mut self, state: bool) -> Result<()>;
fn get_state(&self) -> bool;
}
pub trait Button {
fn subscribe(&mut self) -> Result<()>;
fn unsubscribe(&mut self) -> Result<()>;
fn wait_event(&self, timeout: u32) -> Option<NonZero<u32>>;
}
pub struct GPIOButton<'d, P: InputPin> {
pin: PinDriver<'d, P, Input>,
int_type: InterruptType,
notification: Notification,
notifier: Arc<Notifier>,
}
impl<'d, P: InputPin> GPIOButton<'d, P> {
pub fn new(pin: P, int_type: InterruptType) -> Result<Self, EspError> {
let notification: Notification = Notification::new();
let notifier = notification.notifier();
return Ok(Self {
pin: PinDriver::input(pin)?,
int_type: int_type,
notification: notification,
notifier: notifier,
});
}
pub fn enable_interrupt(&mut self) -> Result<(), EspError>{
self.pin.enable_interrupt()?;
return Ok(());
}
}
impl<'d, P: InputPin> Button for GPIOButton<'d, P> {
fn subscribe(&mut self) -> Result<()> {
self.pin.set_interrupt_type(self.int_type)?;
unsafe {
let notifier = self.notifier.clone();
self.pin.subscribe(move || {
notifier.notify_and_yield(NonZeroU32::new(1).unwrap());
})?;
}
self.pin.enable_interrupt()?;
return Ok(());
}
fn unsubscribe(&mut self) -> Result<()> {
self.pin.disable_interrupt()?;
self.pin.unsubscribe()?;
return Ok(());
}
fn wait_event(&self, timeout: u32) -> Option<NonZero<u32>> {
return self.notification.wait(timeout);
}
}
pub struct GPIOIndicator<'d, P: OutputPin> {
pin: PinDriver<'d, P, Output>,
inverted: bool,
}
impl<'d, P: OutputPin> GPIOIndicator<'d, P> {
pub fn new(pin: P) -> Result<Self> {
let mut indicator = Self {
pin: PinDriver::output(pin)?,
inverted: false,
};
indicator.set_state(false)?;
return Ok(indicator);
}
pub fn set_inverted(&mut self, value: bool) {
self.inverted = value;
}
}
impl<'d, P: OutputPin> Indicator for GPIOIndicator<'d, P> {
fn set_state(&mut self, state: bool) -> Result<()> {
if state != !self.inverted {
self.pin.set_high()?;
} else {
self.pin.set_low()?;
}
return Ok(());
}
fn get_state(&self) -> bool {
return self.pin.is_set_high() != !self.inverted;
}
}
pub struct GPIOIndicatedButton<'d, B: InputPin, I: OutputPin> {
pub button: GPIOButton<'d, B>,
pub indicator: GPIOIndicator<'d, I>,
}
impl<'d, B: InputPin, I: OutputPin> GPIOIndicatedButton<'d, B, I> {
pub fn new(btn_pin: B, btn_int_type: InterruptType, indicator_pin: I) -> Result<Self> {
return Ok(Self {
button: GPIOButton::new(btn_pin, btn_int_type)?,
indicator: GPIOIndicator::new(indicator_pin)?,
});
}
}