esp32_nimble/client/
ble_reader.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use alloc::vec::Vec;
use core::ffi::c_void;
use esp_idf_svc::sys as esp_idf_sys;

use crate::{
  ble,
  utilities::{voidp_to_ref, OsMBuf},
  BLEError, Signal,
};

pub struct BLEReader {
  conn_handle: u16,
  handle: u16,
  signal: Signal<u32>,
}

impl BLEReader {
  pub fn new(conn_handle: u16, handle: u16) -> Self {
    Self {
      conn_handle,
      handle,
      signal: Signal::new(),
    }
  }

  pub async fn read_value(&mut self) -> Result<Vec<u8>, BLEError> {
    let data = Vec::<u8>::new();
    let mut arg = (self, data);

    unsafe {
      ble!(esp_idf_sys::ble_gattc_read_long(
        arg.0.conn_handle,
        arg.0.handle,
        0,
        Some(Self::on_read_cb),
        core::ptr::addr_of_mut!(arg) as _,
      ))?;
    }

    ble!(arg.0.signal.wait().await)?;
    Ok(arg.1)
  }

  extern "C" fn on_read_cb(
    conn_handle: u16,
    error: *const esp_idf_sys::ble_gatt_error,
    attr: *mut esp_idf_sys::ble_gatt_attr,
    arg: *mut c_void,
  ) -> i32 {
    let (reader, data) = unsafe { voidp_to_ref::<(&mut Self, Vec<u8>)>(arg) };
    if conn_handle != reader.conn_handle {
      return 0;
    }

    let error = unsafe { &*error };

    if error.status == 0 {
      if let Some(attr) = unsafe { attr.as_ref() } {
        for om in OsMBuf(attr.om).iter() {
          data.extend_from_slice(om.as_slice());
        }

        return 0;
      }
    }

    reader.signal.signal(error.status as _);
    error.status as _
  }
}