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 //! Host-side types 16 17 use crate::wrapper::{ 18 transport::{Sink, Source}, 19 wrap_python_async, 20 }; 21 use pyo3::{intern, prelude::PyModule, types::PyDict, PyObject, PyResult, Python, ToPyObject}; 22 use pyo3_asyncio::tokio::into_future; 23 24 /// Host HCI commands 25 pub struct Host { 26 pub(crate) obj: PyObject, 27 } 28 29 impl Host { 30 /// Create a Host that wraps the provided obj from(obj: PyObject) -> Self31 pub(crate) fn from(obj: PyObject) -> Self { 32 Self { obj } 33 } 34 35 /// Create a new Host new(source: Source, sink: Sink) -> PyResult<Self>36 pub async fn new(source: Source, sink: Sink) -> PyResult<Self> { 37 Python::with_gil(|py| { 38 let host_ctr = 39 PyModule::import(py, intern!(py, "bumble.host"))?.getattr(intern!(py, "Host"))?; 40 41 let kwargs = PyDict::new(py); 42 kwargs.set_item("controller_source", source.0)?; 43 kwargs.set_item("controller_sink", sink.0)?; 44 45 // Needed for Python 3.8-3.9, in which the Semaphore object, when constructed, calls 46 // `get_event_loop`. 47 wrap_python_async(py, host_ctr)? 48 .call((), Some(kwargs)) 49 .and_then(into_future) 50 })? 51 .await 52 .map(|any| Self { obj: any }) 53 } 54 55 /// Send a reset command and perform other reset tasks. reset(&mut self, driver_factory: DriverFactory) -> PyResult<()>56 pub async fn reset(&mut self, driver_factory: DriverFactory) -> PyResult<()> { 57 Python::with_gil(|py| { 58 let kwargs = match driver_factory { 59 DriverFactory::None => { 60 let kw = PyDict::new(py); 61 kw.set_item("driver_factory", py.None())?; 62 Some(kw) 63 } 64 DriverFactory::Auto => { 65 // leave the default in place 66 None 67 } 68 }; 69 self.obj 70 .call_method(py, intern!(py, "reset"), (), kwargs) 71 .and_then(|coroutine| pyo3_asyncio::tokio::into_future(coroutine.as_ref(py))) 72 })? 73 .await 74 .map(|_| ()) 75 } 76 } 77 78 impl ToPyObject for Host { to_object(&self, _py: Python<'_>) -> PyObject79 fn to_object(&self, _py: Python<'_>) -> PyObject { 80 self.obj.clone() 81 } 82 } 83 84 /// Driver factory to use when initializing a host 85 #[derive(Debug, Clone)] 86 pub enum DriverFactory { 87 /// Do not load drivers 88 None, 89 /// Load appropriate driver, if any is found 90 Auto, 91 } 92