use super::*;
use std::collections::VecDeque;
use std::ptr::NonNull;
pub type AdcId = u8;
pub type AdcMillivolts = u32;
#[derive(Debug)]
pub struct Adc {
state: NonNull<AdcState>,
}
impl Adc {
pub unsafe fn new(avr: &Avr) -> Option<Self> {
let irq =
avr.try_io_getirq(IoCtl::AdcGetIrq, ffi::ADC_IRQ_OUT_TRIGGER)?;
let this = Self {
state: NonNull::from(Box::leak(Default::default())),
};
unsafe {
Avr::irq_register_notify(
irq,
Some(Self::on_adc_ready),
this.state.as_ptr(),
);
}
Some(this)
}
pub fn set_voltage(&mut self, id: AdcId, voltage: AdcMillivolts) {
self.state_mut().voltages.push_back((id, voltage));
}
fn state_mut(&mut self) -> &mut AdcState {
unsafe { self.state.as_mut() }
}
unsafe extern "C" fn on_adc_ready(
irq: NonNull<ffi::avr_irq_t>,
_: u32,
mut state: NonNull<AdcState>,
) {
unsafe {
let (adc_id, adc_voltage) =
if let Some(voltage) = state.as_mut().voltages.pop_front() {
voltage
} else {
return;
};
let irq = irq
.as_ptr()
.sub(ffi::ADC_IRQ_OUT_TRIGGER as _)
.add(adc_id as _);
ffi::avr_raise_irq(irq, adc_voltage);
}
}
}
impl Drop for Adc {
fn drop(&mut self) {
unsafe {
drop(Box::from_raw(self.state.as_ptr()));
}
}
}
#[derive(Default)]
struct AdcState {
voltages: VecDeque<(AdcId, AdcMillivolts)>,
}