1 // Copyright 2023 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //! GATT client support 16 17 use crate::wrapper::ClosureCallback; 18 use pyo3::types::PyTuple; 19 use pyo3::{intern, PyObject, PyResult, Python}; 20 21 /// A GATT service on a remote device 22 pub struct ServiceProxy(pub(crate) PyObject); 23 24 impl ServiceProxy { 25 /// Discover the characteristics in this service. 26 /// 27 /// Populates an internal cache of characteristics in this service. discover_characteristics(&mut self) -> PyResult<()>28 pub async fn discover_characteristics(&mut self) -> PyResult<()> { 29 Python::with_gil(|py| { 30 self.0 31 .call_method0(py, intern!(py, "discover_characteristics")) 32 .and_then(|coroutine| pyo3_asyncio::tokio::into_future(coroutine.as_ref(py))) 33 })? 34 .await 35 .map(|_| ()) 36 } 37 } 38 39 /// A GATT characteristic on a remote device 40 pub struct CharacteristicProxy(pub(crate) PyObject); 41 42 impl CharacteristicProxy { 43 /// Subscribe to changes to the characteristic, executing `callback` for each new value subscribe( &mut self, callback: impl Fn(Python, &PyTuple) -> PyResult<()> + Send + 'static, ) -> PyResult<()>44 pub async fn subscribe( 45 &mut self, 46 callback: impl Fn(Python, &PyTuple) -> PyResult<()> + Send + 'static, 47 ) -> PyResult<()> { 48 let boxed = ClosureCallback::new(move |py, args, _kwargs| callback(py, args)); 49 50 Python::with_gil(|py| { 51 self.0 52 .call_method1(py, intern!(py, "subscribe"), (boxed,)) 53 .and_then(|obj| pyo3_asyncio::tokio::into_future(obj.as_ref(py))) 54 })? 55 .await 56 .map(|_| ()) 57 } 58 59 /// Read the current value of the characteristic read_value(&self) -> PyResult<PyObject>60 pub async fn read_value(&self) -> PyResult<PyObject> { 61 Python::with_gil(|py| { 62 self.0 63 .call_method0(py, intern!(py, "read_value")) 64 .and_then(|obj| pyo3_asyncio::tokio::into_future(obj.as_ref(py))) 65 })? 66 .await 67 } 68 } 69 70 /// Equivalent to the Python `ProfileServiceProxy`. 71 pub trait ProfileServiceProxy { 72 /// The module containing the proxy class 73 const PROXY_CLASS_MODULE: &'static str; 74 /// The module class name 75 const PROXY_CLASS_NAME: &'static str; 76 77 /// Wrap a PyObject in the Rust wrapper type wrap(obj: PyObject) -> Self78 fn wrap(obj: PyObject) -> Self; 79 } 80