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::*;