RKTK API Docs RKTK Home Repo

rktk_drivers_nrf/softdevice/split/
central.rs

1use core::marker::PhantomData;
2use core::slice;
3
4use embassy_futures::join::join;
5use embassy_sync::pipe::Pipe;
6use nrf_softdevice::ble::{central, l2cap, Address, TxPower};
7use nrf_softdevice::Softdevice;
8use rktk::drivers::interface::split::SplitDriver;
9use rktk::utils::RawMutex;
10use rktk_log::{error, info};
11
12use super::packet::Packet;
13use super::{PSM, RKTK_SPLIT_SERVICE_ID};
14
15static TX_PIPE: Pipe<RawMutex, 128> = Pipe::new();
16static RX_PIPE: Pipe<RawMutex, 128> = Pipe::new();
17
18#[embassy_executor::task]
19async fn ble_split_central_task(sd: &'static Softdevice) {
20    embassy_time::Timer::after_secs(3).await;
21    error!("Scanning for peer...");
22
23    let config = central::ScanConfig {
24        whitelist: None,
25        tx_power: TxPower::ZerodBm,
26        ..Default::default()
27    };
28    let res = central::scan(sd, &config, |params| {
29        let mut data =
30            unsafe { slice::from_raw_parts(params.data.p_data, params.data.len as usize) };
31        while !data.is_empty() {
32            let len = data[0] as usize;
33            if data.len() < len + 1 {
34                break;
35            }
36            if len < 1 {
37                break;
38            }
39            let key = data[1];
40            let value = &data[2..len + 1];
41
42            if key == 0x07 && value == RKTK_SPLIT_SERVICE_ID {
43                // info!("{:X}:{:X?}", key, &value);
44                return Some(Address::from_raw(params.peer_addr));
45            }
46            data = &data[len + 1..];
47        }
48        None
49    })
50    .await;
51
52    let address = res.unwrap();
53    rktk::print!("Found slave address {:?}", address);
54
55    let addrs = &[&address];
56
57    let mut config = central::ConnectConfig::default();
58    config.scan_config.whitelist = Some(addrs);
59    let conn = match central::connect(sd, &config).await {
60        Ok(conn) => conn,
61        Err(e) => {
62            error!("connect failed: {:?}", e);
63            return;
64        }
65    };
66
67    let l = l2cap::L2cap::<super::packet::Packet>::init(sd);
68    let config = l2cap::Config { credits: 8 };
69    let ch = match l.setup(&conn, &config, PSM).await {
70        Ok(ch) => ch,
71        Err(e) => {
72            error!("l2cap connect failed: {:?}", e);
73            return;
74        }
75    };
76
77    info!("Starting split handler");
78
79    let ch2 = ch.clone();
80    join(
81        async move {
82            loop {
83                let Ok(p) = ch.rx().await else {
84                    embassy_time::Timer::after_millis(100).await;
85                    continue;
86                };
87                RX_PIPE.write_all(p.as_bytes()).await;
88            }
89        },
90        async move {
91            loop {
92                let mut buf = [0; 128];
93                let size = TX_PIPE.read(&mut buf).await;
94                let packet = Packet::new(&buf[0..size]);
95                let _ = ch2.tx(packet).await;
96            }
97        },
98    )
99    .await;
100}
101
102/// Split driver for central (master) side.
103pub struct SoftdeviceBleCentralSplitDriver {
104    _phantom: PhantomData<()>,
105}
106
107impl SoftdeviceBleCentralSplitDriver {
108    pub async fn new(sd: &'static Softdevice) -> Self {
109        embassy_executor::Spawner::for_current_executor()
110            .await
111            .spawn(ble_split_central_task(sd))
112            .unwrap();
113
114        Self {
115            _phantom: PhantomData,
116        }
117    }
118}
119
120impl SplitDriver for SoftdeviceBleCentralSplitDriver {
121    type Error = core::convert::Infallible;
122
123    async fn recv(&mut self, buf: &mut [u8], _is_master: bool) -> Result<usize, Self::Error> {
124        let size = RX_PIPE.read(buf).await;
125        Ok(size)
126    }
127
128    async fn send_all(&mut self, buf: &[u8], _is_master: bool) -> Result<(), Self::Error> {
129        TX_PIPE.write_all(buf).await;
130        Ok(())
131    }
132}