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