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 //! Drivers for Realtek controllers 16 17 use crate::wrapper::{host::Host, PyObjectExt}; 18 use pyo3::{intern, types::PyModule, PyObject, PyResult, Python, ToPyObject}; 19 use pyo3_asyncio::tokio::into_future; 20 21 pub use crate::internal::drivers::rtk::{Firmware, Patch}; 22 23 /// Driver for a Realtek controller 24 pub struct Driver(PyObject); 25 26 impl Driver { 27 /// Locate the driver for the provided host. for_host(host: &Host, force: bool) -> PyResult<Option<Self>>28 pub async fn for_host(host: &Host, force: bool) -> PyResult<Option<Self>> { 29 Python::with_gil(|py| { 30 PyModule::import(py, intern!(py, "bumble.drivers.rtk"))? 31 .getattr(intern!(py, "Driver"))? 32 .call_method1(intern!(py, "for_host"), (&host.obj, force)) 33 .and_then(into_future) 34 })? 35 .await 36 .map(|obj| obj.into_option(Self)) 37 } 38 39 /// Check if the host has a known driver. check(host: &Host) -> PyResult<bool>40 pub async fn check(host: &Host) -> PyResult<bool> { 41 Python::with_gil(|py| { 42 PyModule::import(py, intern!(py, "bumble.drivers.rtk"))? 43 .getattr(intern!(py, "Driver"))? 44 .call_method1(intern!(py, "check"), (&host.obj,)) 45 .and_then(|obj| obj.extract::<bool>()) 46 }) 47 } 48 49 /// Find the [DriverInfo] for the host, if one matches driver_info_for_host(host: &Host) -> PyResult<Option<DriverInfo>>50 pub async fn driver_info_for_host(host: &Host) -> PyResult<Option<DriverInfo>> { 51 Python::with_gil(|py| { 52 PyModule::import(py, intern!(py, "bumble.drivers.rtk"))? 53 .getattr(intern!(py, "Driver"))? 54 .call_method1(intern!(py, "driver_info_for_host"), (&host.obj,)) 55 .and_then(into_future) 56 })? 57 .await 58 .map(|obj| obj.into_option(DriverInfo)) 59 } 60 61 /// Send a command to the device to drop firmware drop_firmware(host: &mut Host) -> PyResult<()>62 pub async fn drop_firmware(host: &mut Host) -> PyResult<()> { 63 Python::with_gil(|py| { 64 PyModule::import(py, intern!(py, "bumble.drivers.rtk"))? 65 .getattr(intern!(py, "Driver"))? 66 .call_method1(intern!(py, "drop_firmware"), (&host.obj,)) 67 .and_then(into_future) 68 })? 69 .await 70 .map(|_| ()) 71 } 72 73 /// Load firmware onto the device. download_firmware(&mut self) -> PyResult<()>74 pub async fn download_firmware(&mut self) -> PyResult<()> { 75 Python::with_gil(|py| { 76 self.0 77 .call_method0(py, intern!(py, "download_firmware")) 78 .and_then(|coroutine| into_future(coroutine.as_ref(py))) 79 })? 80 .await 81 .map(|_| ()) 82 } 83 } 84 85 /// Metadata about a known driver & applicable device 86 pub struct DriverInfo(PyObject); 87 88 impl DriverInfo { 89 /// Returns a list of all drivers that Bumble knows how to handle. all_drivers() -> PyResult<Vec<DriverInfo>>90 pub fn all_drivers() -> PyResult<Vec<DriverInfo>> { 91 Python::with_gil(|py| { 92 PyModule::import(py, intern!(py, "bumble.drivers.rtk"))? 93 .getattr(intern!(py, "Driver"))? 94 .getattr(intern!(py, "DRIVER_INFOS"))? 95 .iter()? 96 .map(|r| r.map(|h| DriverInfo(h.to_object(py)))) 97 .collect::<PyResult<Vec<_>>>() 98 }) 99 } 100 101 /// The firmware file name to load from the filesystem, e.g. `foo_fw.bin`. firmware_name(&self) -> PyResult<String>102 pub fn firmware_name(&self) -> PyResult<String> { 103 Python::with_gil(|py| { 104 self.0 105 .getattr(py, intern!(py, "fw_name"))? 106 .as_ref(py) 107 .extract::<String>() 108 }) 109 } 110 111 /// The config file name, if any, to load from the filesystem, e.g. `foo_config.bin`. config_name(&self) -> PyResult<Option<String>>112 pub fn config_name(&self) -> PyResult<Option<String>> { 113 Python::with_gil(|py| { 114 let obj = self.0.getattr(py, intern!(py, "config_name"))?; 115 let handle = obj.as_ref(py); 116 117 if handle.is_none() { 118 Ok(None) 119 } else { 120 handle 121 .extract::<String>() 122 .map(|s| if s.is_empty() { None } else { Some(s) }) 123 } 124 }) 125 } 126 127 /// Whether or not config is required. config_needed(&self) -> PyResult<bool>128 pub fn config_needed(&self) -> PyResult<bool> { 129 Python::with_gil(|py| { 130 self.0 131 .getattr(py, intern!(py, "config_needed"))? 132 .as_ref(py) 133 .extract::<bool>() 134 }) 135 } 136 137 /// ROM id rom(&self) -> PyResult<u32>138 pub fn rom(&self) -> PyResult<u32> { 139 Python::with_gil(|py| self.0.getattr(py, intern!(py, "rom"))?.as_ref(py).extract()) 140 } 141 } 142