1use embassy_nrf::interrupt::typelevel::{Binding, Interrupt};
2use embassy_nrf::peripherals::RNG;
3use embassy_nrf::rng::{InterruptHandler, Rng};
4use embassy_nrf::{interrupt, rng};
5use nrf_sdc::mpsl::{
6 ClockInterruptHandler, HighPrioInterruptHandler, LowPrioInterruptHandler,
7 MultiprotocolServiceLayer,
8};
9use nrf_sdc::{self as sdc, mpsl};
10use rktk::singleton;
11use static_cell::StaticCell;
12
13pub use mpsl::Peripherals as MpslPeripherals;
14pub use sdc::Peripherals as SdcPeripherals;
15
16#[derive(Debug)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub enum SdcInitError {
19 Mpsl(mpsl::Error),
20 Sdc(sdc::Error),
21}
22
23#[macro_export]
24macro_rules! init_sdc {
25 (
26 $sdc_name:ident,
27 $irqs:expr,
28 $rng:expr,
29 mpsl: ($rtc0:expr, $timer0:expr, $temp:expr, $ppi1:expr, $ppi2:expr, $ppi3:expr),
30 sdc: ($ppis1:expr,$ppis2:expr,$ppis3:expr,$ppis4:expr,$ppis5:expr,$ppis6:expr,$ppis7:expr,$ppis8:expr,$ppis9:expr,$ppis10:expr,$ppis11:expr,$ppis12:expr),
31 mtu: $l2cap_mtu:expr,
32 txq: $l2cap_txq:expr,
33 rxq: $l2cap_rxq:expr
34 ) => {
35 let __mpsl_p =
36 $crate::sdc::MpslPeripherals::new($rtc0, $timer0, $temp, $ppi1, $ppi2, $ppi3);
37 let __sdc_p = $crate::sdc::SdcPeripherals::new(
38 $ppis1, $ppis2, $ppis3, $ppis4, $ppis5, $ppis6, $ppis7, $ppis8, $ppis9, $ppis10,
39 $ppis11, $ppis12,
40 );
41 let $sdc_name = $crate::sdc::init_sdc(
42 __mpsl_p, __sdc_p, $rng, $l2cap_mtu, $l2cap_txq, $l2cap_rxq, $irqs,
43 )
44 .await;
45 };
46}
47
48#[embassy_executor::task]
49async fn mpsl_task(mpsl: &'static MultiprotocolServiceLayer<'static>) -> ! {
50 mpsl.run().await
51}
52
53pub async fn init_sdc<
57 T: Interrupt,
58 I: Binding<T, LowPrioInterruptHandler>
59 + Binding<interrupt::typelevel::RADIO, HighPrioInterruptHandler>
60 + Binding<interrupt::typelevel::TIMER0, HighPrioInterruptHandler>
61 + Binding<interrupt::typelevel::RTC0, HighPrioInterruptHandler>
62 + Binding<interrupt::typelevel::CLOCK_POWER, ClockInterruptHandler>
63 + Binding<interrupt::typelevel::RNG, InterruptHandler<RNG>>
64 + 'static
65 + Clone,
66 PR: rng::Instance,
67>(
68 mpsl_peripherals: mpsl::Peripherals<'static>,
69 sdc_peripherals: sdc::Peripherals<'static>,
70 rng: &'static mut Rng<'static, PR>,
71 l2cap_mtu: u8,
72 l2cap_txq: u8,
73 l2cap_rxq: u8,
74 irqs: I,
75) -> Result<nrf_sdc::SoftdeviceController<'static>, mpsl::Error> {
76 let lfclk_cfg = mpsl::raw::mpsl_clock_lfclk_cfg_t {
77 source: mpsl::raw::MPSL_CLOCK_LF_SRC_RC as u8,
78 rc_ctiv: mpsl::raw::MPSL_RECOMMENDED_RC_CTIV as u8,
79 rc_temp_ctiv: mpsl::raw::MPSL_RECOMMENDED_RC_TEMP_CTIV as u8,
80 accuracy_ppm: mpsl::raw::MPSL_DEFAULT_CLOCK_ACCURACY_PPM as u16,
81 skip_wait_lfclk_started: mpsl::raw::MPSL_DEFAULT_SKIP_WAIT_LFCLK_STARTED != 0,
82 };
83 static MPSL: StaticCell<MultiprotocolServiceLayer> = StaticCell::new();
84 let mpsl = MPSL.init(mpsl::MultiprotocolServiceLayer::new(
85 mpsl_peripherals,
86 irqs.clone(),
87 lfclk_cfg,
88 )?);
89
90 embassy_executor::Spawner::for_current_executor()
91 .await
92 .must_spawn(mpsl_task(&*mpsl));
93
94 let sdc_mem = singleton!(sdc::Mem::<3312>::new(), sdc::Mem::<3312>);
95
96 let sdc = sdc::Builder::new()?
97 .support_adv()?
98 .support_peripheral()?
99 .peripheral_count(1)?
100 .buffer_cfg(l2cap_mtu, l2cap_mtu, l2cap_txq, l2cap_rxq)?
101 .build(sdc_peripherals, rng, mpsl, sdc_mem)?;
102
103 Ok(sdc)
104}