use quote::{format_ident, quote};
use rmk_config::{ChipModel, ChipSeries, Pmw3610Config};
use super::Initializer;
pub(crate) fn expand_pmw3610_device(
pmw3610_config: Vec<Pmw3610Config>,
chip: &ChipModel,
) -> (Vec<Initializer>, Vec<Initializer>) {
if pmw3610_config.is_empty() {
return (Vec::new(), Vec::new());
}
match chip.series {
ChipSeries::Nrf52 | ChipSeries::Rp2040 => {}
_ => {
panic!("PMW3610 is only supported on nRF52 and RP2040 chips");
}
}
let mut device_initializers = vec![];
let mut processor_initializers = vec![];
for (idx, sensor) in pmw3610_config.iter().enumerate() {
let sensor_name = if sensor.name.is_empty() {
format!("pmw3610_{}", idx)
} else {
sensor.name.clone()
};
let device_ident = format_ident!("{}_device", sensor_name);
let processor_ident = format_ident!("{}_processor", sensor_name);
let spi = &sensor.spi;
let mosi_pin = &spi.mosi;
let miso_pin = &spi.miso;
if mosi_pin.is_empty() && miso_pin.is_empty() {
panic!("pmw3610 requires at least one of spi.mosi or spi.miso");
}
if !(mosi_pin == miso_pin || mosi_pin.is_empty() || miso_pin.is_empty()) {
panic!("pmw3610 requires spi.mosi == spi.miso, or one of them empty");
}
let sdio_pin = if mosi_pin.is_empty() { miso_pin } else { mosi_pin };
let sck_ident = format_ident!("{}", spi.sck);
let sdio_ident = format_ident!("{}", sdio_pin);
let cs_ident = format_ident!("{}", spi.cs.as_ref().expect("pmw3610 requires `cs` in spi config"));
let res_cpi: i16 = sensor.cpi.map(|c| c as i16).unwrap_or(-1);
let invert_x = sensor.invert_x;
let invert_y = sensor.invert_y;
let swap_xy = sensor.swap_xy;
let force_awake = sensor.force_awake;
let smart_mode = sensor.smart_mode;
let motion_pin_init = if let Some(motion_pin) = &sensor.motion {
let motion_ident = format_ident!("{}", motion_pin);
match chip.series {
ChipSeries::Nrf52 => quote! {
Some(::embassy_nrf::gpio::Input::new(p.#motion_ident, ::embassy_nrf::gpio::Pull::Up))
},
ChipSeries::Rp2040 => quote! {
Some(::embassy_rp::gpio::Input::new(p.#motion_ident, ::embassy_rp::gpio::Pull::Up))
},
_ => unreachable!(),
}
} else {
match chip.series {
ChipSeries::Nrf52 => quote! {
None::<::embassy_nrf::gpio::Input<'static>>
},
ChipSeries::Rp2040 => quote! {
None::<::embassy_rp::gpio::Input<'static>>
},
_ => unreachable!(),
}
};
let device_init = match chip.series {
ChipSeries::Nrf52 => quote! {
let mut #device_ident = {
use ::embassy_nrf::gpio::{Output, Flex, Level, OutputDrive};
use ::rmk::input_device::pmw3610::{BitBangSpiBus, Pmw3610Config, Pmw3610Device};
let sck = Output::new(p.#sck_ident, Level::High, OutputDrive::Standard);
let sdio = Flex::new(p.#sdio_ident);
let cs = Output::new(p.#cs_ident, Level::High, OutputDrive::Standard);
let motion = #motion_pin_init;
let spi_bus = BitBangSpiBus::new(sck, sdio);
let config = Pmw3610Config {
res_cpi: #res_cpi,
invert_x: #invert_x,
invert_y: #invert_y,
swap_xy: #swap_xy,
force_awake: #force_awake,
smart_mode: #smart_mode,
};
Pmw3610Device::new(spi_bus, cs, motion, config)
};
},
ChipSeries::Rp2040 => quote! {
let mut #device_ident = {
use ::embassy_rp::gpio::{Output, Flex, Level};
use ::rmk::input_device::pmw3610::{BitBangSpiBus, Pmw3610Config, Pmw3610Device};
let sck = Output::new(p.#sck_ident, Level::High);
let sdio = Flex::new(p.#sdio_ident);
let cs = Output::new(p.#cs_ident, Level::High);
let motion = #motion_pin_init;
let spi_bus = BitBangSpiBus::new(sck, sdio);
let config = Pmw3610Config {
res_cpi: #res_cpi,
invert_x: #invert_x,
invert_y: #invert_y,
swap_xy: #swap_xy,
force_awake: #force_awake,
smart_mode: #smart_mode,
};
Pmw3610Device::new(spi_bus, cs, motion, config)
};
},
_ => unreachable!(),
};
device_initializers.push(Initializer {
initializer: device_init,
var_name: device_ident,
});
let processor_init = quote! {
let mut #processor_ident = ::rmk::input_device::pmw3610::Pmw3610Processor::new(&keymap);
};
processor_initializers.push(Initializer {
initializer: processor_init,
var_name: processor_ident,
});
}
(device_initializers, processor_initializers)
}