implement hid io wrapper
This commit is contained in:
parent
7d35bbedbf
commit
9d0444a87a
2 changed files with 180 additions and 71 deletions
111
firmware/src/hid.rs
Normal file
111
firmware/src/hid.rs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
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)?,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +1,22 @@
|
|||
use std::{num::NonZeroU32, thread, time::Duration};
|
||||
mod hid;
|
||||
|
||||
use std::{thread, time::{Duration, SystemTime}};
|
||||
use anyhow::Result;
|
||||
use embedded_graphics::{
|
||||
mono_font::{ascii::FONT_6X10, MonoTextStyleBuilder},
|
||||
pixelcolor::BinaryColor,
|
||||
prelude::Point,
|
||||
text::{Baseline, Text},
|
||||
Drawable
|
||||
};
|
||||
use esp_idf_svc::hal::{
|
||||
i2c::{I2cConfig, I2cDriver},
|
||||
adc::{attenuation::DB_11, oneshot::{config::AdcChannelConfig, AdcChannelDriver, AdcDriver}},
|
||||
delay::FreeRtos,
|
||||
gpio::{InterruptType, PinDriver, Pull},
|
||||
gpio::{InterruptType, PinDriver},
|
||||
i2c::{I2cConfig, I2cDriver},
|
||||
prelude::Peripherals,
|
||||
units::*,
|
||||
task::notification::Notification
|
||||
units::*
|
||||
};
|
||||
use hid::{Button, GPIOIndicatedButton, Indicator};
|
||||
use ssd1306::{mode::DisplayConfig, prelude::DisplayRotation, size::DisplaySize128x32, I2CDisplayInterface, Ssd1306};
|
||||
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// It is necessary to call this function once. Otherwise some patches to the runtime
|
||||
// implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
|
||||
|
|
@ -32,16 +31,17 @@ fn main() -> Result<()> {
|
|||
let i2c_sda_pin = peripherals.pins.gpio8;
|
||||
let i2c_scl_pin = peripherals.pins.gpio9;
|
||||
|
||||
let mut led_pin = PinDriver::output(peripherals.pins.gpio15).unwrap();
|
||||
let mut led2_pin = PinDriver::output(peripherals.pins.gpio3).unwrap();
|
||||
let mut led_pin= PinDriver::output(peripherals.pins.gpio15).unwrap();
|
||||
|
||||
let mut btn1 = GPIOIndicatedButton::new(peripherals.pins.gpio2, InterruptType::PosEdge, peripherals.pins.gpio3)?;
|
||||
let mut btn2 = GPIOIndicatedButton::new(peripherals.pins.gpio4, InterruptType::PosEdge, peripherals.pins.gpio5)?;
|
||||
let mut btn3 = GPIOIndicatedButton::new(peripherals.pins.gpio6, InterruptType::PosEdge, peripherals.pins.gpio7)?;
|
||||
|
||||
btn1.button.subscribe()?;
|
||||
|
||||
let mut heater_drv_pin = PinDriver::output(peripherals.pins.gpio13).unwrap();
|
||||
let mut pump_drv_pin = PinDriver::output(peripherals.pins.gpio12).unwrap();
|
||||
|
||||
let mut button1 = PinDriver::input(peripherals.pins.gpio2)?;
|
||||
let mut button2 = PinDriver::input(peripherals.pins.gpio4)?;
|
||||
let mut button3 = PinDriver::input(peripherals.pins.gpio6)?;
|
||||
|
||||
let config = AdcChannelConfig {
|
||||
attenuation: DB_11,
|
||||
..Default::default()
|
||||
|
|
@ -61,53 +61,8 @@ fn main() -> Result<()> {
|
|||
.text_color(BinaryColor::On)
|
||||
.build();
|
||||
|
||||
button1.set_pull(Pull::Down)?;
|
||||
button1.set_interrupt_type(InterruptType::PosEdge)?;
|
||||
|
||||
button2.set_pull(Pull::Down)?;
|
||||
button2.set_interrupt_type(InterruptType::PosEdge)?;
|
||||
|
||||
button3.set_pull(Pull::Down)?;
|
||||
button3.set_interrupt_type(InterruptType::PosEdge)?;
|
||||
|
||||
let notification = Notification::new();
|
||||
let notifier = notification.notifier();
|
||||
|
||||
unsafe {
|
||||
button1.subscribe(move || {
|
||||
notifier.notify_and_yield(NonZeroU32::new(1).unwrap());
|
||||
})?;
|
||||
}
|
||||
|
||||
button1.enable_interrupt()?;
|
||||
|
||||
log::info!("Hello, world!");
|
||||
|
||||
loop {
|
||||
let not = notification.wait(esp_idf_svc::hal::delay::NON_BLOCK);
|
||||
match not {
|
||||
Some(n) => {
|
||||
println!("Button 1 pressed!");
|
||||
button1.enable_interrupt()?;
|
||||
|
||||
if heater_drv_pin.is_set_high() {
|
||||
heater_drv_pin.set_low()?;
|
||||
} else {
|
||||
heater_drv_pin.set_high()?;
|
||||
}
|
||||
},
|
||||
None => (),
|
||||
}
|
||||
|
||||
led_pin.set_low().unwrap();
|
||||
led2_pin.set_low().unwrap();
|
||||
FreeRtos::delay_ms(1000);
|
||||
|
||||
led_pin.set_high().unwrap();
|
||||
led2_pin.set_high().unwrap();
|
||||
FreeRtos::delay_ms(1000);
|
||||
println!("blink");
|
||||
|
||||
const R1: f32 = 100000_f32;
|
||||
const R0: f32 = 100000_f32;
|
||||
const V1: f32 = 5_f32;
|
||||
|
|
@ -115,27 +70,70 @@ fn main() -> Result<()> {
|
|||
const B: f32 = 4285_f32;
|
||||
|
||||
let mut samples_sum = 0_f32;
|
||||
for i in 0..64 {
|
||||
let mut temperature = 0_f32;
|
||||
let mut i = 0_u32;
|
||||
|
||||
let mut blink_time: SystemTime = SystemTime::now();
|
||||
let mut measure_time: SystemTime = SystemTime::now();
|
||||
|
||||
loop {
|
||||
// #FIXME button handler needs debounce.
|
||||
let not = btn1.button.wait_event(esp_idf_svc::hal::delay::NON_BLOCK);
|
||||
match not {
|
||||
Some(n) => {
|
||||
println!("Button 1 pressed!");
|
||||
btn1.button.enable_interrupt()?;
|
||||
|
||||
if heater_drv_pin.is_set_high() {
|
||||
heater_drv_pin.set_low()?;
|
||||
btn1.indicator.set_state(false)?;
|
||||
} else {
|
||||
heater_drv_pin.set_high()?;
|
||||
btn1.indicator.set_state(true)?;
|
||||
}
|
||||
},
|
||||
None => (),
|
||||
}
|
||||
|
||||
if measure_time.elapsed()?.as_millis() >= 10 {
|
||||
if i < 64 {
|
||||
let v = adc.read(&mut therm_pin)? as f32 / 1000_f32;
|
||||
let r = R1 / (V1 / v - 1_f32);
|
||||
let temp = T0 * B / (T0 * (r / R0).ln() + B) - 273.15_f32;
|
||||
samples_sum += temp;
|
||||
FreeRtos::delay_ms(10);
|
||||
i += 1;
|
||||
} else {
|
||||
temperature = samples_sum / 64_f32;
|
||||
println!("Temperature value: {}", temperature);
|
||||
samples_sum = 0_f32;
|
||||
i = 0;
|
||||
}
|
||||
measure_time = SystemTime::now();
|
||||
}
|
||||
let temp = samples_sum / 64_f32;
|
||||
|
||||
println!("Temperature value: {}", temp);
|
||||
if blink_time.elapsed()?.as_millis() >= 1000 {
|
||||
if led_pin.is_set_high() {
|
||||
led_pin.set_low().unwrap();
|
||||
} else {
|
||||
led_pin.set_high().unwrap();
|
||||
println!("blink");
|
||||
}
|
||||
|
||||
display.clear_buffer();
|
||||
// #FIXME display updates take too long. Need some research for options.
|
||||
|
||||
Text::with_baseline(format!("Temperature: {}", temp).as_str(), Point::zero(), text_style, Baseline::Top)
|
||||
.draw(&mut display)
|
||||
.unwrap();
|
||||
Text::with_baseline(format!("Relay: {}", heater_drv_pin.is_set_high()).as_str(), Point::new(0, 16), text_style, Baseline::Top)
|
||||
.draw(&mut display)
|
||||
.unwrap();
|
||||
// display.clear_buffer();
|
||||
|
||||
display.flush().unwrap();
|
||||
// Text::with_baseline(format!("Temperature: {}", temperature).as_str(), Point::zero(), text_style, Baseline::Top)
|
||||
// .draw(&mut display)
|
||||
// .unwrap();
|
||||
// Text::with_baseline(format!("Relay: {}", heater_drv_pin.is_set_high()).as_str(), Point::new(0, 16), text_style, Baseline::Top)
|
||||
// .draw(&mut display)
|
||||
// .unwrap();
|
||||
|
||||
// display.flush().unwrap();
|
||||
|
||||
blink_time = SystemTime::now();
|
||||
}
|
||||
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue