nrf_sdc/lib.rs
1//! An interface for the Nordic SoftDevice Controller.
2//!
3//! This crate provides a high-level async API for the Nordic SoftDevice Controller, which is a closed-source
4//! Bluetooth Low Energy protocol stack.
5//!
6//! # Example
7//!
8//! The following example shows how to initialize and run the SoftDevice Controller.
9//!
10//! ```rust,no_run
11//! #![no_std]
12//! #![no_main]
13//! #![feature(type_alias_impl_trait)]
14//!
15//! use embassy_executor::Spawner;
16//! use embassy_nrf as _;
17//! use embassy_nrf::bind_interrupts;
18//! use embassy_nrf::rng::Rng;
19//! use nrf_mpsl::{MultiprotocolServiceLayer, Peripherals as MpslPeripherals, raw as mpsl_raw};
20//! use nrf_sdc::{self as sdc, raw as sdc_raw, SoftdeviceController, Peripherals as SdcPeripherals};
21//! use static_cell::StaticCell;
22//!
23//! bind_interrupts!(struct Irqs {
24//! SWI0_EGU0 => nrf_mpsl::LowPrioInterruptHandler;
25//! POWER_CLOCK => nrf_mpsl::ClockInterruptHandler;
26//! RADIO => nrf_mpsl::HighPrioInterruptHandler;
27//! TIMER0 => nrf_mpsl::HighPrioInterruptHandler;
28//! RTC0 => nrf_mpsl::HighPrioInterruptHandler;
29//! RNG => embassy_nrf::rng::InterruptHandler<embassy_nrf::peripherals::RNG>;
30//! });
31//!
32//! #[embassy_executor::main]
33//! async fn main(spawner: Spawner) -> ! {
34//! let p = embassy_nrf::init(Default::default());
35//!
36//! // Create the clock configuration
37//! let lfclk_cfg = mpsl_raw::mpsl_clock_lfclk_cfg_t {
38//! source: mpsl_raw::MPSL_CLOCK_LF_SRC_RC as u8,
39//! rc_ctiv: 16,
40//! rc_temp_ctiv: 2,
41//! accuracy_ppm: mpsl_raw::MPSL_CLOCK_LF_ACCURACY_500_PPM as u16,
42//! };
43//!
44//! // On nrf52 chips, the peripherals needed by MPSL are:
45//! // RTC0, TIMER0, TEMP, PPI_CH19, PPI_CH30, PPI_CH31
46//! // The list of peripherals is different for other chips.
47//! let mpsl_p = MpslPeripherals::new(
48//! p.RTC0,
49//! p.TIMER0,
50//! p.TEMP,
51//! p.PPI_CH19,
52//! p.PPI_CH30,
53//! p.PPI_CH31,
54//! );
55//!
56//! // Initialize the MPSL
57//! static MPSL: StaticCell<MultiprotocolServiceLayer> = StaticCell::new();
58//! let mpsl = MPSL.init(MultiprotocolServiceLayer::new(mpsl_p, Irqs, lfclk_cfg).unwrap());
59//!
60//! // On nrf52 chips, the peripherals needed by SDC are:
61//! // PPI_CH17, PPI_CH18, PPI_CH20..=PPI_CH29
62//! // The list of peripherals is different for other chips.
63//! let sdc_p = SdcPeripherals::new(
64//! p.PPI_CH17,
65//! p.PPI_CH18,
66//! p.PPI_CH20,
67//! p.PPI_CH21,
68//! p.PPI_CH22,
69//! p.PPI_CH23,
70//! p.PPI_CH24,
71//! p.PPI_CH25,
72//! p.PPI_CH26,
73//! p.PPI_CH27,
74//! p.PPI_CH28,
75//! p.PPI_CH29,
76//! );
77//!
78//! static RNG: StaticCell<Rng<embassy_nrf::peripherals::RNG>> = StaticCell::new();
79//! let mut rng = RNG.init(Rng::new(p.RNG, Irqs));
80//!
81//! // The minimum memory required for the SoftDevice Controller to run.
82//! const SDC_MEM_SIZE: usize = sdc_raw::SDC_MEM_SIZE_MIN as usize;
83//! static SDC_MEM: StaticCell<sdc::Mem<SDC_MEM_SIZE>> = StaticCell::new();
84//!
85//! // Initialize the SoftDevice Controller
86//! let sdc = sdc::Builder::new()
87//! .unwrap()
88//! .support_adv()
89//! .unwrap()
90//! .support_peripheral()
91//! .unwrap()
92//! .build(sdc_p, &mut rng, mpsl, SDC_MEM.init(sdc::Mem::new()))
93//! .unwrap();
94//!
95//! // Spawn the MPSL and SDC tasks
96//! spawner.must_spawn(mpsl_task(mpsl));
97//! spawner.must_spawn(sdc_task(sdc));
98//!
99//! // Your application logic can go here.
100//! loop {
101//! // Do something
102//! }
103//! }
104//!
105//! #[embassy_executor::task]
106//! async fn mpsl_task(mpsl: &'static MultiprotocolServiceLayer) -> ! {
107//! mpsl.run().await
108//! }
109//!
110//! #[embassy_executor::task]
111//! async fn sdc_task(sdc: &'static SoftdeviceController) -> ! {
112//! loop {
113//! let mut evt_buf = [0; sdc_raw::HCI_MSG_BUFFER_MAX_SIZE as usize];
114//! match sdc.hci_get(&mut evt_buf).await {
115//! Ok(_event) => {
116//! // Handle Bluetooth events
117//! }
118//! Err(e) => {
119//! // Handle errors
120//! core::panic!("sdc_task error: {:?}", e)
121//! }
122//! }
123//! }
124//! }
125//!
126//! #[panic_handler]
127//! fn panic(_info: &core::panic::PanicInfo) -> ! {
128//! loop {}
129//! }
130//! ```
131#![no_std]
132#![deny(missing_docs)]
133
134/// The error types, re-exported from `nrf-mpsl`.
135pub use mpsl::{Error, RetVal};
136/// Re-export of the `nrf-mpsl` and `nrf-sdc-sys` crates.
137pub use {nrf_mpsl as mpsl, nrf_sdc_sys as raw};
138
139// This mod MUST go first, so that the others see its macros.
140pub(crate) mod fmt;
141
142mod sdc;
143
144pub use sdc::*;