nrf_sdc/
sdc.rs

1use core::cell::RefCell;
2use core::ffi::CStr;
3use core::future::poll_fn;
4use core::marker::PhantomData;
5use core::mem::MaybeUninit;
6use core::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
7use core::task::{Poll, Waker};
8
9use bt_hci::cmd::le::LeSetPeriodicAdvResponseData;
10use bt_hci::cmd::Cmd;
11use bt_hci::controller::blocking::TryError;
12use bt_hci::controller::{blocking, Controller};
13use bt_hci::event::EventParams;
14use bt_hci::{AsHciBytes, FixedSizeValue, FromHciBytes, WriteHci};
15use embassy_nrf::{peripherals, Peri};
16use embassy_sync::blocking_mutex::raw::NoopRawMutex;
17use embassy_sync::signal::Signal;
18use embassy_sync::waitqueue::AtomicWaker;
19use embedded_io::ErrorType;
20use nrf_mpsl::MultiprotocolServiceLayer;
21use rand_core::CryptoRng;
22use raw::{
23    sdc_cfg_adv_buffer_cfg_t, sdc_cfg_buffer_cfg_t, sdc_cfg_buffer_count_t, sdc_cfg_role_count_t, sdc_cfg_t,
24    SDC_CFG_TYPE_NONE, SDC_DEFAULT_RESOURCE_CFG_TAG,
25};
26
27use crate::{raw, Error, RetVal};
28
29static WAKER: AtomicWaker = AtomicWaker::new();
30static SDC_RNG: AtomicPtr<()> = AtomicPtr::new(core::ptr::null_mut());
31
32/// Peripherals required for the SoftDevice Controller.
33///
34/// This is used to enforce at compile-time that the application does not use
35/// any peripherals that are required by the SDC.
36///
37/// In addition, the application must not use any of the following peripherals directly:
38///
39/// - `CCM`
40/// - `AAR`
41/// - `NVMC`
42///
43/// `NVMC` may be used via the `Flash` implementation in the `nrf-mpsl` crate, which
44/// synchronizes access to the flash with the MPSL timeslot API.
45#[cfg(feature = "nrf52")]
46pub struct Peripherals<'d> {
47    /// PPI channel 17.
48    pub ppi_ch17: Peri<'d, peripherals::PPI_CH17>,
49    /// PPI channel 18.
50    pub ppi_ch18: Peri<'d, peripherals::PPI_CH18>,
51    /// PPI channel 20.
52    pub ppi_ch20: Peri<'d, peripherals::PPI_CH20>,
53    /// PPI channel 21.
54    pub ppi_ch21: Peri<'d, peripherals::PPI_CH21>,
55    /// PPI channel 22.
56    pub ppi_ch22: Peri<'d, peripherals::PPI_CH22>,
57    /// PPI channel 23.
58    pub ppi_ch23: Peri<'d, peripherals::PPI_CH23>,
59    /// PPI channel 24.
60    pub ppi_ch24: Peri<'d, peripherals::PPI_CH24>,
61    /// PPI channel 25.
62    pub ppi_ch25: Peri<'d, peripherals::PPI_CH25>,
63    /// PPI channel 26.
64    pub ppi_ch26: Peri<'d, peripherals::PPI_CH26>,
65    /// PPI channel 27.
66    pub ppi_ch27: Peri<'d, peripherals::PPI_CH27>,
67    /// PPI channel 28.
68    pub ppi_ch28: Peri<'d, peripherals::PPI_CH28>,
69    /// PPI channel 29.
70    pub ppi_ch29: Peri<'d, peripherals::PPI_CH29>,
71}
72#[cfg(feature = "nrf53")]
73/// Peripherals required for the SoftDevice Controller.
74///
75/// This is used to enforce at compile-time that the application does not use
76/// any peripherals that are required by the SDC.
77///
78/// # Panics
79///
80/// The following hardware restrictions must be followed. Panics may occur if they are not.
81///
82/// - Do not use the `CCM`, `AAR`, or `NVMC` peripherals directly.
83pub struct Peripherals<'d> {
84    /// PPI channel 3.
85    pub ppi_ch3: Peri<'d, peripherals::PPI_CH3>,
86    /// PPI channel 4.
87    pub ppi_ch4: Peri<'d, peripherals::PPI_CH4>,
88    /// PPI channel 5.
89    pub ppi_ch5: Peri<'d, peripherals::PPI_CH5>,
90    /// PPI channel 6.
91    pub ppi_ch6: Peri<'d, peripherals::PPI_CH6>,
92    /// PPI channel 7.
93    pub ppi_ch7: Peri<'d, peripherals::PPI_CH7>,
94    /// PPI channel 8.
95    pub ppi_ch8: Peri<'d, peripherals::PPI_CH8>,
96    /// PPI channel 9.
97    pub ppi_ch9: Peri<'d, peripherals::PPI_CH9>,
98    /// PPI channel 10.
99    pub ppi_ch10: Peri<'d, peripherals::PPI_CH10>,
100    /// PPI channel 11.
101    pub ppi_ch11: Peri<'d, peripherals::PPI_CH11>,
102    /// PPI channel 12.
103    pub ppi_ch12: Peri<'d, peripherals::PPI_CH12>,
104}
105
106impl<'d> Peripherals<'d> {
107    /// Creates a new `Peripherals` instance for nRF52 series devices.
108    #[allow(clippy::too_many_arguments)]
109    #[cfg(feature = "nrf52")]
110    pub fn new(
111        ppi_ch17: Peri<'d, peripherals::PPI_CH17>,
112        ppi_ch18: Peri<'d, peripherals::PPI_CH18>,
113        ppi_ch20: Peri<'d, peripherals::PPI_CH20>,
114        ppi_ch21: Peri<'d, peripherals::PPI_CH21>,
115        ppi_ch22: Peri<'d, peripherals::PPI_CH22>,
116        ppi_ch23: Peri<'d, peripherals::PPI_CH23>,
117        ppi_ch24: Peri<'d, peripherals::PPI_CH24>,
118        ppi_ch25: Peri<'d, peripherals::PPI_CH25>,
119        ppi_ch26: Peri<'d, peripherals::PPI_CH26>,
120        ppi_ch27: Peri<'d, peripherals::PPI_CH27>,
121        ppi_ch28: Peri<'d, peripherals::PPI_CH28>,
122        ppi_ch29: Peri<'d, peripherals::PPI_CH29>,
123    ) -> Self {
124        Peripherals {
125            ppi_ch17,
126            ppi_ch18,
127            ppi_ch20,
128            ppi_ch21,
129            ppi_ch22,
130            ppi_ch23,
131            ppi_ch24,
132            ppi_ch25,
133            ppi_ch26,
134            ppi_ch27,
135            ppi_ch28,
136            ppi_ch29,
137        }
138    }
139
140    /// Creates a new `Peripherals` instance for nRF53 series devices.
141    #[allow(clippy::too_many_arguments)]
142    #[cfg(feature = "nrf53")]
143    pub fn new(
144        ppi_ch3: Peri<'d, peripherals::PPI_CH3>,
145        ppi_ch4: Peri<'d, peripherals::PPI_CH4>,
146        ppi_ch5: Peri<'d, peripherals::PPI_CH5>,
147        ppi_ch6: Peri<'d, peripherals::PPI_CH6>,
148        ppi_ch7: Peri<'d, peripherals::PPI_CH7>,
149        ppi_ch8: Peri<'d, peripherals::PPI_CH8>,
150        ppi_ch9: Peri<'d, peripherals::PPI_CH9>,
151        ppi_ch10: Peri<'d, peripherals::PPI_CH10>,
152        ppi_ch11: Peri<'d, peripherals::PPI_CH11>,
153        ppi_ch12: Peri<'d, peripherals::PPI_CH12>,
154    ) -> Self {
155        Peripherals {
156            ppi_ch3,
157            ppi_ch4,
158            ppi_ch5,
159            ppi_ch6,
160            ppi_ch7,
161            ppi_ch8,
162            ppi_ch9,
163            ppi_ch10,
164            ppi_ch11,
165            ppi_ch12,
166        }
167    }
168}
169
170unsafe extern "C" fn fault_handler(file: *const core::ffi::c_char, line: u32) {
171    panic!(
172        "SoftdeviceController: {}:{}",
173        // SAFETY: the SDC should always give us valid utf8 strings.
174        unsafe { core::str::from_utf8_unchecked(CStr::from_ptr(file).to_bytes()) },
175        line
176    )
177}
178
179extern "C" fn sdc_callback() {
180    WAKER.wake()
181}
182
183/// SAFETY: This function must only be called while a `SoftdeviceController` instance
184/// is alive, with the same type parameter as was passed to `Builder::build`, and must
185/// be synchronized with other MPSL accesses.
186///
187/// The softdevice controller calls this function exclusively from `mpsl_low_priority_process`,
188/// which is appropriately synchronized.
189unsafe extern "C" fn rand_blocking<R: CryptoRng + Send>(p_buff: *mut u8, length: u8) {
190    let rng = SDC_RNG.load(Ordering::Acquire) as *mut R;
191    if rng.is_null() {
192        panic!("rand_blocking called from Softdevice Controller when no rng is set");
193    }
194    let buf = core::slice::from_raw_parts_mut(p_buff, usize::from(length));
195    (*rng).fill_bytes(buf);
196}
197
198/// The memory required by the SoftDevice Controller.
199///
200/// The required size of this buffer is determined by the configuration of the SoftDevice Controller.
201#[repr(align(8))]
202pub struct Mem<const N: usize>(MaybeUninit<[u8; N]>);
203
204impl<const N: usize> Mem<N> {
205    /// Creates a new `Mem` instance.
206    pub fn new() -> Self {
207        Self(MaybeUninit::uninit())
208    }
209}
210
211impl<const N: usize> Default for Mem<N> {
212    fn default() -> Self {
213        Self::new()
214    }
215}
216
217/// A builder for the SoftDevice Controller.
218pub struct Builder {
219    // Prevent Send, Sync
220    _private: PhantomData<*mut ()>,
221}
222
223impl Builder {
224    /// Creates a new `Builder` instance.
225    pub fn new() -> Result<Self, Error> {
226        let ret = unsafe { raw::sdc_init(Some(fault_handler)) };
227        RetVal::from(ret).to_result().and(Ok(Builder { _private: PhantomData }))
228    }
229
230    /// Sets the number of central links.
231    pub fn central_count(self, count: u8) -> Result<Self, Error> {
232        self.cfg_set(
233            raw::SDC_CFG_TYPE_CENTRAL_COUNT,
234            sdc_cfg_t {
235                central_count: sdc_cfg_role_count_t { count },
236            },
237        )
238    }
239
240    /// Sets the number of peripheral links.
241    pub fn peripheral_count(self, count: u8) -> Result<Self, Error> {
242        self.cfg_set(
243            raw::SDC_CFG_TYPE_PERIPHERAL_COUNT,
244            sdc_cfg_t {
245                peripheral_count: sdc_cfg_role_count_t { count },
246            },
247        )
248    }
249
250    /// Sets the buffer configuration.
251    pub fn buffer_cfg(
252        self,
253        tx_packet_size: u16,
254        rx_packet_size: u16,
255        tx_packet_count: u8,
256        rx_packet_count: u8,
257    ) -> Result<Self, Error> {
258        self.cfg_set(
259            raw::SDC_CFG_TYPE_BUFFER_CFG,
260            sdc_cfg_t {
261                buffer_cfg: sdc_cfg_buffer_cfg_t {
262                    tx_packet_size,
263                    rx_packet_size,
264                    tx_packet_count,
265                    rx_packet_count,
266                },
267            },
268        )
269    }
270
271    /// Sets the number of advertising sets.
272    pub fn adv_count(self, count: u8) -> Result<Self, Error> {
273        self.cfg_set(
274            raw::SDC_CFG_TYPE_ADV_COUNT,
275            sdc_cfg_t {
276                adv_count: sdc_cfg_role_count_t { count },
277            },
278        )
279    }
280
281    /// Sets the scan buffer configuration.
282    pub fn scan_buffer_cfg(self, count: u8) -> Result<Self, Error> {
283        self.cfg_set(
284            raw::SDC_CFG_TYPE_SCAN_BUFFER_CFG,
285            sdc_cfg_t {
286                scan_buffer_cfg: sdc_cfg_buffer_count_t { count },
287            },
288        )
289    }
290
291    /// Sets the advertising buffer configuration.
292    pub fn adv_buffer_cfg(self, max_adv_data: u16) -> Result<Self, Error> {
293        self.cfg_set(
294            raw::SDC_CFG_TYPE_ADV_BUFFER_CFG,
295            sdc_cfg_t {
296                adv_buffer_cfg: sdc_cfg_adv_buffer_cfg_t { max_adv_data },
297            },
298        )
299    }
300
301    /// Sets the number of periodic advertising sets.
302    pub fn periodic_adv_count(self, count: u8) -> Result<Self, Error> {
303        self.cfg_set(
304            raw::SDC_CFG_TYPE_PERIODIC_ADV_COUNT,
305            sdc_cfg_t {
306                periodic_adv_count: sdc_cfg_role_count_t { count },
307            },
308        )
309    }
310
311    /// Sets the number of periodic syncs.
312    pub fn periodic_sync_count(self, count: u8) -> Result<Self, Error> {
313        self.cfg_set(
314            raw::SDC_CFG_TYPE_PERIODIC_SYNC_COUNT,
315            sdc_cfg_t {
316                periodic_sync_count: sdc_cfg_role_count_t { count },
317            },
318        )
319    }
320
321    /// Sets the periodic sync buffer configuration.
322    pub fn periodic_sync_buffer_cfg(self, count: u8) -> Result<Self, Error> {
323        self.cfg_set(
324            raw::SDC_CFG_TYPE_PERIODIC_SYNC_BUFFER_CFG,
325            sdc_cfg_t {
326                periodic_sync_buffer_cfg: sdc_cfg_buffer_count_t { count },
327            },
328        )
329    }
330
331    /// Sets the periodic advertising list length.
332    pub fn periodic_adv_list_len(self, len: u8) -> Result<Self, Error> {
333        self.cfg_set(
334            raw::SDC_CFG_TYPE_PERIODIC_ADV_LIST_SIZE,
335            sdc_cfg_t {
336                periodic_adv_list_size: len,
337            },
338        )
339    }
340
341    /// Enables support for advertising.
342    pub fn support_adv(self) -> Result<Self, Error> {
343        self.support(raw::sdc_support_adv)
344    }
345
346    /// Enables support for extended advertising.
347    pub fn support_ext_adv(self) -> Result<Self, Error> {
348        self.support(raw::sdc_support_ext_adv)
349    }
350
351    /// Enables support for peripheral role.
352    pub fn support_peripheral(self) -> Result<Self, Error> {
353        self.support(raw::sdc_support_peripheral)
354    }
355
356    /// Enables support for scanning.
357    pub fn support_scan(self) -> Result<Self, Error> {
358        self.support(raw::sdc_support_scan)
359    }
360
361    /// Enables support for extended scanning.
362    pub fn support_ext_scan(self) -> Result<Self, Error> {
363        self.support(raw::sdc_support_ext_scan)
364    }
365
366    /// Enables support for central role.
367    pub fn support_central(self) -> Result<Self, Error> {
368        self.support(raw::sdc_support_central)
369    }
370
371    /// Enables support for extended central role.
372    pub fn support_ext_central(self) -> Result<Self, Error> {
373        self.support(raw::sdc_support_ext_central)
374    }
375
376    /// Enables support for Data Length Extension (DLE) in central role.
377    pub fn support_dle_central(self) -> Result<Self, Error> {
378        self.support(raw::sdc_support_dle_central)
379    }
380
381    /// Enables support for Data Length Extension (DLE) in peripheral role.
382    pub fn support_dle_peripheral(self) -> Result<Self, Error> {
383        self.support(raw::sdc_support_dle_peripheral)
384    }
385
386    /// Enables support for 2M PHY.
387    pub fn support_le_2m_phy(self) -> Result<Self, Error> {
388        self.support(raw::sdc_support_le_2m_phy)
389    }
390
391    /// Enables support for coded PHY.
392    pub fn support_le_coded_phy(self) -> Result<Self, Error> {
393        self.support(raw::sdc_support_le_coded_phy)
394    }
395
396    /// Enables support for PHY update in central role.
397    pub fn support_phy_update_central(self) -> Result<Self, Error> {
398        self.support(raw::sdc_support_phy_update_central)
399    }
400
401    /// Enables support for PHY update in peripheral role.
402    pub fn support_phy_update_peripheral(self) -> Result<Self, Error> {
403        self.support(raw::sdc_support_phy_update_peripheral)
404    }
405
406    /// Enables support for periodic advertising.
407    pub fn support_le_periodic_adv(self) -> Result<Self, Error> {
408        self.support(raw::sdc_support_le_periodic_adv)
409    }
410
411    /// Enables support for periodic sync.
412    pub fn support_le_periodic_sync(self) -> Result<Self, Error> {
413        self.support(raw::sdc_support_le_periodic_sync)
414    }
415
416    /// Enables support for LE power control in central role.
417    pub fn support_le_power_control_central(self) -> Result<Self, Error> {
418        self.support(raw::sdc_support_le_power_control_central)
419    }
420
421    /// Enables support for LE power control in peripheral role.
422    pub fn support_le_power_control_peripheral(self) -> Result<Self, Error> {
423        self.support(raw::sdc_support_le_power_control_peripheral)
424    }
425
426    /// Enables support for sleep clock accuracy (SCA) updates in central role.
427    pub fn support_sca_central(self) -> Result<Self, Error> {
428        self.support(raw::sdc_support_sca_central)
429    }
430
431    /// Enables support for sleep clock accuracy (SCA) updates in peripheral role.
432    pub fn support_sca_peripheral(self) -> Result<Self, Error> {
433        self.support(raw::sdc_support_sca_peripheral)
434    }
435
436    /// Enables support for LE connection CTE response in central role.
437    pub fn support_le_conn_cte_rsp_central(self) -> Result<Self, Error> {
438        self.support(raw::sdc_support_le_conn_cte_rsp_central)
439    }
440
441    /// Enables support for LE connection CTE response in peripheral role.
442    pub fn support_le_conn_cte_rsp_peripheral(self) -> Result<Self, Error> {
443        self.support(raw::sdc_support_le_conn_cte_rsp_peripheral)
444    }
445
446    /// Enables support for periodic advertising sync transfer sender in central role.
447    pub fn support_periodic_adv_sync_transfer_sender_central(self) -> Result<Self, Error> {
448        self.support(raw::sdc_support_periodic_adv_sync_transfer_sender_central)
449    }
450
451    /// Enables support for periodic advertising sync transfer sender in peripheral role.
452    pub fn support_periodic_adv_sync_transfer_sender_peripheral(self) -> Result<Self, Error> {
453        self.support(raw::sdc_support_periodic_adv_sync_transfer_sender_peripheral)
454    }
455
456    /// Enables support for periodic advertising sync transfer receiver in central role.
457    pub fn support_periodic_adv_sync_transfer_receiver_central(self) -> Result<Self, Error> {
458        self.support(raw::sdc_support_periodic_adv_sync_transfer_receiver_central)
459    }
460
461    /// Enables support for periodic advertising sync transfer receiver in peripheral role.
462    pub fn support_periodic_adv_sync_transfer_receiver_peripheral(self) -> Result<Self, Error> {
463        self.support(raw::sdc_support_periodic_adv_sync_transfer_receiver_peripheral)
464    }
465
466    /// Enables support for QoS channel survey.
467    pub fn support_qos_channel_survey(self) -> Result<Self, Error> {
468        self.support(raw::sdc_support_qos_channel_survey)
469    }
470
471    /// Sets the default TX power.
472    pub fn default_tx_power(self, dbm: i8) -> Result<Self, Error> {
473        RetVal::from(unsafe { raw::sdc_default_tx_power_set(dbm) })
474            .to_result()
475            .and(Ok(self))
476    }
477
478    /// Calculates the required memory for the current configuration.
479    pub fn required_memory(&self) -> Result<usize, Error> {
480        let ret = unsafe {
481            raw::sdc_cfg_set(
482                SDC_DEFAULT_RESOURCE_CFG_TAG as u8,
483                SDC_CFG_TYPE_NONE as u8,
484                core::ptr::null(),
485            )
486        };
487        RetVal::from(ret).to_result().map(|x| x as usize)
488    }
489
490    /// Builds the SoftDevice Controller.
491    ///
492    /// # Safety
493    ///
494    /// The returned `SoftdeviceController` must not have its lifetime end without running its destructor, e.g. using `mem::forget`.
495    pub fn build<'d, R: CryptoRng + Send, const N: usize>(
496        self,
497        p: Peripherals<'d>,
498        rng: &'d mut R,
499        mpsl: &'d MultiprotocolServiceLayer,
500        mem: &'d mut Mem<N>,
501    ) -> Result<SoftdeviceController<'d>, Error> {
502        // Peripherals are used by the Softdevice Controller library, so we merely take ownership and ignore them
503        let _ = (p, mpsl);
504
505        let required = self.required_memory()?;
506        match N.cmp(&required) {
507            core::cmp::Ordering::Less => {
508                error!("Memory buffer too small. {} bytes needed.", required);
509                return Err(Error::EINVAL);
510            }
511            core::cmp::Ordering::Equal => (),
512            core::cmp::Ordering::Greater => {
513                warn!("Memory buffer too big. {} bytes needed", required);
514            }
515        }
516
517        unwrap!(
518            SDC_RNG.compare_exchange(
519                core::ptr::null_mut(),
520                rng as *mut _ as _,
521                Ordering::Release,
522                Ordering::Relaxed
523            ),
524            "SoftdeviceController already initialized!"
525        );
526        let rand_source = raw::sdc_rand_source_t {
527            rand_poll: Some(rand_blocking::<R>),
528        };
529        let ret = unsafe { raw::sdc_rand_source_register(&rand_source) };
530        RetVal::from(ret).to_result()?;
531
532        let ret = unsafe { raw::sdc_enable(Some(sdc_callback), mem.0.as_mut_ptr() as *mut _) };
533        RetVal::from(ret).to_result().and(Ok(SoftdeviceController {
534            using_ext_adv_cmds: Default::default(),
535            periodic_adv_response_data_in_progress: AtomicBool::new(false),
536            periodic_adv_response_data_complete: Signal::new(),
537            _private: PhantomData,
538        }))
539    }
540
541    #[inline]
542    fn support(self, f: unsafe extern "C" fn() -> i32) -> Result<Self, Error> {
543        RetVal::from(unsafe { f() }).to_result().and(Ok(self))
544    }
545
546    fn cfg_set(self, config_type: u32, value: sdc_cfg_t) -> Result<Self, Error> {
547        let ret = unsafe { raw::sdc_cfg_set(SDC_DEFAULT_RESOURCE_CFG_TAG as u8, config_type as u8, &value) };
548        RetVal::from(ret).to_result().and(Ok(self))
549    }
550}
551
552/// The SoftDevice Controller.
553///
554/// This is the main interface to the SoftDevice Controller. It is responsible for enabling and running the SDC.
555pub struct SoftdeviceController<'d> {
556    using_ext_adv_cmds: RefCell<Option<bool>>,
557    periodic_adv_response_data_in_progress: AtomicBool,
558    periodic_adv_response_data_complete: Signal<NoopRawMutex, (bt_hci::param::Status, bt_hci::param::SyncHandle)>,
559    // Prevent Send, Sync
560    _private: PhantomData<&'d *mut ()>,
561}
562
563impl Drop for SoftdeviceController<'_> {
564    fn drop(&mut self) {
565        unsafe { raw::sdc_disable() };
566        SDC_RNG.store(core::ptr::null_mut(), Ordering::Release);
567    }
568}
569
570#[inline(always)]
571unsafe fn bytes_of<T: Copy>(t: &T) -> &[u8] {
572    let len = core::mem::size_of::<T>();
573    core::slice::from_raw_parts(t as *const _ as *const u8, len)
574}
575
576impl<'d> SoftdeviceController<'d> {
577    /// Returns the build revision of the SoftDevice Controller.
578    pub fn build_revision() -> Result<[u8; raw::SDC_BUILD_REVISION_SIZE as usize], Error> {
579        let mut rev = [0; raw::SDC_BUILD_REVISION_SIZE as usize];
580        let ret = unsafe { raw::sdc_build_revision_get(rev.as_mut_ptr()) };
581        RetVal::from(ret).to_result().and(Ok(rev))
582    }
583
584    /// Submits an HCI data packet to the controller.
585    pub fn hci_data_put(&self, buf: &[u8]) -> Result<(), Error> {
586        assert!(buf.len() >= 4 && buf.len() >= 4 + usize::from(u16::from_le_bytes([buf[2], buf[3]])));
587        RetVal::from(unsafe { raw::sdc_hci_data_put(buf.as_ptr()) })
588            .to_result()
589            .and(Ok(()))
590    }
591
592    /// Submits an HCI ISO data packet to the controller.
593    pub fn hci_iso_data_put(&self, buf: &[u8]) -> Result<(), Error> {
594        assert!(buf.len() >= 4 && buf.len() >= 4 + usize::from(u16::from_le_bytes([buf[2], buf[3]])));
595        RetVal::from(unsafe { raw::sdc_hci_iso_data_put(buf.as_ptr()) })
596            .to_result()
597            .and(Ok(()))
598    }
599
600    /// Tries to get an HCI packet from the controller.
601    pub fn try_hci_get(&self, buf: &mut [u8]) -> Result<bt_hci::PacketKind, Error> {
602        assert!(buf.len() >= raw::HCI_MSG_BUFFER_MAX_SIZE as usize);
603        let mut msg_type: raw::sdc_hci_msg_type_t = 0;
604
605        let ret = unsafe { raw::sdc_hci_get(buf.as_mut_ptr(), (&mut msg_type) as *mut _ as *mut u8) };
606        RetVal::from(ret).to_result()?;
607        let kind = match msg_type {
608            raw::SDC_HCI_MSG_TYPE_DATA => bt_hci::PacketKind::AclData,
609            raw::SDC_HCI_MSG_TYPE_EVT => bt_hci::PacketKind::Event,
610            _ => unreachable!(),
611        };
612
613        // Check for a CommandComplete packet for an LeSetPeriodicAdvResponseData command
614        if let bt_hci::PacketKind::Event = kind {
615            if let Ok((header, data)) = bt_hci::event::EventPacketHeader::from_hci_bytes(buf) {
616                if header.code == bt_hci::event::CommandComplete::EVENT_CODE {
617                    if let Ok(event) =
618                        bt_hci::event::CommandComplete::from_hci_bytes_complete(&data[..usize::from(header.params_len)])
619                    {
620                        if event.cmd_opcode == LeSetPeriodicAdvResponseData::OPCODE {
621                            if let Ok(return_params) = event.return_params::<LeSetPeriodicAdvResponseData>() {
622                                self.periodic_adv_response_data_complete
623                                    .signal((event.status, return_params));
624                                return Err(Error::EAGAIN);
625                            }
626                        }
627                    }
628                }
629            }
630        }
631
632        Ok(kind)
633    }
634
635    /// Gets an HCI packet from the controller, waiting if necessary.
636    pub async fn hci_get(&self, buf: &mut [u8]) -> Result<bt_hci::PacketKind, Error> {
637        poll_fn(|ctx| match self.try_hci_get(buf) {
638            Err(Error::EAGAIN) => {
639                WAKER.register(ctx.waker());
640                Poll::Pending
641            }
642            res => Poll::Ready(res),
643        })
644        .await
645    }
646
647    /// Registers a waker to be woken when the controller has a new event.
648    pub fn register_waker(&self, waker: &Waker) {
649        WAKER.register(waker);
650    }
651
652    #[inline(always)]
653    unsafe fn raw_cmd(&self, f: unsafe extern "C" fn() -> u8) -> Result<(), bt_hci::param::Error> {
654        bt_hci::param::Status::from(f()).to_result()
655    }
656
657    #[inline(always)]
658    unsafe fn raw_cmd_params<P1: FixedSizeValue, P2: Copy>(
659        &self,
660        f: unsafe extern "C" fn(*const P2) -> u8,
661        params: &P1,
662    ) -> Result<(), bt_hci::param::Error> {
663        debug_assert_eq!(core::mem::size_of::<P1>(), core::mem::size_of::<P2>());
664        bt_hci::param::Status::from(f(params.as_hci_bytes().as_ptr() as *const _)).to_result()
665    }
666
667    #[inline(always)]
668    unsafe fn raw_cmd_return<R1: FixedSizeValue, R2: Copy>(
669        &self,
670        f: unsafe extern "C" fn(*mut R2) -> u8,
671    ) -> Result<R1, bt_hci::param::Error> {
672        debug_assert_eq!(core::mem::size_of::<R1>(), core::mem::size_of::<R2>());
673        let mut out = core::mem::zeroed();
674        bt_hci::param::Status::from(f(&mut out)).to_result()?;
675        Ok(unwrap!(R1::from_hci_bytes_complete(bytes_of(&out))))
676    }
677
678    #[inline(always)]
679    unsafe fn raw_cmd_params_return<P1: FixedSizeValue, R1: FixedSizeValue, P2: Copy, R2: Copy>(
680        &self,
681        f: unsafe extern "C" fn(*const P2, *mut R2) -> u8,
682        params: &P1,
683    ) -> Result<R1, bt_hci::param::Error> {
684        debug_assert_eq!(core::mem::size_of::<P1>(), core::mem::size_of::<P2>());
685        debug_assert_eq!(core::mem::size_of::<R1>(), core::mem::size_of::<R2>());
686
687        let mut out = core::mem::zeroed();
688        bt_hci::param::Status::from(f(params.as_hci_bytes().as_ptr() as *const _, &mut out)).to_result()?;
689        Ok(unwrap!(R1::from_hci_bytes_complete(bytes_of(&out))))
690    }
691
692    fn check_adv_cmd(&self, ext_adv: bool) -> Result<(), bt_hci::param::Error> {
693        let mut using_ext_adv = self.using_ext_adv_cmds.borrow_mut();
694        match *using_ext_adv {
695            None => {
696                *using_ext_adv = Some(ext_adv);
697                Ok(())
698            }
699            Some(x) if x == ext_adv => Ok(()),
700            _ => Err(bt_hci::param::Error::CMD_DISALLOWED),
701        }
702    }
703}
704
705impl ErrorType for SoftdeviceController<'_> {
706    type Error = Error;
707}
708
709impl<'a> Controller for SoftdeviceController<'a> {
710    async fn write_acl_data(&self, packet: &bt_hci::data::AclPacket<'_>) -> Result<(), Self::Error> {
711        let mut buf = [0u8; raw::HCI_DATA_PACKET_MAX_SIZE as usize];
712        packet.write_hci(buf.as_mut_slice()).map_err(|err| match err {
713            embedded_io::SliceWriteError::Full => Error::ENOMEM,
714            _ => unreachable!(),
715        })?;
716        self.hci_data_put(buf.as_slice())
717    }
718
719    async fn write_sync_data(&self, _packet: &bt_hci::data::SyncPacket<'_>) -> Result<(), Self::Error> {
720        unimplemented!()
721    }
722
723    async fn write_iso_data(&self, packet: &bt_hci::data::IsoPacket<'_>) -> Result<(), Self::Error> {
724        let mut buf = [0u8; raw::HCI_DATA_PACKET_MAX_SIZE as usize];
725        packet.write_hci(buf.as_mut_slice()).map_err(|err| match err {
726            embedded_io::SliceWriteError::Full => Error::ENOMEM,
727            _ => unreachable!(),
728        })?;
729        self.hci_iso_data_put(buf.as_slice())
730    }
731
732    async fn read<'b>(&self, buf: &'b mut [u8]) -> Result<bt_hci::ControllerToHostPacket<'b>, Self::Error> {
733        let kind = self.hci_get(buf).await?;
734        bt_hci::ControllerToHostPacket::from_hci_bytes_with_kind(kind, buf)
735            .map(|(x, _)| x)
736            .map_err(|err| match err {
737                bt_hci::FromHciBytesError::InvalidSize => Error::ENOMEM,
738                bt_hci::FromHciBytesError::InvalidValue => Error::EINVAL,
739            })
740    }
741}
742
743impl blocking::Controller for SoftdeviceController<'_> {
744    fn try_write_acl_data(&self, packet: &bt_hci::data::AclPacket<'_>) -> Result<(), blocking::TryError<Self::Error>> {
745        let mut buf = [0u8; raw::HCI_DATA_PACKET_MAX_SIZE as usize];
746        packet
747            .write_hci(buf.as_mut_slice())
748            .map_err(|err| match err {
749                embedded_io::SliceWriteError::Full => Error::ENOMEM,
750                _ => unreachable!(),
751            })
752            .map_err(into_try_err)?;
753        self.hci_data_put(buf.as_slice()).map_err(into_try_err)
754    }
755
756    fn try_write_sync_data(
757        &self,
758        _packet: &bt_hci::data::SyncPacket<'_>,
759    ) -> Result<(), blocking::TryError<Self::Error>> {
760        unimplemented!()
761    }
762
763    fn try_write_iso_data(&self, packet: &bt_hci::data::IsoPacket<'_>) -> Result<(), blocking::TryError<Self::Error>> {
764        let mut buf = [0u8; raw::HCI_DATA_PACKET_MAX_SIZE as usize];
765        packet
766            .write_hci(buf.as_mut_slice())
767            .map_err(|err| match err {
768                embedded_io::SliceWriteError::Full => Error::ENOMEM,
769                _ => unreachable!(),
770            })
771            .map_err(into_try_err)?;
772        self.hci_iso_data_put(buf.as_slice()).map_err(into_try_err)
773    }
774
775    fn try_read<'b>(
776        &self,
777        buf: &'b mut [u8],
778    ) -> Result<bt_hci::ControllerToHostPacket<'b>, blocking::TryError<Self::Error>> {
779        let kind = self.try_hci_get(buf).map_err(into_try_err)?;
780        bt_hci::ControllerToHostPacket::from_hci_bytes_with_kind(kind, buf)
781            .map(|(x, _)| x)
782            .map_err(|err| match err {
783                bt_hci::FromHciBytesError::InvalidSize => Error::ENOMEM,
784                bt_hci::FromHciBytesError::InvalidValue => Error::EINVAL,
785            })
786            .map_err(into_try_err)
787    }
788
789    fn write_acl_data(&self, packet: &bt_hci::data::AclPacket) -> Result<(), Self::Error> {
790        loop {
791            match self.try_write_acl_data(packet) {
792                Ok(v) => return Ok(v),
793                Err(TryError::Error(e)) => return Err(e),
794                Err(TryError::Busy) => {}
795            }
796        }
797    }
798
799    fn write_sync_data(&self, packet: &bt_hci::data::SyncPacket) -> Result<(), Self::Error> {
800        loop {
801            match self.try_write_sync_data(packet) {
802                Ok(v) => return Ok(v),
803                Err(TryError::Error(e)) => return Err(e),
804                Err(TryError::Busy) => {}
805            }
806        }
807    }
808
809    fn write_iso_data(&self, packet: &bt_hci::data::IsoPacket) -> Result<(), Self::Error> {
810        loop {
811            match self.try_write_iso_data(packet) {
812                Ok(v) => return Ok(v),
813                Err(TryError::Error(e)) => return Err(e),
814                Err(TryError::Busy) => {}
815            }
816        }
817    }
818
819    fn read<'b>(&self, buf: &'b mut [u8]) -> Result<bt_hci::ControllerToHostPacket<'b>, Self::Error> {
820        loop {
821            // Safety: the buffer can be reused after try_read has returned.
822            let buf = unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr(), buf.len()) };
823            match self.try_read(buf) {
824                Ok(v) => return Ok(v),
825                Err(TryError::Error(e)) => return Err(e),
826                Err(TryError::Busy) => {}
827            }
828        }
829    }
830}
831
832fn into_try_err(e: Error) -> blocking::TryError<Error> {
833    match e {
834        Error::EAGAIN => blocking::TryError::Busy,
835        other => blocking::TryError::Error(other),
836    }
837}
838
839macro_rules! sdc_cmd {
840    (async $cmd:ty => $raw:ident()) => {
841        sdc_cmd!(async $cmd => raw_cmd($raw));
842    };
843
844    (async $cmd:ty => $raw:ident(x)) => {
845        sdc_cmd!(async $cmd => raw_cmd_params($raw, $cmd));
846    };
847
848    (async $cmd:ty => $method:ident($raw:ident$(, $params:ty)?) $($ext_adv:literal)?) => {
849        #[automatically_derived]
850        #[allow(unused_variables)]
851        impl<'d> bt_hci::controller::ControllerCmdAsync<$cmd> for $crate::sdc::SoftdeviceController<'d> {
852            async fn exec(&self, cmd: &$cmd) -> Result<(), bt_hci::cmd::Error<Self::Error>> {
853                $(self.check_adv_cmd($ext_adv)?;)?
854                unsafe { self.$method(raw::$raw$(, <$params as bt_hci::cmd::Cmd>::params(cmd))?) }.map_err(bt_hci::cmd::Error::Hci)
855            }
856        }
857    };
858
859    ($cmd:ty => $raw:ident()) => {
860        sdc_cmd!($cmd => raw_cmd($raw));
861    };
862
863    ($cmd:ty => $raw:ident(x)) => {
864        sdc_cmd!($cmd => raw_cmd_params($raw, $cmd));
865    };
866
867    ($cmd:ty => $raw:ident() -> y) => {
868        sdc_cmd!($cmd => raw_cmd_return($raw));
869    };
870
871    ($cmd:ty => $raw:ident(x) -> y) => {
872        sdc_cmd!($cmd => raw_cmd_params_return($raw, $cmd));
873    };
874
875    ($cmd:ty => $method:ident($raw:ident$(, $params:ty)*) $($ext_adv:literal)?) => {
876        #[automatically_derived]
877        #[allow(unused_variables)]
878        impl<'d> bt_hci::controller::ControllerCmdSync<$cmd> for $crate::sdc::SoftdeviceController<'d> {
879            async fn exec(&self, cmd: &$cmd) -> Result<<$cmd as bt_hci::cmd::SyncCmd>::Return, bt_hci::cmd::Error<Self::Error>> {
880                $(self.check_adv_cmd($ext_adv)?;)?
881                let ret = unsafe { self.$method(raw::$raw$(, <$params as bt_hci::cmd::Cmd>::params(cmd))?) }?;
882                Ok(ret)
883            }
884        }
885    };
886}
887
888/// Bluetooth HCI Link Control commands (§7.1)
889mod link_control {
890    use bt_hci::cmd::link_control::*;
891
892    use crate::raw;
893
894    sdc_cmd!(Disconnect => sdc_hci_cmd_lc_disconnect(x));
895    sdc_cmd!(async ReadRemoteVersionInformation => sdc_hci_cmd_lc_read_remote_version_information(x));
896}
897
898/// Bluetooth HCI Controller & Baseband commands (§7.3)
899mod controller_baseband {
900    use bt_hci::cmd::controller_baseband::*;
901    use bt_hci::cmd::{Cmd, Error as CmdError};
902    use bt_hci::controller::ControllerCmdSync;
903    use bt_hci::param::ConnHandleCompletedPackets;
904    use bt_hci::WriteHci;
905
906    use crate::raw;
907
908    impl<'d> ControllerCmdSync<Reset> for super::SoftdeviceController<'d> {
909        async fn exec(&self, _cmd: &Reset) -> Result<<Reset as bt_hci::cmd::SyncCmd>::Return, CmdError<Self::Error>> {
910            *self.using_ext_adv_cmds.borrow_mut() = None;
911            unsafe { self.raw_cmd(raw::sdc_hci_cmd_cb_reset) }.map_err(bt_hci::cmd::Error::Hci)
912        }
913    }
914
915    sdc_cmd!(SetEventMask => sdc_hci_cmd_cb_set_event_mask(x));
916    sdc_cmd!(ReadTransmitPowerLevel => sdc_hci_cmd_cb_read_transmit_power_level(x) -> y);
917    sdc_cmd!(SetControllerToHostFlowControl => sdc_hci_cmd_cb_set_controller_to_host_flow_control(x));
918    sdc_cmd!(HostBufferSize => sdc_hci_cmd_cb_host_buffer_size(x));
919    sdc_cmd!(SetEventMaskPage2 => sdc_hci_cmd_cb_set_event_mask_page_2(x));
920    sdc_cmd!(ReadAuthenticatedPayloadTimeout => sdc_hci_cmd_cb_read_authenticated_payload_timeout(x) -> y);
921    sdc_cmd!(WriteAuthenticatedPayloadTimeout => sdc_hci_cmd_cb_write_authenticated_payload_timeout(x) -> y);
922
923    impl<'a, 'd> ControllerCmdSync<HostNumberOfCompletedPackets<'a>> for super::SoftdeviceController<'d> {
924        async fn exec(
925            &self,
926            cmd: &HostNumberOfCompletedPackets<'a>,
927        ) -> Result<<HostNumberOfCompletedPackets<'a> as bt_hci::cmd::SyncCmd>::Return, CmdError<Self::Error>> {
928            const MAX_CONN_HANDLES: usize = 63;
929            const N: usize = 1 + MAX_CONN_HANDLES + core::mem::size_of::<ConnHandleCompletedPackets>();
930            let mut buf = [0; N];
931            unwrap!(cmd.params().write_hci(buf.as_mut_slice()));
932            let ret = unsafe { raw::sdc_hci_cmd_cb_host_number_of_completed_packets(buf.as_ptr() as *const _) };
933            bt_hci::param::Status::from(ret).to_result().map_err(CmdError::Hci)
934        }
935    }
936}
937
938/// Bluetooth HCI Informational parameters (§7.4)
939mod info {
940    use bt_hci::cmd::info::*;
941
942    use crate::raw;
943
944    sdc_cmd!(ReadLocalVersionInformation => sdc_hci_cmd_ip_read_local_version_information() -> y);
945    sdc_cmd!(ReadLocalSupportedCmds => sdc_hci_cmd_ip_read_local_supported_commands() -> y);
946    sdc_cmd!(ReadLocalSupportedFeatures => sdc_hci_cmd_ip_read_local_supported_features() -> y);
947    sdc_cmd!(ReadBdAddr => sdc_hci_cmd_ip_read_bd_addr() -> y);
948}
949
950/// Bluetooth HCI Status parameters (§7.5)
951mod status {
952    use bt_hci::cmd::status::*;
953
954    use crate::raw;
955
956    sdc_cmd!(ReadRssi => sdc_hci_cmd_sp_read_rssi(x) -> y);
957}
958
959/// Bluetooth HCI LE Controller commands (§7.8)
960mod le {
961    use core::sync::atomic::Ordering;
962
963    use bt_hci::cmd::le::*;
964    use bt_hci::cmd::{Cmd, Error as CmdError};
965    use bt_hci::controller::{ControllerCmdAsync, ControllerCmdSync};
966    use bt_hci::param::{AdvHandle, AdvSet, ConnHandle, InitiatingPhy, ScanningPhy, SyncHandle};
967    use bt_hci::{FromHciBytes, WriteHci};
968
969    use crate::raw;
970
971    const MAX_PHY_COUNT: usize = 3;
972    const MAX_ADV_SET: usize = 63;
973    const MAX_ANTENNA_IDS: usize = 75;
974    const MAX_SUBEVENTS: usize = 128;
975
976    // Legacy advertising commands
977    sdc_cmd!(LeSetAdvParams => raw_cmd_params(sdc_hci_cmd_le_set_adv_params, LeSetAdvParams) false);
978    sdc_cmd!(LeReadAdvPhysicalChannelTxPower => raw_cmd_return(sdc_hci_cmd_le_read_adv_physical_channel_tx_power) false);
979    sdc_cmd!(LeSetAdvData => raw_cmd_params(sdc_hci_cmd_le_set_adv_data, LeSetAdvData) false);
980    sdc_cmd!(LeSetScanResponseData => raw_cmd_params(sdc_hci_cmd_le_set_scan_response_data, LeSetScanResponseData) false);
981    sdc_cmd!(LeSetAdvEnable => raw_cmd_params(sdc_hci_cmd_le_set_adv_enable, LeSetAdvEnable) false);
982    sdc_cmd!(LeSetScanParams => raw_cmd_params(sdc_hci_cmd_le_set_scan_params, LeSetScanParams) false);
983    sdc_cmd!(LeSetScanEnable => raw_cmd_params(sdc_hci_cmd_le_set_scan_enable, LeSetScanEnable) false);
984    sdc_cmd!(async LeCreateConn => raw_cmd_params(sdc_hci_cmd_le_create_conn, LeCreateConn) false);
985
986    // Extended advertising commands
987    sdc_cmd!(LeSetExtAdvParams => raw_cmd_params_return(sdc_hci_cmd_le_set_ext_adv_params, LeSetExtAdvParams) true);
988    sdc_cmd!(LeSetExtAdvParamsV2 => raw_cmd_params_return(sdc_hci_cmd_le_set_ext_adv_params_v2, LeSetExtAdvParamsV2) true);
989    sdc_cmd!(LeReadMaxAdvDataLength => raw_cmd_return(sdc_hci_cmd_le_read_max_adv_data_length) true);
990    sdc_cmd!(LeReadNumberOfSupportedAdvSets => raw_cmd_return(sdc_hci_cmd_le_read_number_of_supported_adv_sets) true);
991    sdc_cmd!(LeRemoveAdvSet => raw_cmd_params(sdc_hci_cmd_le_remove_adv_set, LeRemoveAdvSet) true);
992    sdc_cmd!(LeClearAdvSets => raw_cmd(sdc_hci_cmd_le_clear_adv_sets) true);
993    sdc_cmd!(LeSetPeriodicAdvParams => raw_cmd_params(sdc_hci_cmd_le_set_periodic_adv_params, LeSetPeriodicAdvParams) true);
994    sdc_cmd!(LeSetPeriodicAdvParamsV2 => raw_cmd_params_return(sdc_hci_cmd_le_set_periodic_adv_params_v2, LeSetPeriodicAdvParamsV2) true);
995    sdc_cmd!(LeSetPeriodicAdvEnable => raw_cmd_params(sdc_hci_cmd_le_set_periodic_adv_enable, LeSetPeriodicAdvEnable) true);
996    sdc_cmd!(LeSetExtScanEnable => raw_cmd_params(sdc_hci_cmd_le_set_ext_scan_enable, LeSetExtScanEnable) true);
997    sdc_cmd!(async LePeriodicAdvCreateSync => raw_cmd_params(sdc_hci_cmd_le_periodic_adv_create_sync, LePeriodicAdvCreateSync) true);
998    sdc_cmd!(LePeriodicAdvCreateSyncCancel => raw_cmd(sdc_hci_cmd_le_periodic_adv_create_sync_cancel) true);
999    sdc_cmd!(LePeriodicAdvTerminateSync => raw_cmd_params(sdc_hci_cmd_le_periodic_adv_terminate_sync, LePeriodicAdvTerminateSync) true);
1000    sdc_cmd!(LeAddDeviceToPeriodicAdvList => raw_cmd_params(sdc_hci_cmd_le_add_device_to_periodic_adv_list, LeAddDeviceToPeriodicAdvList) true);
1001    sdc_cmd!(LeRemoveDeviceFromPeriodicAdvList => raw_cmd_params(sdc_hci_cmd_le_remove_device_from_periodic_adv_list, LeRemoveDeviceFromPeriodicAdvList) true);
1002    sdc_cmd!(LeClearPeriodicAdvList => raw_cmd(sdc_hci_cmd_le_clear_periodic_adv_list) true);
1003    sdc_cmd!(LeReadPeriodicAdvListSize => raw_cmd_return(sdc_hci_cmd_le_read_periodic_adv_list_size) true);
1004    sdc_cmd!(LeSetPeriodicAdvSyncTransferParams => raw_cmd_params_return(sdc_hci_cmd_le_set_periodic_adv_sync_transfer_params, LeSetPeriodicAdvSyncTransferParams) true);
1005    sdc_cmd!(LeSetDefaultPeriodicAdvSyncTransferParams => raw_cmd_params(sdc_hci_cmd_le_set_default_periodic_adv_sync_transfer_params, LeSetDefaultPeriodicAdvSyncTransferParams) true);
1006
1007    sdc_cmd!(LeSetEventMask => sdc_hci_cmd_le_set_event_mask(x));
1008    sdc_cmd!(LeReadBufferSize => sdc_hci_cmd_le_read_buffer_size() -> y);
1009    sdc_cmd!(LeReadLocalSupportedFeatures => sdc_hci_cmd_le_read_local_supported_features() -> y);
1010    sdc_cmd!(LeSetRandomAddr => sdc_hci_cmd_le_set_random_address(x));
1011    sdc_cmd!(LeCreateConnCancel => sdc_hci_cmd_le_create_conn_cancel());
1012    sdc_cmd!(LeReadFilterAcceptListSize => sdc_hci_cmd_le_read_filter_accept_list_size() -> y);
1013    sdc_cmd!(LeClearFilterAcceptList => sdc_hci_cmd_le_clear_filter_accept_list());
1014    sdc_cmd!(LeAddDeviceToFilterAcceptList => sdc_hci_cmd_le_add_device_to_filter_accept_list(x));
1015    sdc_cmd!(LeRemoveDeviceFromFilterAcceptList => sdc_hci_cmd_le_remove_device_from_filter_accept_list(x));
1016    sdc_cmd!(async LeConnUpdate => sdc_hci_cmd_le_conn_update(x));
1017    sdc_cmd!(LeSetHostChannelClassification => sdc_hci_cmd_le_set_host_channel_classification(x));
1018    sdc_cmd!(LeReadChannelMap => sdc_hci_cmd_le_read_channel_map(x) -> y);
1019    sdc_cmd!(async LeReadRemoteFeatures => sdc_hci_cmd_le_read_remote_features(x));
1020    sdc_cmd!(LeEncrypt => sdc_hci_cmd_le_encrypt(x) -> y);
1021    sdc_cmd!(LeRand => sdc_hci_cmd_le_rand() -> y);
1022    sdc_cmd!(async LeEnableEncryption => sdc_hci_cmd_le_enable_encryption(x));
1023    sdc_cmd!(LeLongTermKeyRequestReply => sdc_hci_cmd_le_long_term_key_request_reply(x) -> y);
1024    sdc_cmd!(LeLongTermKeyRequestNegativeReply => sdc_hci_cmd_le_long_term_key_request_negative_reply(x) -> y);
1025    sdc_cmd!(LeReadSupportedStates => sdc_hci_cmd_le_read_supported_states() -> y);
1026    sdc_cmd!(LeTestEnd => sdc_hci_cmd_le_test_end() -> y);
1027    sdc_cmd!(LeSetDataLength => sdc_hci_cmd_le_set_data_length(x) -> y);
1028    sdc_cmd!(LeReadSuggestedDefaultDataLength => sdc_hci_cmd_le_read_suggested_default_data_length() -> y);
1029    sdc_cmd!(LeWriteSuggestedDefaultDataLength => sdc_hci_cmd_le_write_suggested_default_data_length(x));
1030    sdc_cmd!(LeAddDeviceToResolvingList => sdc_hci_cmd_le_add_device_to_resolving_list(x));
1031    sdc_cmd!(LeRemoveDeviceFromResolvingList => sdc_hci_cmd_le_remove_device_from_resolving_list(x));
1032    sdc_cmd!(LeClearResolvingList => sdc_hci_cmd_le_clear_resolving_list());
1033    sdc_cmd!(LeReadResolvingListSize => sdc_hci_cmd_le_read_resolving_list_size() -> y);
1034    sdc_cmd!(LeSetAddrResolutionEnable => sdc_hci_cmd_le_set_address_resolution_enable(x));
1035    sdc_cmd!(LeSetResolvablePrivateAddrTimeout => sdc_hci_cmd_le_set_resolvable_private_address_timeout(x));
1036    sdc_cmd!(LeReadMaxDataLength => sdc_hci_cmd_le_read_max_data_length() -> y);
1037    sdc_cmd!(LeReadPhy => sdc_hci_cmd_le_read_phy(x) -> y);
1038    sdc_cmd!(LeSetDefaultPhy => sdc_hci_cmd_le_set_default_phy(x));
1039    sdc_cmd!(async LeSetPhy => sdc_hci_cmd_le_set_phy(x));
1040    sdc_cmd!(LeSetAdvSetRandomAddr => sdc_hci_cmd_le_set_adv_set_random_address(x));
1041    sdc_cmd!(LeReadTransmitPower => sdc_hci_cmd_le_read_transmit_power() -> y);
1042    sdc_cmd!(LeReadRfPathCompensation => sdc_hci_cmd_le_read_rf_path_compensation() -> y);
1043    sdc_cmd!(LeWriteRfPathCompensation => sdc_hci_cmd_le_write_rf_path_compensation(x));
1044    sdc_cmd!(LeSetPrivacyMode => sdc_hci_cmd_le_set_privacy_mode(x));
1045    sdc_cmd!(LeSetConnectionlessCteTransmitEnable => sdc_hci_cmd_le_set_connless_cte_transmit_enable(x));
1046    sdc_cmd!(LeConnCteResponseEnable => sdc_hci_cmd_le_conn_cte_response_enable(x) -> y);
1047    sdc_cmd!(LeReadAntennaInformation => sdc_hci_cmd_le_read_antenna_information() -> y);
1048    sdc_cmd!(LeSetPeriodicAdvReceiveEnable => sdc_hci_cmd_le_set_periodic_adv_receive_enable(x));
1049    sdc_cmd!(LePeriodicAdvSyncTransfer => sdc_hci_cmd_le_periodic_adv_sync_transfer(x) -> y);
1050    sdc_cmd!(LePeriodicAdvSetInfoTransfer => sdc_hci_cmd_le_periodic_adv_set_info_transfer(x) -> y);
1051    sdc_cmd!(async LeRequestPeerSca => sdc_hci_cmd_le_request_peer_sca(x));
1052    sdc_cmd!(LeEnhancedReadTransmitPowerLevel => sdc_hci_cmd_le_enhanced_read_transmit_power_level(x) -> y);
1053    sdc_cmd!(async LeReadRemoteTransmitPowerLevel => sdc_hci_cmd_le_read_remote_transmit_power_level(x));
1054    sdc_cmd!(LeSetPathLossReportingParams => sdc_hci_cmd_le_set_path_loss_reporting_params(x) -> y);
1055    sdc_cmd!(LeSetPathLossReportingEnable => sdc_hci_cmd_le_set_path_loss_reporting_enable(x) -> y);
1056    sdc_cmd!(LeSetTransmitPowerReportingEnable => sdc_hci_cmd_le_set_transmit_power_reporting_enable(x) -> y);
1057    sdc_cmd!(LeSetDataRelatedAddrChanges => sdc_hci_cmd_le_set_data_related_address_changes(x));
1058    sdc_cmd!(LeSetHostFeature => sdc_hci_cmd_le_set_host_feature(x));
1059    sdc_cmd!(LeSetHostFeatureV2 => sdc_hci_cmd_le_set_host_feature_v2(x));
1060
1061    impl<'a, 'd> ControllerCmdSync<LeSetExtAdvData<'a>> for super::SoftdeviceController<'d> {
1062        async fn exec(&self, cmd: &LeSetExtAdvData<'a>) -> Result<(), CmdError<nrf_mpsl::Error>> {
1063            self.check_adv_cmd(true)?;
1064            const N: usize = 4 + 251;
1065            let mut buf = [0; N];
1066            unwrap!(cmd.params().write_hci(buf.as_mut_slice()));
1067            let ret = unsafe { raw::sdc_hci_cmd_le_set_ext_adv_data(buf.as_ptr() as *const _) };
1068            bt_hci::param::Status::from(ret).to_result().map_err(CmdError::Hci)
1069        }
1070    }
1071
1072    impl<'a, 'd> ControllerCmdSync<LeSetExtScanResponseData<'a>> for super::SoftdeviceController<'d> {
1073        async fn exec(&self, cmd: &LeSetExtScanResponseData<'a>) -> Result<(), CmdError<nrf_mpsl::Error>> {
1074            self.check_adv_cmd(true)?;
1075            const N: usize = 4 + 251;
1076            let mut buf = [0; N];
1077            unwrap!(cmd.params().write_hci(buf.as_mut_slice()));
1078            let ret = unsafe { raw::sdc_hci_cmd_le_set_ext_scan_response_data(buf.as_ptr() as *const _) };
1079            bt_hci::param::Status::from(ret).to_result().map_err(CmdError::Hci)
1080        }
1081    }
1082
1083    impl<'a, 'd> ControllerCmdSync<LeSetExtAdvEnable<'a>> for super::SoftdeviceController<'d> {
1084        async fn exec(&self, cmd: &LeSetExtAdvEnable<'a>) -> Result<(), CmdError<nrf_mpsl::Error>> {
1085            self.check_adv_cmd(true)?;
1086            const N: usize = 2 + MAX_ADV_SET * core::mem::size_of::<AdvSet>();
1087            let mut buf = [0; N];
1088            unwrap!(cmd.params().write_hci(buf.as_mut_slice()));
1089            let ret = unsafe { raw::sdc_hci_cmd_le_set_ext_adv_enable(buf.as_ptr() as *const _) };
1090            bt_hci::param::Status::from(ret).to_result().map_err(CmdError::Hci)
1091        }
1092    }
1093
1094    impl<'a, 'd> ControllerCmdSync<LeSetPeriodicAdvData<'a>> for super::SoftdeviceController<'d> {
1095        async fn exec(&self, cmd: &LeSetPeriodicAdvData<'a>) -> Result<(), CmdError<nrf_mpsl::Error>> {
1096            self.check_adv_cmd(true)?;
1097            const N: usize = 3 + 252;
1098            let mut buf = [0; N];
1099            unwrap!(cmd.params().write_hci(buf.as_mut_slice()));
1100            let ret = unsafe { raw::sdc_hci_cmd_le_set_periodic_adv_data(buf.as_ptr() as *const _) };
1101            bt_hci::param::Status::from(ret).to_result().map_err(CmdError::Hci)
1102        }
1103    }
1104
1105    impl<'d> ControllerCmdSync<LeSetExtScanParams> for super::SoftdeviceController<'d> {
1106        async fn exec(&self, cmd: &LeSetExtScanParams) -> Result<(), CmdError<nrf_mpsl::Error>> {
1107            self.check_adv_cmd(true)?;
1108            const N: usize = 3 + MAX_PHY_COUNT * core::mem::size_of::<ScanningPhy>();
1109            let mut buf = [0; N];
1110            unwrap!(cmd.params().write_hci(buf.as_mut_slice()));
1111            let ret = unsafe { raw::sdc_hci_cmd_le_set_ext_scan_params(buf.as_ptr() as *const _) };
1112            bt_hci::param::Status::from(ret).to_result().map_err(CmdError::Hci)
1113        }
1114    }
1115
1116    impl<'d> ControllerCmdAsync<LeExtCreateConn> for super::SoftdeviceController<'d> {
1117        async fn exec(&self, cmd: &LeExtCreateConn) -> Result<(), CmdError<nrf_mpsl::Error>> {
1118            self.check_adv_cmd(true)?;
1119            const N: usize = 10 + MAX_PHY_COUNT * core::mem::size_of::<InitiatingPhy>();
1120            let mut buf = [0; N];
1121            unwrap!(cmd.params().write_hci(buf.as_mut_slice()));
1122            let ret = unsafe { raw::sdc_hci_cmd_le_ext_create_conn(buf.as_ptr() as *const _) };
1123            bt_hci::param::Status::from(ret).to_result().map_err(CmdError::Hci)
1124        }
1125    }
1126
1127    impl<'a, 'd> ControllerCmdSync<LeSetConnectionlessCteTransmitParams<'a>> for super::SoftdeviceController<'d> {
1128        async fn exec(&self, cmd: &LeSetConnectionlessCteTransmitParams<'a>) -> Result<(), CmdError<nrf_mpsl::Error>> {
1129            const N: usize = 5 + MAX_ANTENNA_IDS;
1130            let mut buf = [0; N];
1131            unwrap!(cmd.params().write_hci(buf.as_mut_slice()));
1132            let ret = unsafe { raw::sdc_hci_cmd_le_set_connless_cte_transmit_params(buf.as_ptr() as *const _) };
1133            bt_hci::param::Status::from(ret).to_result().map_err(CmdError::Hci)
1134        }
1135    }
1136
1137    impl<'a, 'd> ControllerCmdSync<LeSetConnCteTransmitParams<'a>> for super::SoftdeviceController<'d> {
1138        async fn exec(&self, cmd: &LeSetConnCteTransmitParams<'a>) -> Result<ConnHandle, CmdError<nrf_mpsl::Error>> {
1139            const N: usize = 5 + MAX_ANTENNA_IDS;
1140            let mut buf = [0; N];
1141            unwrap!(cmd.params().write_hci(buf.as_mut_slice()));
1142
1143            let mut out = unsafe { core::mem::zeroed() };
1144            let ret = unsafe { raw::sdc_hci_cmd_le_set_conn_cte_transmit_params(buf.as_ptr() as *const _, &mut out) };
1145
1146            bt_hci::param::Status::from(ret).to_result()?;
1147            Ok(unwrap!(ConnHandle::from_hci_bytes_complete(unsafe {
1148                super::bytes_of(&out)
1149            })))
1150        }
1151    }
1152
1153    impl<'d> ControllerCmdAsync<LeExtCreateConnV2> for super::SoftdeviceController<'d> {
1154        async fn exec(&self, cmd: &LeExtCreateConnV2) -> Result<(), CmdError<nrf_mpsl::Error>> {
1155            self.check_adv_cmd(true)?;
1156            const N: usize = 12 + MAX_PHY_COUNT * 16;
1157            let mut buf = [0; N];
1158            unwrap!(cmd.params().write_hci(buf.as_mut_slice()));
1159
1160            let ret = unsafe { raw::sdc_hci_cmd_le_ext_create_conn_v2(buf.as_ptr() as *const _) };
1161            bt_hci::param::Status::from(ret).to_result().map_err(CmdError::Hci)
1162        }
1163    }
1164
1165    impl<'a, 'd> ControllerCmdSync<LeSetPeriodicAdvSubeventData<'a>> for super::SoftdeviceController<'d> {
1166        async fn exec(&self, cmd: &LeSetPeriodicAdvSubeventData<'a>) -> Result<AdvHandle, CmdError<nrf_mpsl::Error>> {
1167            self.check_adv_cmd(true)?;
1168            const N: usize = raw::HCI_CMD_MAX_SIZE as usize;
1169            let mut buf = [0; N];
1170            unwrap!(cmd.params().write_hci(buf.as_mut_slice()));
1171
1172            let mut out = unsafe { core::mem::zeroed() };
1173            let ret = unsafe { raw::sdc_hci_cmd_le_set_periodic_adv_subevent_data(buf.as_ptr() as *const _, &mut out) };
1174
1175            bt_hci::param::Status::from(ret).to_result()?;
1176            Ok(unwrap!(AdvHandle::from_hci_bytes_complete(unsafe {
1177                super::bytes_of(&out)
1178            })))
1179        }
1180    }
1181
1182    impl<'a, 'd> ControllerCmdSync<LeSetPeriodicAdvResponseData<'a>> for super::SoftdeviceController<'d> {
1183        async fn exec(&self, cmd: &LeSetPeriodicAdvResponseData<'a>) -> Result<SyncHandle, CmdError<nrf_mpsl::Error>> {
1184            if self
1185                .periodic_adv_response_data_in_progress
1186                .swap(true, Ordering::Relaxed)
1187            {
1188                return Err(CmdError::Hci(bt_hci::param::Error::CONTROLLER_BUSY));
1189            }
1190
1191            self.check_adv_cmd(true)?;
1192            const N: usize = raw::HCI_CMD_MAX_SIZE as usize;
1193            let mut buf = [0; N];
1194            unwrap!(cmd.params().write_hci(buf.as_mut_slice()));
1195
1196            let mut out = unsafe { core::mem::zeroed() };
1197            let ret = unsafe { raw::sdc_hci_cmd_le_set_periodic_adv_response_data(buf.as_ptr() as *const _, &mut out) };
1198            bt_hci::param::Status::from(ret).to_result()?;
1199
1200            // sdc_hci_cmd_le_set_periodic_adv_response_data generates an actual CommandComplete event, so wait for that.
1201            let (status, handle) = self.periodic_adv_response_data_complete.wait().await;
1202            self.periodic_adv_response_data_in_progress
1203                .store(false, Ordering::Relaxed);
1204
1205            status.to_result().map(|_| handle).map_err(CmdError::Hci)
1206        }
1207    }
1208
1209    impl<'a, 'd> ControllerCmdSync<LeSetPeriodicSyncSubevent<'a>> for super::SoftdeviceController<'d> {
1210        async fn exec(&self, cmd: &LeSetPeriodicSyncSubevent<'a>) -> Result<SyncHandle, CmdError<nrf_mpsl::Error>> {
1211            self.check_adv_cmd(true)?;
1212            const N: usize = 5 + MAX_SUBEVENTS;
1213            let mut buf = [0; N];
1214            unwrap!(cmd.params().write_hci(buf.as_mut_slice()));
1215
1216            let mut out = unsafe { core::mem::zeroed() };
1217            let ret = unsafe { raw::sdc_hci_cmd_le_set_periodic_sync_subevent(buf.as_ptr() as *const _, &mut out) };
1218
1219            bt_hci::param::Status::from(ret).to_result()?;
1220            Ok(unwrap!(SyncHandle::from_hci_bytes_complete(unsafe {
1221                super::bytes_of(&out)
1222            })))
1223        }
1224    }
1225}
1226
1227/// Bluetooth HCI vendor specific commands.
1228pub mod vendor {
1229    #![allow(missing_docs)]
1230    use bt_hci::cmd::Error as CmdError;
1231    use bt_hci::controller::ControllerCmdSync;
1232    use bt_hci::param::{BdAddr, ChannelMap, ConnHandle, Duration};
1233    use bt_hci::{cmd, param, FromHciBytes};
1234
1235    use crate::raw;
1236
1237    param!(
1238        struct ZephyrStaticAddr {
1239            addr: BdAddr,
1240            identity_root: [u8; 16],
1241        }
1242    );
1243
1244    param!(
1245        struct ZephyrTxPower {
1246            handle_type: u8,
1247            handle: u16,
1248            selected_tx_power: i8,
1249        }
1250    );
1251
1252    cmd! {
1253        /// https://docs.zephyrproject.org/apidoc/latest/hci__vs_8h.html
1254        ZephyrReadVersionInfo(VENDOR_SPECIFIC, 0x0001) {
1255            Params = ();
1256            ZephyrReadVersionInfoReturn {
1257                hw_platform: u16,
1258                hw_variant: u16,
1259                fw_variant: u8,
1260                fw_version: u8,
1261                fw_revision: u16,
1262                fw_build: u32,
1263            }
1264        }
1265    }
1266
1267    cmd! {
1268        /// https://docs.zephyrproject.org/apidoc/latest/hci__vs_8h.html
1269        ZephyrReadSupportedCommands(VENDOR_SPECIFIC, 0x0002) {
1270            Params = ();
1271            Return = [u8; 64];
1272        }
1273    }
1274
1275    cmd! {
1276        /// https://docs.zephyrproject.org/apidoc/latest/hci__vs_8h.html
1277        ZephyrWriteBdAddr(VENDOR_SPECIFIC, 0x0006) {
1278            Params = BdAddr;
1279            Return = ();
1280        }
1281    }
1282
1283    cmd! {
1284        /// https://docs.zephyrproject.org/apidoc/latest/hci__vs_8h.html
1285        ZephyrReadStaticAddrs(VENDOR_SPECIFIC, 0x0009) {
1286            Params = ();
1287            ZephyrReadStaticAddrsReturn {
1288                num_addresses: u8,
1289                addr: ZephyrStaticAddr, // The softdevice controller always returns exactly 1 static address
1290            }
1291        }
1292    }
1293
1294    cmd! {
1295        /// https://docs.zephyrproject.org/apidoc/latest/hci__vs_8h.html
1296        ZephyrReadKeyHierarchyRoots(VENDOR_SPECIFIC, 0x000a) {
1297            Params = ();
1298            ZephyrReadKeyHierarchyRootsReturn {
1299                ir: [u8; 16usize],
1300                er: [u8; 16usize],
1301            }
1302        }
1303    }
1304
1305    cmd! {
1306        /// https://docs.zephyrproject.org/apidoc/latest/hci__vs_8h.html
1307        ZephyrReadChipTemp(VENDOR_SPECIFIC, 0x000b) {
1308            Params = ();
1309            Return = i8;
1310        }
1311    }
1312
1313    cmd! {
1314        /// https://docs.zephyrproject.org/apidoc/latest/hci__vs_8h.html
1315        ZephyrWriteTxPower(VENDOR_SPECIFIC, 0x000e) {
1316            Params = ZephyrWriteTxPowerParams;
1317            Return = ZephyrTxPower;
1318        }
1319    }
1320
1321    param! {
1322        struct ZephyrWriteTxPowerParams {
1323            handle_type: u8,
1324            handle: u16,
1325            tx_power_level: i8,
1326        }
1327    }
1328
1329    cmd! {
1330        /// https://docs.zephyrproject.org/apidoc/latest/hci__vs_8h.html
1331        ZephyrReadTxPower(VENDOR_SPECIFIC, 0x000f) {
1332            Params = ZephyrReadTxPowerParams;
1333            Return = ZephyrTxPower;
1334        }
1335    }
1336
1337    param! {
1338        struct ZephyrReadTxPowerParams {
1339            handle_type: u8,
1340            handle: u16,
1341        }
1342    }
1343
1344    cmd! {
1345        NordicLlpmModeSet(VENDOR_SPECIFIC, 0x0101) {
1346            Params = bool;
1347            Return = ();
1348        }
1349    }
1350
1351    cmd! {
1352        NordicConnUpdate(VENDOR_SPECIFIC, 0x0102) {
1353            Params = NordicConnUpdateParams;
1354            Return = ();
1355        }
1356    }
1357
1358    param! {
1359        struct NordicConnUpdateParams {
1360            handle: ConnHandle,
1361            interval_us: u32,
1362            latency: u16,
1363            supervision_timeout: Duration<10_000>,
1364        }
1365    }
1366
1367    cmd! {
1368        NordicConnEventExtend(VENDOR_SPECIFIC, 0x0103) {
1369            Params = bool;
1370            Return = ();
1371        }
1372    }
1373
1374    cmd! {
1375        NordicQosConnEventReportEnable(VENDOR_SPECIFIC, 0x0104) {
1376            Params = bool;
1377            Return = ();
1378        }
1379    }
1380
1381    cmd! {
1382        NordicEventLengthSet(VENDOR_SPECIFIC, 0x0105) {
1383            Params = u32;
1384            Return = ();
1385        }
1386    }
1387
1388    cmd! {
1389        NordicPeriodicAdvEventLengthSet(VENDOR_SPECIFIC, 0x0106) {
1390            Params = u32;
1391            Return = ();
1392        }
1393    }
1394
1395    cmd! {
1396        NordicPeripheralLatencyModeSet(VENDOR_SPECIFIC, 0x0109) {
1397            Params = NordicPeripheralLatencyModeSetParams;
1398            Return = ();
1399        }
1400    }
1401
1402    param! {
1403        struct NordicPeripheralLatencyModeSetParams{
1404            handle: ConnHandle,
1405            mode: u8,
1406         }
1407    }
1408
1409    cmd! {
1410        NordicWriteRemoteTxPower(VENDOR_SPECIFIC, 0x010a) {
1411            Params = NordicWriteRemoteTxPowerParams;
1412            Return = ();
1413        }
1414    }
1415
1416    param! {
1417        struct NordicWriteRemoteTxPowerParams {
1418            handle: ConnHandle,
1419            phy: u8,
1420            delta: i8,
1421        }
1422    }
1423
1424    cmd! {
1425        NordicSetAdvRandomness(VENDOR_SPECIFIC, 0x010c) {
1426            Params = NordicSetAdvRandomnessParams;
1427            Return = ();
1428        }
1429    }
1430
1431    param! {
1432        struct NordicSetAdvRandomnessParams {
1433            adv_handle: u8,
1434            rand_us: u16,
1435        }
1436    }
1437
1438    cmd! {
1439        NordicCompatModeWindowOffsetSet(VENDOR_SPECIFIC, 0x010d) {
1440            Params = bool;
1441            Return = ();
1442        }
1443    }
1444
1445    cmd! {
1446        NordicQosChannelSurveyEnable(VENDOR_SPECIFIC, 0x010e) {
1447            NordicQosChannelSurveyEnableParams {
1448                enable: bool,
1449                interval_us: u32,
1450            }
1451            Return = ();
1452        }
1453    }
1454
1455    cmd! {
1456        NordicSetPowerControlRequestParams(VENDOR_SPECIFIC, 0x0110) {
1457            NordicSetPowerControlRequestParamsParams {
1458                auto_enable: bool,
1459                apr_enable: bool,
1460                beta: u16,
1461                lower_limit: i8,
1462                upper_limit: i8,
1463                lower_target_rssi: i8,
1464                upper_target_rssi: i8,
1465                wait_period_ms: Duration<1_000>,
1466                apr_margin: u8,
1467            }
1468            Return = ();
1469        }
1470    }
1471
1472    cmd! {
1473        NordicReadAverageRssi(VENDOR_SPECIFIC, 0x111) {
1474            Params = ConnHandle;
1475            NordicReadAverageRssiReturn {
1476                avg_rssi: i8,
1477            }
1478            Handle = handle: ConnHandle;
1479        }
1480    }
1481
1482    cmd! {
1483        NordicCentralAclEventSpacingSet(VENDOR_SPECIFIC, 0x112) {
1484            Params = u32;
1485            Return = ();
1486        }
1487    }
1488
1489    cmd! {
1490        NordicGetNextConnEventCounter(VENDOR_SPECIFIC, 0x114) {
1491            Params = ConnHandle;
1492            NordicGetNextConnEventCounterReturn {
1493                next_conn_event_counter: u16,
1494            }
1495            Handle = handle: ConnHandle;
1496        }
1497    }
1498
1499    cmd! {
1500        NordicAllowParallelConnectionEstablishments(VENDOR_SPECIFIC, 0x115) {
1501            Params = bool;
1502            Return = ();
1503        }
1504    }
1505
1506    cmd! {
1507        NordicMinValOfMaxAclTxPayloadSet(VENDOR_SPECIFIC, 0x116) {
1508            Params = u8;
1509            Return = ();
1510        }
1511    }
1512
1513    cmd! {
1514        NordicIsoReadTxTimestamp(VENDOR_SPECIFIC, 0x117) {
1515            Params = ConnHandle;
1516            NordicIsoReadTxTimestampReturn {
1517                packet_sequence_number: u16,
1518                tx_time_stamp: u32,
1519            }
1520            Handle = handle: ConnHandle;
1521        }
1522    }
1523
1524    cmd! {
1525        NordicBigReservedTimeSet(VENDOR_SPECIFIC, 0x118) {
1526            Params = u32;
1527            Return = ();
1528        }
1529    }
1530
1531    cmd! {
1532        NordicCigReservedTimeSet(VENDOR_SPECIFIC, 0x119) {
1533            Params = u32;
1534            Return = ();
1535        }
1536    }
1537
1538    cmd! {
1539        NordicCisSubeventLengthSet(VENDOR_SPECIFIC, 0x11a) {
1540            Params = u32;
1541            Return = ();
1542        }
1543    }
1544
1545    cmd! {
1546        NordicScanChannelMapSet(VENDOR_SPECIFIC, 0x11b) {
1547            Params = ChannelMap;
1548            Return = ();
1549        }
1550    }
1551
1552    cmd! {
1553        NordicScanAcceptExtAdvPacketsSet(VENDOR_SPECIFIC, 0x11c) {
1554            Params = bool;
1555            Return = ();
1556        }
1557    }
1558
1559    cmd! {
1560        NordicSetRolePriority(VENDOR_SPECIFIC, 0x11d) {
1561            NordicSetRolePriorityParams {
1562                handle_type: u8,
1563                handle: u16,
1564                priority: u8,
1565            }
1566            Return = ();
1567        }
1568    }
1569
1570    cmd! {
1571        NordicSetEventStartTask(VENDOR_SPECIFIC, 0x11e) {
1572            NordicSetEventStartTaskParams {
1573                handle_type: u8,
1574                handle: u16,
1575                task_address: u32,
1576            }
1577            Return = ();
1578        }
1579    }
1580
1581    cmd! {
1582        NordicConnAnchorPointUpdateEventReportEnable(VENDOR_SPECIFIC, 0x11f) {
1583            Params = bool;
1584            Return = ();
1585        }
1586    }
1587
1588    sdc_cmd!(ZephyrReadVersionInfo => sdc_hci_cmd_vs_zephyr_read_version_info() -> y);
1589    sdc_cmd!(ZephyrReadSupportedCommands => sdc_hci_cmd_vs_zephyr_read_supported_commands() -> y);
1590    sdc_cmd!(ZephyrWriteBdAddr => sdc_hci_cmd_vs_zephyr_write_bd_addr(x));
1591    sdc_cmd!(ZephyrReadKeyHierarchyRoots => sdc_hci_cmd_vs_zephyr_read_key_hierarchy_roots() -> y);
1592    sdc_cmd!(ZephyrReadChipTemp => sdc_hci_cmd_vs_zephyr_read_chip_temp() -> y);
1593    sdc_cmd!(ZephyrWriteTxPower => sdc_hci_cmd_vs_zephyr_write_tx_power(x) -> y);
1594    sdc_cmd!(ZephyrReadTxPower => sdc_hci_cmd_vs_zephyr_read_tx_power(x) -> y);
1595    sdc_cmd!(NordicLlpmModeSet => sdc_hci_cmd_vs_llpm_mode_set(x));
1596    sdc_cmd!(NordicConnUpdate => sdc_hci_cmd_vs_conn_update(x));
1597    sdc_cmd!(NordicConnEventExtend => sdc_hci_cmd_vs_conn_event_extend(x));
1598    sdc_cmd!(NordicQosConnEventReportEnable => sdc_hci_cmd_vs_qos_conn_event_report_enable(x));
1599    sdc_cmd!(NordicEventLengthSet => sdc_hci_cmd_vs_event_length_set(x));
1600    sdc_cmd!(NordicPeriodicAdvEventLengthSet => sdc_hci_cmd_vs_periodic_adv_event_length_set(x));
1601    sdc_cmd!(NordicPeripheralLatencyModeSet => sdc_hci_cmd_vs_peripheral_latency_mode_set(x));
1602    sdc_cmd!(NordicWriteRemoteTxPower => sdc_hci_cmd_vs_write_remote_tx_power(x));
1603    sdc_cmd!(NordicSetAdvRandomness => sdc_hci_cmd_vs_set_adv_randomness(x));
1604    sdc_cmd!(NordicCompatModeWindowOffsetSet => sdc_hci_cmd_vs_compat_mode_window_offset_set(x));
1605    sdc_cmd!(NordicQosChannelSurveyEnable => sdc_hci_cmd_vs_qos_channel_survey_enable(x));
1606    sdc_cmd!(NordicSetPowerControlRequestParams => sdc_hci_cmd_vs_set_power_control_request_params(x));
1607    sdc_cmd!(NordicReadAverageRssi => sdc_hci_cmd_vs_read_average_rssi(x) -> y);
1608    sdc_cmd!(NordicCentralAclEventSpacingSet => sdc_hci_cmd_vs_central_acl_event_spacing_set(x));
1609    sdc_cmd!(NordicGetNextConnEventCounter => sdc_hci_cmd_vs_get_next_conn_event_counter(x) -> y);
1610    sdc_cmd!(NordicAllowParallelConnectionEstablishments => sdc_hci_cmd_vs_allow_parallel_connection_establishments(x));
1611    sdc_cmd!(NordicMinValOfMaxAclTxPayloadSet => sdc_hci_cmd_vs_min_val_of_max_acl_tx_payload_set(x));
1612    sdc_cmd!(NordicIsoReadTxTimestamp => sdc_hci_cmd_vs_iso_read_tx_timestamp(x) -> y);
1613    sdc_cmd!(NordicBigReservedTimeSet => sdc_hci_cmd_vs_big_reserved_time_set(x));
1614    sdc_cmd!(NordicCigReservedTimeSet => sdc_hci_cmd_vs_cig_reserved_time_set(x));
1615    sdc_cmd!(NordicCisSubeventLengthSet => sdc_hci_cmd_vs_cis_subevent_length_set(x));
1616    sdc_cmd!(NordicScanChannelMapSet => sdc_hci_cmd_vs_scan_channel_map_set(x));
1617    sdc_cmd!(NordicScanAcceptExtAdvPacketsSet => sdc_hci_cmd_vs_scan_accept_ext_adv_packets_set(x));
1618    sdc_cmd!(NordicSetRolePriority => sdc_hci_cmd_vs_set_role_priority(x));
1619    sdc_cmd!(NordicSetEventStartTask => sdc_hci_cmd_vs_set_event_start_task(x));
1620    sdc_cmd!(NordicConnAnchorPointUpdateEventReportEnable => sdc_hci_cmd_vs_conn_anchor_point_update_event_report_enable(x));
1621
1622    impl<'d> ControllerCmdSync<ZephyrReadStaticAddrs> for super::SoftdeviceController<'d> {
1623        async fn exec(
1624            &self,
1625            _cmd: &ZephyrReadStaticAddrs,
1626        ) -> Result<<ZephyrReadStaticAddrs as bt_hci::cmd::SyncCmd>::Return, CmdError<Self::Error>> {
1627            const N: usize = core::mem::size_of::<ZephyrReadStaticAddrsReturn>();
1628            let mut out = [0; N];
1629            let ret = unsafe { raw::sdc_hci_cmd_vs_zephyr_read_static_addresses(out.as_mut_ptr() as *mut _) };
1630            bt_hci::param::Status::from(ret).to_result()?;
1631            Ok(unwrap!(ZephyrReadStaticAddrsReturn::from_hci_bytes_complete(&out)))
1632        }
1633    }
1634}