use core::cell::RefCell;
use embassy_sync::signal::Signal;
use embedded_hal::digital::InputPin;
#[cfg(all(feature = "_ble", feature = "controller"))]
use {crate::channel::send_controller_event, crate::event::ControllerEvent};
use super::{InputDevice, InputProcessor};
use crate::KeyMap;
#[cfg(feature = "controller")]
use crate::channel::{CONTROLLER_CHANNEL, ControllerPub};
use crate::event::Event;
use crate::input_device::ProcessResult;
pub(crate) static BATTERY_UPDATE: Signal<crate::RawMutex, BatteryState> = Signal::new();
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BatteryState {
NotAvailable,
Normal(u8),
Charging,
Charged,
}
pub struct ChargingStateReader<I: InputPin> {
state_input: I,
low_active: bool,
current_charging_state: bool,
first_read: bool,
}
impl<I: InputPin> ChargingStateReader<I> {
pub fn new(state_input: I, low_active: bool) -> Self {
Self {
state_input,
low_active,
current_charging_state: false,
first_read: false,
}
}
}
impl<I: InputPin> InputDevice for ChargingStateReader<I> {
async fn read_event(&mut self) -> Event {
if !self.first_read {
embassy_time::Timer::after_secs(2).await;
let charging_state = self.state_input.is_low().unwrap_or(false);
self.current_charging_state = charging_state;
self.first_read = true;
return Event::ChargingState(charging_state);
}
loop {
let charging_state = self.state_input.is_low().unwrap_or(false);
if charging_state != self.current_charging_state {
self.current_charging_state = charging_state;
return Event::ChargingState(charging_state);
}
embassy_time::Timer::after_secs(5).await;
}
}
}
pub struct BatteryProcessor<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize, const NUM_ENCODER: usize> {
keymap: &'a RefCell<KeyMap<'a, ROW, COL, NUM_LAYER, NUM_ENCODER>>,
adc_divider_measured: u32,
adc_divider_total: u32,
battery_state: BatteryState,
#[cfg(feature = "controller")]
controller_pub: ControllerPub,
}
impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize, const NUM_ENCODER: usize>
BatteryProcessor<'a, ROW, COL, NUM_LAYER, NUM_ENCODER>
{
pub fn new(
adc_divider_measured: u32,
adc_divider_total: u32,
keymap: &'a RefCell<KeyMap<'a, ROW, COL, NUM_LAYER, NUM_ENCODER>>,
) -> Self {
BatteryProcessor {
keymap,
adc_divider_measured,
adc_divider_total,
battery_state: BatteryState::NotAvailable,
#[cfg(feature = "controller")]
controller_pub: unwrap!(CONTROLLER_CHANNEL.publisher()),
}
}
#[cfg(feature = "_ble")]
fn get_battery_percent(&self, val: u16) -> u8 {
let val = val as i32;
let mut measured = self.adc_divider_measured as i32;
let mut total = self.adc_divider_total as i32;
if 500 < val && val < 1000 {
measured = 1;
total = 5;
}
if val > 4755_i32 * measured / total {
100_u8
} else if val < 4055_i32 * measured / total {
0_u8
} else {
((val * total / measured - 4055) / 7) as u8
}
}
}
impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize, const NUM_ENCODER: usize>
InputProcessor<'a, ROW, COL, NUM_LAYER, NUM_ENCODER> for BatteryProcessor<'a, ROW, COL, NUM_LAYER, NUM_ENCODER>
{
async fn process(&mut self, event: Event) -> ProcessResult {
match event {
Event::Battery(val) => {
trace!("Detected battery ADC value: {:?}", val);
#[cfg(feature = "_ble")]
{
if matches!(self.battery_state, BatteryState::Normal(_) | BatteryState::NotAvailable) {
let battery_percent = self.get_battery_percent(val);
#[cfg(feature = "controller")]
send_controller_event(&mut self.controller_pub, ControllerEvent::Battery(battery_percent));
if self.battery_state != BatteryState::Normal(battery_percent) {
self.battery_state = BatteryState::Normal(battery_percent);
BATTERY_UPDATE.signal(self.battery_state);
}
}
}
ProcessResult::Stop
}
Event::ChargingState(charging) => {
info!("Charging state changed: {:?}", charging);
#[cfg(feature = "_ble")]
{
#[cfg(feature = "controller")]
send_controller_event(&mut self.controller_pub, ControllerEvent::ChargingState(charging));
if charging {
self.battery_state = BatteryState::Charging;
} else {
self.battery_state = BatteryState::NotAvailable;
}
}
ProcessResult::Stop
}
_ => ProcessResult::Continue(event),
}
}
fn get_keymap(&self) -> &RefCell<KeyMap<'a, ROW, COL, NUM_LAYER, NUM_ENCODER>> {
self.keymap
}
}