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