use core::cell::RefCell;
use embedded_hal_bus::i2c::RefCellDevice as I2cRefCellDevice;
use esp_hal::{
analog::adc::{Adc, AdcConfig, AdcPin, Attenuation},
gpio::{Input, InputConfig, Level, Output, OutputConfig},
i2c::master::I2c,
ledc::{
LowSpeed,
channel::{Channel, ChannelIFace},
timer::{self, Timer, TimerIFace},
},
peripherals::{GPIO0, Peripherals},
time::Rate,
};
use static_cell::StaticCell;
#[cfg(feature = "async")]
use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice as I2cAsyncDevice;
#[cfg(feature = "async")]
use embassy_sync::{blocking_mutex::raw::NoopRawMutex, mutex::Mutex as AsyncMutex};
#[cfg(feature = "async")]
use esp_hal::peripherals::{SW_INTERRUPT, TIMG0};
#[cfg(feature = "power-board")]
use embedded_hal_bus::spi::RefCellDevice as SpiRefCellDevice;
#[cfg(feature = "power-board")]
use esp_hal::delay::Delay;
#[cfg(feature = "power-board")]
use esp_hal::spi::master::Spi;
#[cfg(feature = "async")]
use crate::Async;
use crate::Uferris;
#[cfg(feature = "async")]
use crate::components::io_expander::IoExpander;
use crate::components::ldr::OneShot;
#[cfg(feature = "async")]
use crate::components::ldr::OneShotAsync;
static BUZZER_TIMER: StaticCell<Timer<'static, LowSpeed>> = StaticCell::new();
static I2C_BUS: StaticCell<RefCell<EspI2c>> = StaticCell::new();
#[cfg(feature = "power-board")]
static SPI_BUS: StaticCell<RefCell<EspSpi>> = StaticCell::new();
#[cfg(feature = "async")]
static ASYNC_I2C_BUS: StaticCell<AsyncMutex<NoopRawMutex, EspAsyncI2c>> = StaticCell::new();
type EspI2c = I2c<'static, esp_hal::Blocking>;
type SharedI2c = I2cRefCellDevice<'static, EspI2c>;
#[cfg(feature = "async")]
type EspAsyncI2c = I2c<'static, esp_hal::Async>;
#[cfg(feature = "async")]
type SharedAsyncI2c = I2cAsyncDevice<'static, NoopRawMutex, EspAsyncI2c>;
pub struct LdrAdc<'d> {
adc: Adc<'d, esp_hal::peripherals::ADC1<'d>, esp_hal::Blocking>,
pin: AdcPin<GPIO0<'d>, esp_hal::peripherals::ADC1<'d>>,
}
impl<'d> OneShot for LdrAdc<'d> {
fn read_raw(&mut self) -> u16 {
nb::block!(self.adc.read_oneshot(&mut self.pin)).unwrap_or(0)
}
}
#[cfg(feature = "async")]
pub struct LdrAdcAsync<'d> {
adc: Adc<'d, esp_hal::peripherals::ADC1<'d>, esp_hal::Async>,
pin: AdcPin<GPIO0<'d>, esp_hal::peripherals::ADC1<'d>>,
}
#[cfg(feature = "async")]
impl OneShotAsync for LdrAdcAsync<'_> {
async fn read_raw(&mut self) -> u16 {
self.adc.read_oneshot(&mut self.pin).await
}
}
pub type EspBuzzerChannel = Channel<'static, LowSpeed>;
#[cfg(feature = "power-board")]
type EspSpi = Spi<'static, esp_hal::Blocking>;
#[cfg(feature = "power-board")]
type SdBlockDevice =
embedded_sdmmc::SdCard<SpiRefCellDevice<'static, EspSpi, Output<'static>, Delay>, Delay>;
#[cfg(not(feature = "power-board"))]
pub type UferrisEsp32 = Uferris<
Output<'static>, Input<'static>, EspBuzzerChannel, SharedI2c, LdrAdc<'static>, (),
>;
#[cfg(feature = "power-board")]
pub type UferrisEsp32 = Uferris<
Output<'static>, Input<'static>, EspBuzzerChannel, SharedI2c, LdrAdc<'static>, SdBlockDevice, >;
#[cfg(all(feature = "async", not(feature = "power-board")))]
pub type UferrisEsp32Async = Uferris<
Output<'static>, Input<'static>, EspBuzzerChannel, SharedAsyncI2c, LdrAdcAsync<'static>, (),
Async,
>;
#[cfg(all(feature = "async", feature = "power-board"))]
pub type UferrisEsp32Async = Uferris<
Output<'static>, Input<'static>, EspBuzzerChannel, SharedAsyncI2c, LdrAdcAsync<'static>, SdBlockDevice, Async,
>;
#[cfg(feature = "async")]
pub struct EspRtosParts {
pub timg0: TIMG0<'static>,
pub sw_interrupt: SW_INTERRUPT<'static>,
}
pub fn uferris_init(peripherals: Peripherals) -> UferrisEsp32 {
let mut adc_config = AdcConfig::new();
let ldr_pin = adc_config.enable_pin(peripherals.GPIO0, Attenuation::_11dB);
let adc1 = Adc::new(peripherals.ADC1, adc_config);
let ldr_driver = LdrAdc {
adc: adc1,
pin: ldr_pin,
};
let i2c = I2c::new(
peripherals.I2C0,
esp_hal::i2c::master::Config::default().with_frequency(Rate::from_khz(100)),
)
.unwrap()
.with_scl(peripherals.GPIO23)
.with_sda(peripherals.GPIO22);
let i2c_bus_ref = I2C_BUS.init(RefCell::new(i2c));
let expander_i2c = I2cRefCellDevice::new(i2c_bus_ref);
let rtc_i2c = I2cRefCellDevice::new(i2c_bus_ref);
let raw_i2c = I2cRefCellDevice::new(i2c_bus_ref);
#[cfg(feature = "power-board")]
let ina_i2c = I2cRefCellDevice::new(i2c_bus_ref);
let led = Output::new(peripherals.GPIO1, Level::Low, OutputConfig::default());
let button = Input::new(peripherals.GPIO21, InputConfig::default());
let mut ledc = esp_hal::ledc::Ledc::new(peripherals.LEDC);
ledc.set_global_slow_clock(esp_hal::ledc::LSGlobalClkSource::APBClk);
let mut buzzer_timer =
ledc.timer::<esp_hal::ledc::LowSpeed>(esp_hal::ledc::timer::Number::Timer0);
buzzer_timer
.configure(timer::config::Config {
duty: timer::config::Duty::Duty14Bit,
clock_source: timer::LSClockSource::APBClk,
frequency: Rate::from_hz(2700u32),
})
.unwrap();
let buzzer_timer_ref = BUZZER_TIMER.init(buzzer_timer);
let mut buzzer_channel =
ledc.channel(esp_hal::ledc::channel::Number::Channel0, peripherals.GPIO2);
buzzer_channel
.configure(esp_hal::ledc::channel::config::Config {
timer: buzzer_timer_ref,
duty_pct: 0,
drive_mode: esp_hal::gpio::DriveMode::PushPull,
})
.unwrap();
#[cfg(feature = "power-board")]
let vol_mgr = {
let spi = Spi::new(
peripherals.SPI2,
esp_hal::spi::master::Config::default().with_frequency(Rate::from_khz(400)),
)
.unwrap()
.with_sck(peripherals.GPIO19)
.with_miso(peripherals.GPIO20)
.with_mosi(peripherals.GPIO18);
let spi_bus_ref = SPI_BUS.init(RefCell::new(spi));
let sd_cs = Output::new(peripherals.GPIO17, Level::High, OutputConfig::default());
let delay = Delay::new();
let sd_device = SpiRefCellDevice::new(spi_bus_ref, sd_cs, delay).unwrap();
let sd_card = embedded_sdmmc::SdCard::new(sd_device, delay);
Some(embedded_sdmmc::VolumeManager::new(
sd_card,
crate::DummyTimeSource::default(),
))
};
Uferris::new(
led,
button,
buzzer_channel,
ldr_driver,
expander_i2c,
rtc_i2c,
raw_i2c,
#[cfg(feature = "power-board")]
vol_mgr,
#[cfg(feature = "power-board")]
ina_i2c,
)
.unwrap()
}
#[cfg(feature = "async")]
pub fn uferris_init_async(peripherals: Peripherals) -> (UferrisEsp32Async, EspRtosParts) {
let rtos_parts = EspRtosParts {
timg0: peripherals.TIMG0,
sw_interrupt: peripherals.SW_INTERRUPT,
};
let mut adc_config = AdcConfig::new();
let ldr_pin = adc_config.enable_pin(peripherals.GPIO0, Attenuation::_11dB);
let adc1 = Adc::new(peripherals.ADC1, adc_config).into_async();
let ldr_driver = LdrAdcAsync {
adc: adc1,
pin: ldr_pin,
};
let mut i2c = I2c::new(
peripherals.I2C0,
esp_hal::i2c::master::Config::default().with_frequency(Rate::from_khz(100)),
)
.unwrap()
.with_scl(peripherals.GPIO23)
.with_sda(peripherals.GPIO22);
IoExpander::<_, crate::Blocking>::new(&mut i2c)
.init()
.unwrap();
let i2c = i2c.into_async();
let i2c_bus_ref = ASYNC_I2C_BUS.init(AsyncMutex::new(i2c));
let expander_i2c = I2cAsyncDevice::new(i2c_bus_ref);
let rtc_i2c = I2cAsyncDevice::new(i2c_bus_ref);
let raw_i2c = I2cAsyncDevice::new(i2c_bus_ref);
let led = Output::new(peripherals.GPIO1, Level::Low, OutputConfig::default());
let button = Input::new(peripherals.GPIO21, InputConfig::default());
let mut ledc = esp_hal::ledc::Ledc::new(peripherals.LEDC);
ledc.set_global_slow_clock(esp_hal::ledc::LSGlobalClkSource::APBClk);
let mut buzzer_timer =
ledc.timer::<esp_hal::ledc::LowSpeed>(esp_hal::ledc::timer::Number::Timer0);
buzzer_timer
.configure(timer::config::Config {
duty: timer::config::Duty::Duty14Bit,
clock_source: timer::LSClockSource::APBClk,
frequency: Rate::from_hz(2700u32),
})
.unwrap();
let buzzer_timer_ref = BUZZER_TIMER.init(buzzer_timer);
let mut buzzer_channel =
ledc.channel(esp_hal::ledc::channel::Number::Channel0, peripherals.GPIO2);
buzzer_channel
.configure(esp_hal::ledc::channel::config::Config {
timer: buzzer_timer_ref,
duty_pct: 0,
drive_mode: esp_hal::gpio::DriveMode::PushPull,
})
.unwrap();
let uferris = Uferris::new_async_preinit(
led,
button,
buzzer_channel,
ldr_driver,
expander_i2c,
rtc_i2c,
raw_i2c,
);
(uferris, rtos_parts)
}