use core::cell::RefCell;
use embedded_hal::pwm::{ErrorType as PwmErrorType, SetDutyCycle};
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,
peripherals::{GPIO1, 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 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<GPIO1<'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<GPIO1<'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
}
}
const STUB_BUZZER_MAX_DUTY: u16 = 16384;
pub struct StubBuzzer {
_pin: Output<'static>,
}
impl PwmErrorType for StubBuzzer {
type Error = core::convert::Infallible;
}
impl SetDutyCycle for StubBuzzer {
fn max_duty_cycle(&self) -> u16 {
STUB_BUZZER_MAX_DUTY
}
fn set_duty_cycle(&mut self, _duty: u16) -> Result<(), Self::Error> {
Ok(())
}
}
#[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>, StubBuzzer, SharedI2c, LdrAdc<'static>, (),
>;
#[cfg(feature = "power-board")]
pub type UferrisEsp32 = Uferris<
Output<'static>, Input<'static>, StubBuzzer, SharedI2c, LdrAdc<'static>, SdBlockDevice, >;
#[cfg(all(feature = "async", not(feature = "power-board")))]
pub type UferrisEsp32Async = Uferris<
Output<'static>, Input<'static>, StubBuzzer, SharedAsyncI2c, LdrAdcAsync<'static>, (),
Async,
>;
#[cfg(all(feature = "async", feature = "power-board"))]
pub type UferrisEsp32Async = Uferris<
Output<'static>, Input<'static>, StubBuzzer, 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.GPIO1, 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.GPIO24)
.with_sda(peripherals.GPIO23);
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.GPIO0, Level::Low, OutputConfig::default());
let button = Input::new(peripherals.GPIO7, InputConfig::default());
let buzzer_channel = StubBuzzer {
_pin: Output::new(peripherals.GPIO25, Level::Low, OutputConfig::default()),
};
#[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.GPIO8)
.with_miso(peripherals.GPIO9)
.with_mosi(peripherals.GPIO10);
let spi_bus_ref = SPI_BUS.init(RefCell::new(spi));
let sd_cs = Output::new(peripherals.GPIO12, 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.GPIO1, 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.GPIO24)
.with_sda(peripherals.GPIO23);
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.GPIO0, Level::Low, OutputConfig::default());
let button = Input::new(peripherals.GPIO7, InputConfig::default());
let buzzer_channel = StubBuzzer {
_pin: Output::new(peripherals.GPIO25, Level::Low, OutputConfig::default()),
};
let uferris = Uferris::new_async_preinit(
led,
button,
buzzer_channel,
ldr_driver,
expander_i2c,
rtc_i2c,
raw_i2c,
);
(uferris, rtos_parts)
}