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