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 //! HCI packet transport 16 17 use crate::wrapper::controller::Controller; 18 use futures::executor::block_on; 19 use pyo3::{intern, types::PyModule, PyObject, PyResult, Python}; 20 21 /// A source/sink pair for HCI packet I/O. 22 /// 23 /// See <https://google.github.io/bumble/transports/index.html>. 24 pub struct Transport(PyObject); 25 26 impl Transport { 27 /// Open a new Transport for the provided spec, e.g. `"usb:0"` or `"android-netsim"`. open(transport_spec: impl Into<String>) -> PyResult<Self>28 pub async fn open(transport_spec: impl Into<String>) -> PyResult<Self> { 29 Python::with_gil(|py| { 30 PyModule::import(py, intern!(py, "bumble.transport"))? 31 .call_method1(intern!(py, "open_transport"), (transport_spec.into(),)) 32 .and_then(pyo3_asyncio::tokio::into_future) 33 })? 34 .await 35 .map(Self) 36 } 37 38 /// Close the transport. close(&mut self) -> PyResult<()>39 pub async fn close(&mut self) -> PyResult<()> { 40 Python::with_gil(|py| { 41 self.0 42 .call_method0(py, intern!(py, "close")) 43 .and_then(|coroutine| pyo3_asyncio::tokio::into_future(coroutine.as_ref(py))) 44 })? 45 .await 46 .map(|_| ()) 47 } 48 49 /// Returns the source half of the transport. source(&self) -> PyResult<Source>50 pub fn source(&self) -> PyResult<Source> { 51 Python::with_gil(|py| self.0.getattr(py, intern!(py, "source"))).map(Source) 52 } 53 54 /// Returns the sink half of the transport. sink(&self) -> PyResult<Sink>55 pub fn sink(&self) -> PyResult<Sink> { 56 Python::with_gil(|py| self.0.getattr(py, intern!(py, "sink"))).map(Sink) 57 } 58 } 59 60 impl Drop for Transport { drop(&mut self)61 fn drop(&mut self) { 62 // don't spawn a thread to handle closing, as it may get dropped at program termination, 63 // resulting in `RuntimeWarning: coroutine ... was never awaited` from Python 64 let _ = block_on(self.close()); 65 } 66 } 67 68 /// The source side of a [Transport]. 69 #[derive(Clone)] 70 pub struct Source(pub(crate) PyObject); 71 72 impl From<Controller> for Source { from(value: Controller) -> Self73 fn from(value: Controller) -> Self { 74 Self(value.0) 75 } 76 } 77 78 /// The sink side of a [Transport]. 79 #[derive(Clone)] 80 pub struct Sink(pub(crate) PyObject); 81 82 impl From<Controller> for Sink { from(value: Controller) -> Self83 fn from(value: Controller) -> Self { 84 Self(value.0) 85 } 86 } 87