1 // Copyright 2022, The Android Open Source Project 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 //! This module provides a thin adapter of UwbService and UwbServiceCallback that encodes the 16 //! arguments to protobuf. 17 18 use log::{debug, error}; 19 20 use crate::error::{Error, Result}; 21 use crate::params::{AppConfigParams, DeviceState, ReasonCode, SessionId, SessionState}; 22 use crate::proto::bindings::{ 23 AndroidGetPowerStatsResponse, AndroidSetCountryCodeRequest, AndroidSetCountryCodeResponse, 24 DeinitSessionRequest, DeinitSessionResponse, DisableResponse, EnableResponse, 25 InitSessionRequest, InitSessionResponse, RangeDataReceivedSignal, ReconfigureRequest, 26 ReconfigureResponse, SendVendorCmdRequest, SendVendorCmdResponse, ServiceResetSignal, 27 SessionParamsRequest, SessionParamsResponse, SessionStateChangedSignal, SetLoggerModeRequest, 28 SetLoggerModeResponse, StartRangingRequest, StartRangingResponse, Status as ProtoStatus, 29 StopRangingRequest, StopRangingResponse, UciDeviceStatusChangedSignal, 30 UpdateControllerMulticastListRequest, UpdateControllerMulticastListResponse, 31 VendorNotificationReceivedSignal, 32 }; 33 use crate::proto::utils::{parse_from_bytes, write_to_bytes}; 34 use crate::service::uwb_service::{UwbService, UwbServiceCallback}; 35 use crate::uci::notification::SessionRangeData; 36 37 /// A thin adapter of UwbService. The argument and the response of each method are protobuf-encoded 38 /// buffer. The definition of the protobuf is at protos/uwb_core_protos.proto. 39 /// 40 /// For the naming of the protobuf struct, the argument of a method `do_something()` will be called 41 /// `DoSomethingRequest`, and the result will be called `DoSomethingResponse`. 42 pub struct ProtoUwbService { 43 service: UwbService, 44 } 45 46 impl ProtoUwbService { 47 /// Create a ProtoUwbService. new(service: UwbService) -> Self48 pub fn new(service: UwbService) -> Self { 49 Self { service } 50 } 51 52 /// Set UCI log mode. set_logger_mode(&self, request: &[u8]) -> Result<Vec<u8>>53 pub fn set_logger_mode(&self, request: &[u8]) -> Result<Vec<u8>> { 54 let request = parse_from_bytes::<SetLoggerModeRequest>(request)?; 55 let mut resp = SetLoggerModeResponse::new(); 56 resp.set_status(self.service.set_logger_mode(request.logger_mode.into()).into()); 57 write_to_bytes(&resp) 58 } 59 60 /// Enable the UWB service. enable(&self) -> Result<Vec<u8>>61 pub fn enable(&self) -> Result<Vec<u8>> { 62 let mut resp = EnableResponse::new(); 63 resp.set_status(self.service.enable().into()); 64 write_to_bytes(&resp) 65 } 66 67 /// Disable the UWB service. disable(&self) -> Result<Vec<u8>>68 pub fn disable(&self) -> Result<Vec<u8>> { 69 let mut resp = DisableResponse::new(); 70 resp.set_status(self.service.disable().into()); 71 write_to_bytes(&resp) 72 } 73 74 /// Initialize a new ranging session with the given parameters. 75 /// 76 /// Note: Currently the protobuf only support Fira parameters, but not support CCC parameters. init_session(&self, request: &[u8]) -> Result<Vec<u8>>77 pub fn init_session(&self, request: &[u8]) -> Result<Vec<u8>> { 78 let mut request = parse_from_bytes::<InitSessionRequest>(request)?; 79 let params = request 80 .params 81 .take() 82 .ok_or_else(|| { 83 error!("InitSessionRequest.params is empty"); 84 Error::BadParameters 85 })? 86 .try_into() 87 .map_err(|e| { 88 error!("Failed to convert to AppConfigParams: {}", e); 89 Error::BadParameters 90 })?; 91 92 let mut resp = InitSessionResponse::new(); 93 resp.set_status( 94 self.service 95 .init_session(request.session_id, request.session_type.into(), params) 96 .into(), 97 ); 98 write_to_bytes(&resp) 99 } 100 101 /// Destroy the session. deinit_session(&self, request: &[u8]) -> Result<Vec<u8>>102 pub fn deinit_session(&self, request: &[u8]) -> Result<Vec<u8>> { 103 let request = parse_from_bytes::<DeinitSessionRequest>(request)?; 104 let mut resp = DeinitSessionResponse::new(); 105 resp.set_status(self.service.deinit_session(request.session_id).into()); 106 write_to_bytes(&resp) 107 } 108 109 /// Start ranging of the session. start_ranging(&self, request: &[u8]) -> Result<Vec<u8>>110 pub fn start_ranging(&self, request: &[u8]) -> Result<Vec<u8>> { 111 let request = parse_from_bytes::<StartRangingRequest>(request)?; 112 // Currently we only support FiRa session, not CCC. For FiRa session, the returned 113 // AppConfigParams is the same as the configured one before start_ranging(). Therefore, we 114 // don't reply the AppConfigParams received from uwb_core. 115 let mut resp = StartRangingResponse::new(); 116 resp.set_status(self.service.start_ranging(request.session_id).into()); 117 write_to_bytes(&resp) 118 } 119 120 /// Stop ranging. stop_ranging(&self, request: &[u8]) -> Result<Vec<u8>>121 pub fn stop_ranging(&self, request: &[u8]) -> Result<Vec<u8>> { 122 let request = parse_from_bytes::<StopRangingRequest>(request)?; 123 let mut resp = StopRangingResponse::new(); 124 resp.set_status(self.service.stop_ranging(request.session_id).into()); 125 write_to_bytes(&resp) 126 } 127 128 /// Reconfigure the parameters of the session. reconfigure(&self, request: &[u8]) -> Result<Vec<u8>>129 pub fn reconfigure(&self, request: &[u8]) -> Result<Vec<u8>> { 130 let mut request = parse_from_bytes::<ReconfigureRequest>(request)?; 131 let params = request 132 .params 133 .take() 134 .ok_or_else(|| { 135 error!("ReconfigureRequest.params is empty"); 136 Error::BadParameters 137 })? 138 .try_into() 139 .map_err(|e| { 140 error!("Failed to convert to AppConfigParams: {}", e); 141 Error::BadParameters 142 })?; 143 144 let mut resp = ReconfigureResponse::new(); 145 resp.set_status(self.service.reconfigure(request.session_id, params).into()); 146 write_to_bytes(&resp) 147 } 148 149 /// Update the list of the controlees to the ongoing session. update_controller_multicast_list(&self, request: &[u8]) -> Result<Vec<u8>>150 pub fn update_controller_multicast_list(&self, request: &[u8]) -> Result<Vec<u8>> { 151 let request = parse_from_bytes::<UpdateControllerMulticastListRequest>(request)?; 152 let mut controlees = vec![]; 153 for controlee in request.controlees.into_iter() { 154 let controlee = controlee.try_into().map_err(|e| { 155 error!("Failed to convert Controlee: {:?}", e); 156 Error::BadParameters 157 })?; 158 controlees.push(controlee); 159 } 160 161 let mut resp = UpdateControllerMulticastListResponse::new(); 162 resp.set_status( 163 self.service 164 .update_controller_multicast_list( 165 request.session_id, 166 request.action.into(), 167 controlees, 168 ) 169 .into(), 170 ); 171 write_to_bytes(&resp) 172 } 173 174 /// Set the country code. Android-specific method. android_set_country_code(&self, request: &[u8]) -> Result<Vec<u8>>175 pub fn android_set_country_code(&self, request: &[u8]) -> Result<Vec<u8>> { 176 let request = parse_from_bytes::<AndroidSetCountryCodeRequest>(request)?; 177 let country_code = request.country_code.try_into()?; 178 179 let mut resp = AndroidSetCountryCodeResponse::new(); 180 resp.set_status(self.service.android_set_country_code(country_code).into()); 181 write_to_bytes(&resp) 182 } 183 184 /// Get the power statistics. Android-specific method. android_get_power_stats(&self) -> Result<Vec<u8>>185 pub fn android_get_power_stats(&self) -> Result<Vec<u8>> { 186 let mut resp = AndroidGetPowerStatsResponse::new(); 187 match self.service.android_get_power_stats() { 188 Ok(power_stats) => { 189 resp.set_status(Ok(()).into()); 190 resp.set_power_stats(power_stats.into()); 191 } 192 Err(e) => { 193 resp.set_status(From::<Result<()>>::from(Err(e))); 194 } 195 } 196 write_to_bytes(&resp) 197 } 198 199 /// Send a raw UCI message. raw_uci_cmd(&self, request: &[u8]) -> Result<Vec<u8>>200 pub fn raw_uci_cmd(&self, request: &[u8]) -> Result<Vec<u8>> { 201 let request = parse_from_bytes::<SendVendorCmdRequest>(request)?; 202 let mut resp = SendVendorCmdResponse::new(); 203 match self.service.raw_uci_cmd(request.mt, request.gid, request.oid, request.payload) { 204 Ok(msg) => { 205 resp.set_status(Ok(()).into()); 206 resp.set_gid(msg.gid); 207 resp.set_oid(msg.oid); 208 resp.set_payload(msg.payload); 209 } 210 Err(e) => { 211 resp.set_status(From::<Result<()>>::from(Err(e))); 212 } 213 } 214 write_to_bytes(&resp) 215 } 216 217 /// Get app config params for the given session id session_params(&self, request: &[u8]) -> Result<Vec<u8>>218 pub fn session_params(&self, request: &[u8]) -> Result<Vec<u8>> { 219 let request = parse_from_bytes::<SessionParamsRequest>(request)?; 220 let mut resp = SessionParamsResponse::new(); 221 match self.service.session_params(request.session_id) { 222 Ok(AppConfigParams::Fira(params)) => { 223 resp.set_status(Ok(()).into()); 224 resp.set_params(params.into()); 225 } 226 Ok(params) => { 227 error!("Received non-Fira session parameters: {:?}", params); 228 resp.set_status(ProtoStatus::UNKNOWN); 229 } 230 Err(e) => { 231 resp.set_status(From::<Result<()>>::from(Err(e))); 232 } 233 } 234 write_to_bytes(&resp) 235 } 236 } 237 238 /// The trait that provides the same callbacks of UwbServiceCallback. It has the blanket 239 /// implementation of UwbServiceCallback trait that converts the arguments to one protobuf-encoded 240 /// payload. 241 /// 242 /// For the naming of the protobuf struct, the payload of a callback `on_something_happened()` 243 /// will be called `SomethingHappenedSignal`. 244 pub trait ProtoUwbServiceCallback: 'static { 245 /// Notify the UWB service has been reset due to internal error. All the sessions are closed. on_service_reset(&mut self, payload: Vec<u8>)246 fn on_service_reset(&mut self, payload: Vec<u8>); 247 /// Notify the status of the UCI device. on_uci_device_status_changed(&mut self, payload: Vec<u8>)248 fn on_uci_device_status_changed(&mut self, payload: Vec<u8>); 249 /// Notify the state of the session is changed. on_session_state_changed(&mut self, payload: Vec<u8>)250 fn on_session_state_changed(&mut self, payload: Vec<u8>); 251 /// Notify the ranging data of the session is received. on_range_data_received(&mut self, payload: Vec<u8>)252 fn on_range_data_received(&mut self, payload: Vec<u8>); 253 /// Notify the vendor notification is received. on_vendor_notification_received(&mut self, payload: Vec<u8>)254 fn on_vendor_notification_received(&mut self, payload: Vec<u8>); 255 } 256 257 impl<C: ProtoUwbServiceCallback> UwbServiceCallback for C { on_service_reset(&mut self, success: bool)258 fn on_service_reset(&mut self, success: bool) { 259 debug!("UwbService is reset, success: {}", success); 260 let mut msg = ServiceResetSignal::new(); 261 msg.set_success(success); 262 if let Ok(payload) = write_to_bytes(&msg) { 263 ProtoUwbServiceCallback::on_service_reset(self, payload); 264 } else { 265 error!("Failed to call on_service_reset()"); 266 } 267 } 268 on_uci_device_status_changed(&mut self, state: DeviceState)269 fn on_uci_device_status_changed(&mut self, state: DeviceState) { 270 debug!("UCI device status is changed: {:?}", state); 271 let mut msg = UciDeviceStatusChangedSignal::new(); 272 msg.set_state(state.into()); 273 if let Ok(payload) = write_to_bytes(&msg) { 274 ProtoUwbServiceCallback::on_uci_device_status_changed(self, payload); 275 } else { 276 error!("Failed to call on_uci_device_status_changed()"); 277 } 278 } 279 on_session_state_changed( &mut self, session_id: SessionId, session_state: SessionState, reason_code: ReasonCode, )280 fn on_session_state_changed( 281 &mut self, 282 session_id: SessionId, 283 session_state: SessionState, 284 reason_code: ReasonCode, 285 ) { 286 debug!( 287 "Session {:?}'s state is changed to {:?}, reason: {:?}", 288 session_id, session_state, reason_code 289 ); 290 let mut msg = SessionStateChangedSignal::new(); 291 msg.set_session_id(session_id); 292 msg.set_session_state(session_state.into()); 293 msg.set_reason_code(reason_code.into()); 294 if let Ok(payload) = write_to_bytes(&msg) { 295 ProtoUwbServiceCallback::on_session_state_changed(self, payload); 296 } else { 297 error!("Failed to call on_session_state_changed()"); 298 } 299 } 300 on_range_data_received(&mut self, session_id: SessionId, range_data: SessionRangeData)301 fn on_range_data_received(&mut self, session_id: SessionId, range_data: SessionRangeData) { 302 debug!("Received range data {:?} from Session {:?}", range_data, session_id); 303 let mut msg = RangeDataReceivedSignal::new(); 304 msg.set_session_id(session_id); 305 msg.set_range_data(range_data.into()); 306 if let Ok(payload) = write_to_bytes(&msg) { 307 ProtoUwbServiceCallback::on_range_data_received(self, payload); 308 } else { 309 error!("Failed to call on_range_data_received()"); 310 } 311 } 312 on_vendor_notification_received(&mut self, gid: u32, oid: u32, payload: Vec<u8>)313 fn on_vendor_notification_received(&mut self, gid: u32, oid: u32, payload: Vec<u8>) { 314 debug!("Received vendor notification: gid={}, oid={}, payload={:?}", gid, oid, payload); 315 let mut msg = VendorNotificationReceivedSignal::new(); 316 msg.set_gid(gid); 317 msg.set_oid(oid); 318 msg.set_payload(payload); 319 if let Ok(payload) = write_to_bytes(&msg) { 320 ProtoUwbServiceCallback::on_vendor_notification_received(self, payload); 321 } else { 322 error!("Failed to call on_vendor_notification_received()"); 323 } 324 } 325 } 326