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