Skip to main content

esp32_nimble/l2cap/
l2cap_server.rs

1use super::{L2cap, L2capChannel, ReceivedData};
2use crate::{
3    BLEError, Channel, ble,
4    utilities::{as_void_ptr, extend_lifetime_mut, mutex::Mutex, voidp_to_ref},
5};
6use esp_idf_svc::sys;
7
8const N: usize = sys::CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM as usize;
9static SERVER_LIST: Mutex<heapless::Vec<L2capServer, N>> = Mutex::new(heapless::Vec::new());
10
11#[allow(clippy::type_complexity)]
12pub struct L2capServer {
13    l2cap: L2cap,
14    channel: Channel<ReceivedData, 1>,
15}
16
17impl L2capServer {
18    pub fn create(psm: u16, mtu: u16) -> Result<&'static mut L2capServer, BLEError> {
19        let mut list = SERVER_LIST.lock();
20        list.push(L2capServer {
21            l2cap: Default::default(),
22            channel: Channel::new(),
23        })
24        .map_err(|_| BLEError::convert(sys::BLE_HS_ENOMEM as _).unwrap_err())?;
25
26        let server = list.last_mut().unwrap();
27        server.l2cap.init(mtu, 20)?;
28
29        unsafe {
30            ble!(sys::ble_l2cap_create_server(
31                psm,
32                mtu,
33                Some(Self::handle_l2cap_event),
34                as_void_ptr(server),
35            ))?;
36        }
37        Ok(unsafe { extend_lifetime_mut(server) })
38    }
39
40    pub fn tx(&mut self, channel: L2capChannel, data: &[u8]) -> Result<(), BLEError> {
41        self.l2cap.tx(channel.0, data)
42    }
43
44    pub async fn rx(&mut self) -> ReceivedData {
45        self.channel.receive().await
46    }
47
48    pub(crate) extern "C" fn handle_l2cap_event(
49        _event: *mut sys::ble_l2cap_event,
50        arg: *mut core::ffi::c_void,
51    ) -> i32 {
52        let event = unsafe { &*_event };
53        let server = unsafe { voidp_to_ref::<Self>(arg) };
54
55        match event.type_ as _ {
56            sys::BLE_L2CAP_EVENT_COC_CONNECTED => {
57                let connect = unsafe { event.__bindgen_anon_1.connect };
58                if connect.status > 0 {
59                    ::log::warn!("LE COC error: {}", connect.status);
60                    return 0;
61                }
62
63                0
64            }
65            sys::BLE_L2CAP_EVENT_COC_DISCONNECTED => {
66                let disconnect = unsafe { event.__bindgen_anon_1.disconnect };
67                ::log::debug!("LE CoC disconnected: {:?}", disconnect.chan);
68                0
69            }
70            sys::BLE_L2CAP_EVENT_COC_ACCEPT => {
71                let accept = unsafe { event.__bindgen_anon_1.accept };
72                server.l2cap.ble_l2cap_recv_ready(accept.chan);
73                0
74            }
75            sys::BLE_L2CAP_EVENT_COC_DATA_RECEIVED => {
76                let receive = unsafe { event.__bindgen_anon_1.receive };
77                if !receive.sdu_rx.is_null() {
78                    let _ = server.channel.try_send(ReceivedData::from_raw(receive));
79                }
80                server.l2cap.ble_l2cap_recv_ready(receive.chan);
81                0
82            }
83
84            _ => 0,
85        }
86    }
87}
88
89unsafe impl Send for L2capServer {}