android_ble/
characteristic.rs1use std::sync::Arc;
2
3use futures_core::Stream;
4use java_spaghetti::ByteArray;
5use uuid::Uuid;
6
7use super::bindings::android::bluetooth::BluetoothGattCharacteristic;
8use super::descriptor::Descriptor;
9use super::error::ErrorKind;
10use super::gatt_tree::{CachedWeak, CharacteristicInner, GattTree};
11use super::jni::{ByteArrayExt, Monitor};
12use super::util::{BoolExt, IntExt, OptionExt};
13use super::vm_context::{android_api_level, jni_with_env};
14use super::{CharacteristicProperties, DeviceId, Result};
15
16#[derive(Debug, Clone)]
18pub struct Characteristic {
19 dev_id: DeviceId,
20 service_id: Uuid,
21 char_id: Uuid,
22 inner: CachedWeak<CharacteristicInner>,
23}
24
25impl PartialEq for Characteristic {
26 fn eq(&self, other: &Self) -> bool {
27 self.dev_id == other.dev_id
28 && self.service_id == other.service_id
29 && self.char_id == other.char_id
30 }
31}
32
33impl Eq for Characteristic {}
34
35impl std::hash::Hash for Characteristic {
36 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
37 self.dev_id.hash(state);
38 self.service_id.hash(state);
39 self.char_id.hash(state);
40 }
41}
42
43impl Characteristic {
44 pub(crate) fn new(dev_id: DeviceId, service_id: Uuid, char_id: Uuid) -> Self {
45 Self {
46 dev_id,
47 service_id,
48 char_id,
49 inner: CachedWeak::new(),
50 }
51 }
52
53 pub fn uuid(&self) -> Uuid {
55 self.char_id
56 }
57
58 pub async fn uuid_async(&self) -> Result<Uuid> {
60 Ok(self.char_id)
61 }
62
63 pub async fn properties(&self) -> Result<CharacteristicProperties> {
68 jni_with_env(|env| {
69 let val = self.get_inner()?.char.as_ref(env).getProperties()?;
70 Ok(CharacteristicProperties::from_bits(val.cast_unsigned()))
71 })
72 }
73
74 pub async fn value(&self) -> Result<Vec<u8>> {
76 self.get_inner()?
77 .read
78 .last_value()
79 .ok_or(crate::Error::new(
80 ErrorKind::NotReady,
81 None,
82 "please call `Characteristic::read` at first",
83 ))?
84 }
85
86 pub async fn read(&self) -> Result<Vec<u8>> {
94 let conn = GattTree::check_connection(&self.dev_id)?;
95 let inner = self.get_inner()?;
96 let read_lock = inner.read.lock().await;
97 let _write_lock = inner.write.lock().await;
98 jni_with_env(|env| {
99 let gatt = &conn.gatt.as_ref(env);
100 let gatt = Monitor::new(gatt);
101 gatt.readCharacteristic(inner.char.as_ref(env))
102 .map_err(|e| e.into())
103 .and_then(|b| b.non_false())
104 })?;
105 drop((conn, inner));
106 read_lock
107 .wait_unlock()
108 .await
109 .ok_or_check_conn(&self.dev_id)?
110 }
111
112 pub async fn write(&self, value: &[u8]) -> Result<()> {
115 self.write_internal(value, true).await
118 }
119
120 pub async fn write_without_response(&self, value: &[u8]) -> Result<()> {
122 if value.len() <= self.max_write_len()? {
129 self.write_internal(value, false).await
130 } else {
131 Err(crate::Error::new(
132 ErrorKind::InvalidParameter,
133 None,
134 "write length probably exceeded the MTU's limitation",
135 ))
136 }
137 }
138
139 async fn write_internal(&self, value: &[u8], with_response: bool) -> Result<()> {
140 let conn = GattTree::check_connection(&self.dev_id)?;
141 let inner = self.get_inner()?;
142 let _read_lock = inner.read.lock().await;
143 let write_lock = inner.write.lock().await;
144 jni_with_env(|env| {
145 let gatt = conn.gatt.as_ref(env);
146 let gatt = Monitor::new(&gatt);
147 let char = inner.char.as_ref(env);
148 let array = ByteArray::from_slice(env, value);
149 let write_type = if with_response {
150 BluetoothGattCharacteristic::WRITE_TYPE_DEFAULT
151 } else {
152 BluetoothGattCharacteristic::WRITE_TYPE_NO_RESPONSE
153 };
154 char.setWriteType(write_type)?;
155 if android_api_level() >= 33 {
156 gatt.writeCharacteristic_BluetoothGattCharacteristic_byte_array_int(
157 char, array, write_type,
158 )?
159 .check_status_code()
160 } else {
161 #[allow(deprecated)]
162 char.setValue_byte_array(array)?;
163 #[allow(deprecated)]
164 gatt.writeCharacteristic_BluetoothGattCharacteristic(char)
165 .map_err(|e| e.into())
166 .and_then(|b| b.non_false())
167 }
168 })?;
169 drop((conn, inner));
170 write_lock
171 .wait_unlock()
172 .await
173 .ok_or_check_conn(&self.dev_id)?
174 }
175
176 pub fn max_write_len(&self) -> Result<usize> {
183 let conn = GattTree::check_connection(&self.dev_id)?;
184 let mtu = conn.mtu_changed_received.last_value().unwrap_or(23);
185 Ok(mtu - 5)
186 }
187
188 pub async fn max_write_len_async(&self) -> Result<usize> {
190 self.max_write_len()
191 }
192
193 pub async fn notify(&self) -> Result<impl Stream<Item = Result<Vec<u8>>> + Send + Unpin + '_> {
197 let conn = GattTree::check_connection(&self.dev_id)?;
198 let inner = self.get_inner()?;
199 let inner_2 = inner.clone();
200 let (gatt_for_stop, char_for_stop) = (conn.gatt.clone(), inner.char.clone());
201 inner
202 .notify
203 .subscribe(
204 move || {
205 jni_with_env(|env| {
206 let gatt = conn.gatt.as_ref(env);
207 let gatt = Monitor::new(&gatt);
208 let result =
209 gatt.setCharacteristicNotification(inner_2.char.as_ref(env), true)?;
210 result.non_false()
211 })
212 },
213 move || {
214 jni_with_env(|env| {
215 let gatt = gatt_for_stop.as_ref(env);
216 let gatt = Monitor::new(&gatt);
217 let _ =
218 gatt.setCharacteristicNotification(char_for_stop.as_ref(env), false);
219 })
220 },
221 )
222 .await
223 }
224
225 pub async fn is_notifying(&self) -> Result<bool> {
227 Ok(self.get_inner()?.notify.is_notifying())
228 }
229
230 pub async fn discover_descriptors(&self) -> Result<Vec<Descriptor>> {
232 self.descriptors().await
233 }
234
235 pub async fn descriptors(&self) -> Result<Vec<Descriptor>> {
237 Ok(self
238 .get_inner()?
239 .descs
240 .keys()
241 .map(|id| Descriptor::new(self.dev_id.clone(), self.service_id, self.char_id, *id))
242 .collect())
243 }
244
245 fn get_inner(&self) -> Result<Arc<CharacteristicInner>, crate::Error> {
246 self.inner.get_or_find(|| {
247 GattTree::find_characteristic(&self.dev_id, self.service_id, self.char_id)
248 .ok_or_check_conn(&self.dev_id)
249 })
250 }
251}