use darling::FromMeta;
use proc_macro2::TokenStream as TokenStream2;
use quote::{ToTokens, quote};
use rmk_config::{BoardConfig, ChipModel, ChipSeries, CommunicationConfig, KeyboardTomlConfig};
use syn::{ItemFn, ItemMod};
use crate::keyboard::Overwritten;
pub(crate) fn expand_chip_init(
keyboard_config: &KeyboardTomlConfig,
peripheral_id: Option<usize>,
item_mod: &ItemMod,
) -> TokenStream2 {
if let Some((_, items)) = &item_mod.content {
items
.iter()
.find_map(|item| {
if let syn::Item::Fn(item_fn) = &item
&& item_fn.attrs.len() == 1
{
match Overwritten::from_meta(&item_fn.attrs[0].meta) {
Ok(Overwritten::ChipConfig) => {
return Some(override_chip_config(
&keyboard_config.get_chip_model().unwrap(),
item_fn,
));
}
Ok(Overwritten::ChipInit) => {
let stmts = &item_fn.block.stmts;
return Some(quote! { #(#stmts)* });
}
_ => (),
}
}
None
})
.unwrap_or(chip_init_default(keyboard_config, peripheral_id))
} else {
chip_init_default(keyboard_config, peripheral_id)
}
}
pub(crate) fn chip_init_default(keyboard_config: &KeyboardTomlConfig, peripheral_id: Option<usize>) -> TokenStream2 {
let chip = keyboard_config.get_chip_model().unwrap();
let communication = keyboard_config.get_communication_config().unwrap();
let peri_num = keyboard_config.get_board_config().unwrap().get_num_periphreal();
match chip.series {
ChipSeries::Stm32 => quote! {
let config = ::embassy_stm32::Config::default();
let mut p = ::embassy_stm32::init(config);
},
ChipSeries::Nrf52 => {
let chip_cfg = keyboard_config.get_chip_config();
let dcdc_config = if chip.chip == "nrf52840" {
let reg0_enabled = chip_cfg.dcdc_reg0.unwrap_or(true);
let reg1_enabled = chip_cfg.dcdc_reg1.unwrap_or(true);
let reg0_voltage_str = chip_cfg.dcdc_reg0_voltage.as_deref().unwrap_or("3V3");
let reg0_voltage = match reg0_voltage_str {
"3V3" => quote! { ::embassy_nrf::config::Reg0Voltage::_3V3 },
"1V8" => quote! { ::embassy_nrf::config::Reg0Voltage::_1V8 },
_ => {
panic!(
"Invalid dcdc_reg0_voltage: {}. Must be \"3V3\" or \"1V8\"",
reg0_voltage_str
);
}
};
quote! {
config.dcdc.reg0_voltage = Some(#reg0_voltage);
config.dcdc.reg0 = #reg0_enabled;
config.dcdc.reg1 = #reg1_enabled;
::defmt::info!("DCDC config: reg0_voltage={}, reg0={}, reg1={}", #reg0_voltage_str, #reg0_enabled, #reg1_enabled);
}
} else if chip.chip == "nrf52833" {
let reg1_enabled = chip_cfg.dcdc_reg1.unwrap_or(true);
quote! {
config.dcdc.reg1 = #reg1_enabled;
::defmt::info!("DCDC config: reg1={}", #reg1_enabled);
}
} else {
quote! {}
};
let ble_addr = get_ble_addr(keyboard_config, peripheral_id);
let sdc_mem_size = if peripheral_id.is_none() {
4096 + peri_num * 2304
} else {
6144
};
let ble_init = match &communication {
CommunicationConfig::Ble(_) | CommunicationConfig::Both(_, _) => quote! {
let mpsl_p = ::nrf_sdc::mpsl::Peripherals::new(p.RTC0, p.TIMER0, p.TEMP, p.PPI_CH19, p.PPI_CH30, p.PPI_CH31);
let lfclk_cfg = ::nrf_sdc::mpsl::raw::mpsl_clock_lfclk_cfg_t {
source: ::nrf_sdc::mpsl::raw::MPSL_CLOCK_LF_SRC_RC as u8,
rc_ctiv: ::nrf_sdc::mpsl::raw::MPSL_RECOMMENDED_RC_CTIV as u8,
rc_temp_ctiv: ::nrf_sdc::mpsl::raw::MPSL_RECOMMENDED_RC_TEMP_CTIV as u8,
accuracy_ppm: ::nrf_sdc::mpsl::raw::MPSL_DEFAULT_CLOCK_ACCURACY_PPM as u16,
skip_wait_lfclk_started: ::nrf_sdc::mpsl::raw::MPSL_DEFAULT_SKIP_WAIT_LFCLK_STARTED != 0,
};
static MPSL: ::static_cell::StaticCell<::nrf_sdc::mpsl::MultiprotocolServiceLayer> = ::static_cell::StaticCell::new();
static SESSION_MEM: ::static_cell::StaticCell<::nrf_sdc::mpsl::SessionMem<1>> = ::static_cell::StaticCell::new();
let mpsl = MPSL.init(::defmt::unwrap!(::nrf_sdc::mpsl::MultiprotocolServiceLayer::with_timeslots(
mpsl_p,
Irqs,
lfclk_cfg,
SESSION_MEM.init(::nrf_sdc::mpsl::SessionMem::new())
)));
spawner.must_spawn(mpsl_task(&*mpsl));
let sdc_p = ::nrf_sdc::Peripherals::new(
p.PPI_CH17, p.PPI_CH18, p.PPI_CH20, p.PPI_CH21, p.PPI_CH22, p.PPI_CH23, p.PPI_CH24, p.PPI_CH25, p.PPI_CH26,
p.PPI_CH27, p.PPI_CH28, p.PPI_CH29,
);
let mut rng = ::embassy_nrf::rng::Rng::new(p.RNG, Irqs);
use rand_core::SeedableRng;
let mut rng_gen = ::rand_chacha::ChaCha12Rng::from_rng(&mut rng).unwrap();
let mut sdc_mem = ::nrf_sdc::Mem::<#sdc_mem_size>::new();
let sdc = ::defmt::unwrap!(build_sdc(sdc_p, &mut rng, &*mpsl, &mut sdc_mem));
let ble_addr = #ble_addr;
let mut host_resources = ::rmk::HostResources::new();
let stack = ::rmk::ble::build_ble_stack(sdc, ble_addr, &mut rng_gen, &mut host_resources).await;
},
_ => quote! {},
};
quote! {
use embassy_nrf::interrupt::InterruptExt;
let mut config = ::embassy_nrf::config::Config::default();
#dcdc_config
let p = ::embassy_nrf::init(config);
#ble_init
}
}
ChipSeries::Rp2040 => {
let ble_addr = get_ble_addr(keyboard_config, peripheral_id);
if communication.ble_enabled() {
quote! {
let config = ::embassy_rp::config::Config::default();
let p = ::embassy_rp::init(config);
#[cfg(feature = "skip-cyw43-firmware")]
let (fw, clm, btfw) = (&[], &[], &[]);
#[cfg(not(feature = "skip-cyw43-firmware"))]
let (fw, clm, btfw) = {
let fw = include_bytes!("../cyw43-firmware/43439A0.bin");
let clm = include_bytes!("../cyw43-firmware/43439A0_clm.bin");
let btfw = include_bytes!("../cyw43-firmware/43439A0_btfw.bin");
(fw, clm, btfw)
};
let pwr = ::embassy_rp::gpio::Output::new(p.PIN_23, ::embassy_rp::gpio::Level::Low);
let cs = ::embassy_rp::gpio::Output::new(p.PIN_25, ::embassy_rp::gpio::Level::High);
let mut pio = ::embassy_rp::pio::Pio::new(p.PIO0, Irqs);
let spi = ::cyw43_pio::PioSpi::new(
&mut pio.common,
pio.sm0,
::cyw43_pio::DEFAULT_CLOCK_DIVIDER,
pio.irq0,
cs,
p.PIN_24,
p.PIN_29,
p.DMA_CH0,
);
static STATE: ::static_cell::StaticCell<::cyw43::State> = ::static_cell::StaticCell::new();
let state = STATE.init(::cyw43::State::new());
let (_net_device, bt_device, mut control, runner) = ::cyw43::new_with_bluetooth(state, pwr, spi, fw, btfw).await;
spawner.spawn(cyw43_task(runner)).unwrap();
control.init(clm).await;
let controller: ::bt_hci::controller::ExternalController<_, 10> = ::bt_hci::controller::ExternalController::new(bt_device);
let ble_addr = #ble_addr;
let mut host_resources = ::rmk::HostResources::new();
let mut rosc_rng = ::embassy_rp::clocks::RoscRng {};
use rand_core::SeedableRng;
let mut rng = ::rand_chacha::ChaCha12Rng::from_rng(&mut rosc_rng).unwrap();
let stack = ::rmk::ble::build_ble_stack(controller, ble_addr, &mut rng, &mut host_resources).await;
}
} else {
quote! {
let config = ::embassy_rp::config::Config::default();
let p = ::embassy_rp::init(config);
}
}
}
ChipSeries::Esp32 => {
let ble_addr = get_ble_addr(keyboard_config, peripheral_id);
quote! {
::esp_println::logger::init_logger_from_env();
let p = ::esp_hal::init(::esp_hal::Config::default().with_cpu_clock(::esp_hal::clock::CpuClock::max()));
::esp_alloc::heap_allocator!(size: 72 * 1024);
let timg0 = ::esp_hal::timer::timg::TimerGroup::new(p.TIMG0);
#[cfg(target_arch = "riscv32")]
let software_interrupt = ::esp_hal::interrupt::software::SoftwareInterruptControl::new(p.SW_INTERRUPT);
::esp_rtos::start(
timg0.timer0,
#[cfg(target_arch = "riscv32")]
software_interrupt.software_interrupt0
);
let _trng_source = ::esp_hal::rng::TrngSource::new(p.RNG, p.ADC1);
let mut rng = ::esp_hal::rng::Trng::try_new().unwrap();
static RADIO: ::static_cell::StaticCell<::esp_radio::Controller<'static>> = ::static_cell::StaticCell::new();
let radio = RADIO.init(::esp_radio::init().unwrap());
let bluetooth = p.BT;
let connector = ::esp_radio::ble::controller::BleConnector::new(radio, bluetooth, Default::default()).unwrap();
let controller: ::bt_hci::controller::ExternalController<_, 64> = ::bt_hci::controller::ExternalController::new(connector);
let ble_addr = #ble_addr;
let mut host_resources = ::rmk::HostResources::new();
let stack = ::rmk::ble::build_ble_stack(controller, ble_addr, &mut rng, &mut host_resources).await;
}
}
}
}
fn override_chip_config(chip: &ChipModel, item_fn: &ItemFn) -> TokenStream2 {
let initialization = item_fn.block.to_token_stream();
let mut initialization_tokens = quote! {
let config = #initialization;
};
match chip.series {
ChipSeries::Stm32 => initialization_tokens.extend(quote! {
let mut p = ::embassy_stm32::init(config);
}),
ChipSeries::Nrf52 => initialization_tokens.extend(quote! {
let mut p = ::embassy_nrf::init(config);
}),
ChipSeries::Rp2040 => initialization_tokens.extend(quote! {
let mut p = ::embassy_rp::init(config);
}),
ChipSeries::Esp32 => initialization_tokens.extend(quote! {
let p = ::esp_hal::init(::esp_hal::Config::default().with_cpu_clock(::esp_hal::clock::CpuClock::max()));
}),
}
initialization_tokens
}
fn get_ble_addr(keyboard_config: &KeyboardTomlConfig, peripheral_id: Option<usize>) -> TokenStream2 {
let chip = keyboard_config.get_chip_model().unwrap();
if chip.series == ChipSeries::Nrf52 {
quote! {
{
let ficr = ::embassy_nrf::pac::FICR;
let high = u64::from(ficr.deviceid(1).read());
let addr = high << 32 | u64::from(ficr.deviceid(0).read());
let addr = addr | 0x0000_c000_0000_0000;
let ble_addr = addr.to_le_bytes()[..6].try_into().expect("Failed to read BLE address from FICR");
ble_addr
}
}
} else {
let board = keyboard_config.get_board_config().unwrap();
let addr = match board {
BoardConfig::Split(split) => {
match peripheral_id {
Some(id) => {
let default_addr = [0x7e, 0xfe, 0x73, id as u8, 0x66, 0xe3];
split
.peripheral
.get(id)
.unwrap_or_else(|| panic!("There's no config for peripheral {}", id))
.ble_addr
.unwrap_or(default_addr)
}
None => {
let default_addr = [0x18, 0xe2, 0x21, 0x80, 0xc0, 0xc7];
split.central.ble_addr.unwrap_or(default_addr)
}
}
}
BoardConfig::UniBody(_uni_body) => [0x18, 0xe2, 0x21, 0x80, 0xc0, 0xc7],
};
quote! {
[
#(#addr),*
]
}
}
}