RKTK API Docs RKTK Home Repo

rktk_drivers_nrf/softdevice/split/
peripheral.rs

1use core::marker::PhantomData;
2
3use embassy_futures::join::join;
4use embassy_sync::pipe::Pipe;
5use nrf_softdevice::{
6    ble::{
7        advertisement_builder::{
8            Flag, LegacyAdvertisementBuilder, LegacyAdvertisementPayload, ServiceList,
9        },
10        l2cap, peripheral,
11    },
12    Softdevice,
13};
14use rktk::drivers::interface::split::SplitDriver;
15use rktk::utils::RawMutex;
16use rktk_log::error;
17
18use super::packet::Packet;
19use super::PSM;
20
21static TX_PIPE: Pipe<RawMutex, 128> = Pipe::new();
22static RX_PIPE: Pipe<RawMutex, 128> = Pipe::new();
23
24#[embassy_executor::task]
25async fn ble_split_peripheral_task(sd: &'static Softdevice) {
26    embassy_time::Timer::after_secs(3).await;
27    error!("ble split start");
28
29    static ADV_DATA: LegacyAdvertisementPayload = LegacyAdvertisementBuilder::new()
30        .flags(&[Flag::GeneralDiscovery, Flag::LE_Only])
31        .services_128(ServiceList::Complete, &[super::RKTK_SPLIT_SERVICE_ID])
32        .short_name("H")
33        .build();
34
35    static SCAN_DATA: [u8; 0] = [];
36
37    let l = l2cap::L2cap::<Packet>::init(sd);
38
39    let config = peripheral::Config::default();
40    let adv = peripheral::ConnectableAdvertisement::ScannableUndirected {
41        adv_data: &ADV_DATA,
42        scan_data: &SCAN_DATA,
43    };
44    let conn = loop {
45        match peripheral::advertise_connectable(sd, adv, &config).await {
46            Ok(conn) => break conn,
47            Err(e) => {
48                rktk::print!("{:?}", e);
49                continue;
50            }
51        };
52    };
53
54    rktk::print!("advertising done!");
55
56    let config = l2cap::Config { credits: 8 };
57    let ch = l.listen(&conn, &config, PSM).await.unwrap();
58    rktk::print!("l2cap connected");
59
60    let ch2 = ch.clone();
61    join(
62        async move {
63            loop {
64                let Ok(p) = ch.rx().await else {
65                    continue;
66                };
67                rktk::print!("Received: {:?}", p);
68                RX_PIPE.write_all(p.as_bytes()).await;
69            }
70        },
71        async move {
72            loop {
73                let mut buf = [0; 128];
74                let size = TX_PIPE.read(&mut buf).await;
75                let packet = Packet::new(&buf[0..size]);
76                rktk::print!("Sending: {:?}", packet);
77                let _ = ch2.tx(packet).await;
78            }
79        },
80    )
81    .await;
82}
83
84/// Split driver for peripheral (slave) side.
85pub struct SoftdeviceBlePeripheralSplitDriver {
86    _phantom: PhantomData<()>,
87}
88
89impl SoftdeviceBlePeripheralSplitDriver {
90    pub async fn new(sd: &'static Softdevice) -> Self {
91        embassy_executor::Spawner::for_current_executor()
92            .await
93            .spawn(ble_split_peripheral_task(sd))
94            .unwrap();
95
96        Self {
97            _phantom: PhantomData,
98        }
99    }
100}
101
102impl SplitDriver for SoftdeviceBlePeripheralSplitDriver {
103    type Error = core::convert::Infallible;
104
105    async fn recv(&mut self, buf: &mut [u8], _is_master: bool) -> Result<usize, Self::Error> {
106        let size = RX_PIPE.read(buf).await;
107        Ok(size)
108    }
109
110    async fn send_all(&mut self, buf: &[u8], _is_master: bool) -> Result<(), Self::Error> {
111        TX_PIPE.write_all(buf).await;
112        Ok(())
113    }
114}