1 //! jni for uwb native stack
2 use jni::objects::{JObject, JValue};
3 use jni::sys::{
4 jarray, jboolean, jbyte, jbyteArray, jint, jintArray, jlong, jobject, jshort, jshortArray,
5 jsize,
6 };
7 use jni::JNIEnv;
8 use log::{error, info};
9 use num_traits::ToPrimitive;
10 use uwb_uci_packets::{
11 GetCapsInfoRspPacket, Packet, SessionGetAppConfigRspPacket, SessionSetAppConfigRspPacket,
12 StatusCode, UciResponseChild, UciResponsePacket, UciVendor_9_ResponseChild,
13 UciVendor_A_ResponseChild, UciVendor_B_ResponseChild, UciVendor_E_ResponseChild,
14 UciVendor_F_ResponseChild,
15 };
16 use uwb_uci_rust::error::UwbErr;
17 use uwb_uci_rust::event_manager::EventManagerImpl as EventManager;
18 use uwb_uci_rust::uci::{uci_hrcv::UciResponse, Dispatcher, DispatcherImpl, JNICommand};
19
20 trait Context<'a> {
convert_byte_array(&self, array: jbyteArray) -> Result<Vec<u8>, jni::errors::Error>21 fn convert_byte_array(&self, array: jbyteArray) -> Result<Vec<u8>, jni::errors::Error>;
get_array_length(&self, array: jarray) -> Result<jsize, jni::errors::Error>22 fn get_array_length(&self, array: jarray) -> Result<jsize, jni::errors::Error>;
get_short_array_region( &self, array: jshortArray, start: jsize, buf: &mut [jshort], ) -> Result<(), jni::errors::Error>23 fn get_short_array_region(
24 &self,
25 array: jshortArray,
26 start: jsize,
27 buf: &mut [jshort],
28 ) -> Result<(), jni::errors::Error>;
get_int_array_region( &self, array: jintArray, start: jsize, buf: &mut [jint], ) -> Result<(), jni::errors::Error>29 fn get_int_array_region(
30 &self,
31 array: jintArray,
32 start: jsize,
33 buf: &mut [jint],
34 ) -> Result<(), jni::errors::Error>;
get_dispatcher(&self) -> Result<&'a mut dyn Dispatcher, UwbErr>35 fn get_dispatcher(&self) -> Result<&'a mut dyn Dispatcher, UwbErr>;
36 }
37
38 struct JniContext<'a> {
39 env: JNIEnv<'a>,
40 obj: JObject<'a>,
41 }
42
43 impl<'a> JniContext<'a> {
new(env: JNIEnv<'a>, obj: JObject<'a>) -> Self44 fn new(env: JNIEnv<'a>, obj: JObject<'a>) -> Self {
45 Self { env, obj }
46 }
47 }
48
49 impl<'a> Context<'a> for JniContext<'a> {
convert_byte_array(&self, array: jbyteArray) -> Result<Vec<u8>, jni::errors::Error>50 fn convert_byte_array(&self, array: jbyteArray) -> Result<Vec<u8>, jni::errors::Error> {
51 self.env.convert_byte_array(array)
52 }
get_array_length(&self, array: jarray) -> Result<jsize, jni::errors::Error>53 fn get_array_length(&self, array: jarray) -> Result<jsize, jni::errors::Error> {
54 self.env.get_array_length(array)
55 }
get_short_array_region( &self, array: jshortArray, start: jsize, buf: &mut [jshort], ) -> Result<(), jni::errors::Error>56 fn get_short_array_region(
57 &self,
58 array: jshortArray,
59 start: jsize,
60 buf: &mut [jshort],
61 ) -> Result<(), jni::errors::Error> {
62 self.env.get_short_array_region(array, start, buf)
63 }
get_int_array_region( &self, array: jintArray, start: jsize, buf: &mut [jint], ) -> Result<(), jni::errors::Error>64 fn get_int_array_region(
65 &self,
66 array: jintArray,
67 start: jsize,
68 buf: &mut [jint],
69 ) -> Result<(), jni::errors::Error> {
70 self.env.get_int_array_region(array, start, buf)
71 }
get_dispatcher(&self) -> Result<&'a mut dyn Dispatcher, UwbErr>72 fn get_dispatcher(&self) -> Result<&'a mut dyn Dispatcher, UwbErr> {
73 let dispatcher_ptr_value = self.env.get_field(self.obj, "mDispatcherPointer", "J")?;
74 let dispatcher_ptr = dispatcher_ptr_value.j()?;
75 if dispatcher_ptr == 0i64 {
76 error!("The dispatcher is not initialized.");
77 return Err(UwbErr::NoneDispatcher);
78 }
79 // Safety: dispatcher pointer must not be a null pointer and it must point to a valid dispatcher object.
80 // This can be ensured because the dispatcher is created in an earlier stage and
81 // won't be deleted before calling doDeinitialize.
82 unsafe { Ok(&mut *(dispatcher_ptr as *mut DispatcherImpl)) }
83 }
84 }
85
86 /// Initialize UWB
87 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeInit( _env: JNIEnv, _obj: JObject, ) -> jboolean88 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeInit(
89 _env: JNIEnv,
90 _obj: JObject,
91 ) -> jboolean {
92 logger::init(
93 logger::Config::default()
94 .with_tag_on_device("uwb")
95 .with_min_level(log::Level::Trace)
96 .with_filter("trace,jni=info"),
97 );
98 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeInit: enter");
99 true as jboolean
100 }
101
102 /// Get max session number
103 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetMaxSessionNumber( _env: JNIEnv, _obj: JObject, ) -> jint104 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetMaxSessionNumber(
105 _env: JNIEnv,
106 _obj: JObject,
107 ) -> jint {
108 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetMaxSessionNumber: enter");
109 5
110 }
111
112 /// Turn on UWB. initialize the GKI module and HAL module for UWB device.
113 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoInitialize( env: JNIEnv, obj: JObject, ) -> jboolean114 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoInitialize(
115 env: JNIEnv,
116 obj: JObject,
117 ) -> jboolean {
118 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoInitialize: enter");
119 boolean_result_helper(do_initialize(&JniContext::new(env, obj)), "DoInitialize")
120 }
121
122 /// Turn off UWB. Deinitilize the GKI and HAL module, power of the UWB device.
123 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoDeinitialize( env: JNIEnv, obj: JObject, ) -> jboolean124 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoDeinitialize(
125 env: JNIEnv,
126 obj: JObject,
127 ) -> jboolean {
128 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeDoDeinitialize: enter");
129 boolean_result_helper(do_deinitialize(&JniContext::new(env, obj)), "DoDeinitialize")
130 }
131
132 /// get nanos
133 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetTimestampResolutionNanos( _env: JNIEnv, _obj: JObject, ) -> jlong134 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetTimestampResolutionNanos(
135 _env: JNIEnv,
136 _obj: JObject,
137 ) -> jlong {
138 info!(
139 "Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetTimestampResolutionNanos: enter"
140 );
141 0
142 }
143
144 /// reset the device
145 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDeviceReset( env: JNIEnv, obj: JObject, reset_config: jbyte, ) -> jbyte146 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDeviceReset(
147 env: JNIEnv,
148 obj: JObject,
149 reset_config: jbyte,
150 ) -> jbyte {
151 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeDeviceReset: enter");
152 byte_result_helper(reset_device(&JniContext::new(env, obj), reset_config as u8), "ResetDevice")
153 }
154
155 /// init the session
156 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionInit( env: JNIEnv, obj: JObject, session_id: jint, session_type: jbyte, ) -> jbyte157 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionInit(
158 env: JNIEnv,
159 obj: JObject,
160 session_id: jint,
161 session_type: jbyte,
162 ) -> jbyte {
163 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionInit: enter");
164 byte_result_helper(
165 session_init(&JniContext::new(env, obj), session_id as u32, session_type as u8),
166 "SessionInit",
167 )
168 }
169
170 /// deinit the session
171 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionDeInit( env: JNIEnv, obj: JObject, session_id: jint, ) -> jbyte172 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionDeInit(
173 env: JNIEnv,
174 obj: JObject,
175 session_id: jint,
176 ) -> jbyte {
177 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeSessionDeInit: enter");
178 byte_result_helper(
179 session_deinit(&JniContext::new(env, obj), session_id as u32),
180 "SessionDeInit",
181 )
182 }
183
184 /// get session count
185 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionCount( env: JNIEnv, obj: JObject, ) -> jbyte186 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionCount(
187 env: JNIEnv,
188 obj: JObject,
189 ) -> jbyte {
190 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionCount: enter");
191 match get_session_count(&JniContext::new(env, obj)) {
192 Ok(count) => count,
193 Err(e) => {
194 error!("GetSessionCount failed with {:?}", e);
195 -1
196 }
197 }
198 }
199
200 /// start the ranging
201 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStart( env: JNIEnv, obj: JObject, session_id: jint, ) -> jbyte202 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStart(
203 env: JNIEnv,
204 obj: JObject,
205 session_id: jint,
206 ) -> jbyte {
207 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStart: enter");
208 byte_result_helper(ranging_start(&JniContext::new(env, obj), session_id as u32), "RangingStart")
209 }
210
211 /// stop the ranging
212 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStop( env: JNIEnv, obj: JObject, session_id: jint, ) -> jbyte213 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStop(
214 env: JNIEnv,
215 obj: JObject,
216 session_id: jint,
217 ) -> jbyte {
218 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeRangingStop: enter");
219 byte_result_helper(ranging_stop(&JniContext::new(env, obj), session_id as u32), "RangingStop")
220 }
221
222 /// get the session state
223 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionState( env: JNIEnv, obj: JObject, session_id: jint, ) -> jbyte224 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionState(
225 env: JNIEnv,
226 obj: JObject,
227 session_id: jint,
228 ) -> jbyte {
229 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetSessionState: enter");
230 match get_session_state(&JniContext::new(env, obj), session_id as u32) {
231 Ok(state) => state,
232 Err(e) => {
233 error!("GetSessionState failed with {:?}", e);
234 -1
235 }
236 }
237 }
238
239 /// set app configurations
240 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetAppConfigurations( env: JNIEnv, obj: JObject, session_id: jint, no_of_params: jint, app_config_param_len: jint, app_config_params: jbyteArray, ) -> jbyteArray241 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetAppConfigurations(
242 env: JNIEnv,
243 obj: JObject,
244 session_id: jint,
245 no_of_params: jint,
246 app_config_param_len: jint,
247 app_config_params: jbyteArray,
248 ) -> jbyteArray {
249 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetAppConfigurations: enter");
250 match set_app_configurations(
251 &JniContext::new(env, obj),
252 session_id as u32,
253 no_of_params as u32,
254 app_config_param_len as u32,
255 app_config_params,
256 ) {
257 Ok(data) => {
258 let uwb_config_status_class =
259 env.find_class("com/android/server/uwb/data/UwbConfigStatusData").unwrap();
260 let mut buf: Vec<u8> = Vec::new();
261 for iter in data.get_cfg_status() {
262 buf.push(iter.cfg_id as u8);
263 buf.push(iter.status as u8);
264 }
265 let cfg_jbytearray = env.byte_array_from_slice(&buf).unwrap();
266 let uwb_config_status_object = env.new_object(
267 uwb_config_status_class,
268 "(II[B)V",
269 &[
270 JValue::Int(data.get_status().to_i32().unwrap()),
271 JValue::Int(data.get_cfg_status().len().to_i32().unwrap()),
272 JValue::Object(JObject::from(cfg_jbytearray)),
273 ],
274 );
275 *uwb_config_status_object.unwrap()
276 }
277 Err(e) => {
278 error!("SetAppConfig failed with: {:?}", e);
279 *JObject::null()
280 }
281 }
282 }
283
284 /// get app configurations
285 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetAppConfigurations( env: JNIEnv, obj: JObject, session_id: jint, no_of_params: jint, app_config_param_len: jint, app_config_params: jbyteArray, ) -> jbyteArray286 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetAppConfigurations(
287 env: JNIEnv,
288 obj: JObject,
289 session_id: jint,
290 no_of_params: jint,
291 app_config_param_len: jint,
292 app_config_params: jbyteArray,
293 ) -> jbyteArray {
294 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetAppConfigurations: enter");
295 match get_app_configurations(
296 &JniContext::new(env, obj),
297 session_id as u32,
298 no_of_params as u32,
299 app_config_param_len as u32,
300 app_config_params,
301 ) {
302 Ok(data) => {
303 let uwb_tlv_info_class =
304 env.find_class("com/android/server/uwb/data/UwbTlvData").unwrap();
305 let mut buf: Vec<u8> = Vec::new();
306 for tlv in data.get_tlvs() {
307 buf.push(tlv.cfg_id as u8);
308 buf.push(tlv.v.len() as u8);
309 buf.extend(&tlv.v);
310 }
311 let tlv_jbytearray = env.byte_array_from_slice(&buf).unwrap();
312 let uwb_tlv_info_object = env.new_object(
313 uwb_tlv_info_class,
314 "(II[B)V",
315 &[
316 JValue::Int(data.get_status().to_i32().unwrap()),
317 JValue::Int(data.get_tlvs().len().to_i32().unwrap()),
318 JValue::Object(JObject::from(tlv_jbytearray)),
319 ],
320 );
321 *uwb_tlv_info_object.unwrap()
322 }
323 Err(e) => {
324 error!("GetAppConfig failed with: {:?}", e);
325 *JObject::null()
326 }
327 }
328 }
329
330 /// get capability info
331 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetCapsInfo( env: JNIEnv, obj: JObject, ) -> jbyteArray332 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetCapsInfo(
333 env: JNIEnv,
334 obj: JObject,
335 ) -> jbyteArray {
336 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetCapsInfo: enter");
337 match get_caps_info(&JniContext::new(env, obj)) {
338 Ok(data) => {
339 let uwb_tlv_info_class =
340 env.find_class("com/android/server/uwb/data/UwbTlvData").unwrap();
341 let mut buf: Vec<u8> = Vec::new();
342 for tlv in data.get_tlvs() {
343 buf.push(tlv.t as u8);
344 buf.push(tlv.v.len() as u8);
345 buf.extend(&tlv.v);
346 }
347 let tlv_jbytearray = env.byte_array_from_slice(&buf).unwrap();
348 let uwb_tlv_info_object = env.new_object(
349 uwb_tlv_info_class,
350 "(II[B)V",
351 &[
352 JValue::Int(data.get_status().to_i32().unwrap()),
353 JValue::Int(data.get_tlvs().len().to_i32().unwrap()),
354 JValue::Object(JObject::from(tlv_jbytearray)),
355 ],
356 );
357 *uwb_tlv_info_object.unwrap()
358 }
359 Err(e) => {
360 error!("GetCapsInfo failed with: {:?}", e);
361 *JObject::null()
362 }
363 }
364 }
365
366 /// update multicast list
367 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeControllerMulticastListUpdate( env: JNIEnv, obj: JObject, session_id: jint, action: jbyte, no_of_controlee: jbyte, addresses: jshortArray, sub_session_ids: jintArray, ) -> jbyte368 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeControllerMulticastListUpdate(
369 env: JNIEnv,
370 obj: JObject,
371 session_id: jint,
372 action: jbyte,
373 no_of_controlee: jbyte,
374 addresses: jshortArray,
375 sub_session_ids: jintArray,
376 ) -> jbyte {
377 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeControllerMulticastListUpdate: enter");
378 byte_result_helper(
379 multicast_list_update(
380 &JniContext::new(env, obj),
381 session_id as u32,
382 action as u8,
383 no_of_controlee as u8,
384 addresses,
385 sub_session_ids,
386 ),
387 "ControllerMulticastListUpdate",
388 )
389 }
390
391 /// set country code
392 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetCountryCode( env: JNIEnv, obj: JObject, country_code: jbyteArray, ) -> jbyte393 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetCountryCode(
394 env: JNIEnv,
395 obj: JObject,
396 country_code: jbyteArray,
397 ) -> jbyte {
398 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeSetCountryCode: enter");
399 byte_result_helper(set_country_code(&JniContext::new(env, obj), country_code), "SetCountryCode")
400 }
401
402 /// set country code
403 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeSendRawVendorCmd( env: JNIEnv, obj: JObject, gid: jint, oid: jint, payload: jbyteArray, ) -> jobject404 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeSendRawVendorCmd(
405 env: JNIEnv,
406 obj: JObject,
407 gid: jint,
408 oid: jint,
409 payload: jbyteArray,
410 ) -> jobject {
411 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeRawVendor: enter");
412 let uwb_vendor_uci_response_class =
413 env.find_class("com/android/server/uwb/data/UwbVendorUciResponse").unwrap();
414 match send_raw_vendor_cmd(
415 &JniContext::new(env, obj),
416 gid.try_into().expect("invalid gid"),
417 oid.try_into().expect("invalid oid"),
418 payload,
419 ) {
420 Ok((gid, oid, payload)) => *env
421 .new_object(
422 uwb_vendor_uci_response_class,
423 "(BII[B)V",
424 &[
425 JValue::Byte(StatusCode::UciStatusOk.to_i8().unwrap()),
426 JValue::Int(gid.to_i32().unwrap()),
427 JValue::Int(oid.to_i32().unwrap()),
428 JValue::Object(JObject::from(
429 env.byte_array_from_slice(payload.as_ref()).unwrap(),
430 )),
431 ],
432 )
433 .unwrap(),
434 Err(e) => {
435 error!("send raw uci cmd failed with: {:?}", e);
436 *env.new_object(
437 uwb_vendor_uci_response_class,
438 "(BII[B)V",
439 &[
440 JValue::Byte(StatusCode::UciStatusFailed.to_i8().unwrap()),
441 JValue::Int(-1),
442 JValue::Int(-1),
443 JValue::Object(JObject::null()),
444 ],
445 )
446 .unwrap()
447 }
448 }
449 }
450
451 /// retrieve the UWB power stats
452 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetPowerStats( env: JNIEnv, obj: JObject, ) -> jobject453 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetPowerStats(
454 env: JNIEnv,
455 obj: JObject,
456 ) -> jobject {
457 info!("Java_com_android_server_uwb_jni_NativeUwbManager_nativeGetPowerStats: enter");
458 let uwb_power_stats_class =
459 env.find_class("com/android/server/uwb/info/UwbPowerStats").unwrap();
460 match get_power_stats(&JniContext::new(env, obj)) {
461 Ok(para) => {
462 let power_stats = env.new_object(uwb_power_stats_class, "(IIII)V", ¶).unwrap();
463 *power_stats
464 }
465 Err(e) => {
466 error!("Get power stats failed with: {:?}", e);
467 *JObject::null()
468 }
469 }
470 }
471
boolean_result_helper(result: Result<(), UwbErr>, function_name: &str) -> jboolean472 fn boolean_result_helper(result: Result<(), UwbErr>, function_name: &str) -> jboolean {
473 match result {
474 Ok(()) => true as jboolean,
475 Err(err) => {
476 error!("{} failed with: {:?}", function_name, err);
477 false as jboolean
478 }
479 }
480 }
481
byte_result_helper(result: Result<(), UwbErr>, function_name: &str) -> jbyte482 fn byte_result_helper(result: Result<(), UwbErr>, function_name: &str) -> jbyte {
483 match result {
484 Ok(()) => StatusCode::UciStatusOk.to_i8().unwrap(),
485 Err(err) => {
486 error!("{} failed with: {:?}", function_name, err);
487 match err {
488 UwbErr::StatusCode(status_code) => status_code
489 .to_i8()
490 .unwrap_or_else(|| StatusCode::UciStatusFailed.to_i8().unwrap()),
491 _ => StatusCode::UciStatusFailed.to_i8().unwrap(),
492 }
493 }
494 }
495 }
496
do_initialize<'a, T: Context<'a>>(context: &T) -> Result<(), UwbErr>497 fn do_initialize<'a, T: Context<'a>>(context: &T) -> Result<(), UwbErr> {
498 let dispatcher = context.get_dispatcher()?;
499 dispatcher.send_jni_command(JNICommand::Enable)?;
500 match uwa_get_device_info(dispatcher) {
501 Ok(res) => {
502 if let UciResponse::GetDeviceInfoRsp(device_info) = res {
503 dispatcher.set_device_info(Some(device_info));
504 }
505 }
506 Err(e) => {
507 error!("GetDeviceInfo failed with: {:?}", e);
508 return Err(UwbErr::failed());
509 }
510 }
511 Ok(())
512 }
513
do_deinitialize<'a, T: Context<'a>>(context: &T) -> Result<(), UwbErr>514 fn do_deinitialize<'a, T: Context<'a>>(context: &T) -> Result<(), UwbErr> {
515 let dispatcher = context.get_dispatcher()?;
516 dispatcher.send_jni_command(JNICommand::Disable(true))?;
517 dispatcher.wait_for_exit()?;
518 Ok(())
519 }
520
521 // unused, but leaving this behind if we want to use it later.
522 #[allow(dead_code)]
get_specification_info<'a, T: Context<'a>>(context: &T) -> Result<[JValue<'a>; 16], UwbErr>523 fn get_specification_info<'a, T: Context<'a>>(context: &T) -> Result<[JValue<'a>; 16], UwbErr> {
524 let dispatcher = context.get_dispatcher()?;
525 match dispatcher.get_device_info() {
526 Some(data) => {
527 Ok([
528 JValue::Int((data.get_uci_version() & 0xFF).into()),
529 JValue::Int(((data.get_uci_version() >> 8) & 0xF).into()),
530 JValue::Int(((data.get_uci_version() >> 12) & 0xF).into()),
531 JValue::Int((data.get_mac_version() & 0xFF).into()),
532 JValue::Int(((data.get_mac_version() >> 8) & 0xF).into()),
533 JValue::Int(((data.get_mac_version() >> 12) & 0xF).into()),
534 JValue::Int((data.get_phy_version() & 0xFF).into()),
535 JValue::Int(((data.get_phy_version() >> 8) & 0xF).into()),
536 JValue::Int(((data.get_phy_version() >> 12) & 0xF).into()),
537 JValue::Int((data.get_uci_test_version() & 0xFF).into()),
538 JValue::Int(((data.get_uci_test_version() >> 8) & 0xF).into()),
539 JValue::Int(((data.get_uci_test_version() >> 12) & 0xF).into()),
540 JValue::Int(1), // fira_major_version
541 JValue::Int(0), // fira_minor_version
542 JValue::Int(1), // ccc_major_version
543 JValue::Int(0), // ccc_minor_version
544 ])
545 }
546 None => {
547 error!("Fail to get specification info.");
548 Err(UwbErr::failed())
549 }
550 }
551 }
552
session_init<'a, T: Context<'a>>( context: &T, session_id: u32, session_type: u8, ) -> Result<(), UwbErr>553 fn session_init<'a, T: Context<'a>>(
554 context: &T,
555 session_id: u32,
556 session_type: u8,
557 ) -> Result<(), UwbErr> {
558 let dispatcher = context.get_dispatcher()?;
559 let res = match dispatcher
560 .block_on_jni_command(JNICommand::UciSessionInit(session_id, session_type))?
561 {
562 UciResponse::SessionInitRsp(data) => data,
563 _ => return Err(UwbErr::failed()),
564 };
565 status_code_to_res(res.get_status())
566 }
567
session_deinit<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<(), UwbErr>568 fn session_deinit<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<(), UwbErr> {
569 let dispatcher = context.get_dispatcher()?;
570 let res = match dispatcher.block_on_jni_command(JNICommand::UciSessionDeinit(session_id))? {
571 UciResponse::SessionDeinitRsp(data) => data,
572 _ => return Err(UwbErr::failed()),
573 };
574 status_code_to_res(res.get_status())
575 }
576
get_session_count<'a, T: Context<'a>>(context: &T) -> Result<jbyte, UwbErr>577 fn get_session_count<'a, T: Context<'a>>(context: &T) -> Result<jbyte, UwbErr> {
578 let dispatcher = context.get_dispatcher()?;
579 match dispatcher.block_on_jni_command(JNICommand::UciSessionGetCount)? {
580 UciResponse::SessionGetCountRsp(rsp) => match status_code_to_res(rsp.get_status()) {
581 Ok(()) => Ok(rsp.get_session_count() as jbyte),
582 Err(err) => Err(err),
583 },
584 _ => Err(UwbErr::failed()),
585 }
586 }
587
ranging_start<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<(), UwbErr>588 fn ranging_start<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<(), UwbErr> {
589 let dispatcher = context.get_dispatcher()?;
590 let res = match dispatcher.block_on_jni_command(JNICommand::UciStartRange(session_id))? {
591 UciResponse::RangeStartRsp(data) => data,
592 _ => return Err(UwbErr::failed()),
593 };
594 status_code_to_res(res.get_status())
595 }
596
ranging_stop<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<(), UwbErr>597 fn ranging_stop<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<(), UwbErr> {
598 let dispatcher = context.get_dispatcher()?;
599 let res = match dispatcher.block_on_jni_command(JNICommand::UciStopRange(session_id))? {
600 UciResponse::RangeStopRsp(data) => data,
601 _ => return Err(UwbErr::failed()),
602 };
603 status_code_to_res(res.get_status())
604 }
605
get_session_state<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<jbyte, UwbErr>606 fn get_session_state<'a, T: Context<'a>>(context: &T, session_id: u32) -> Result<jbyte, UwbErr> {
607 let dispatcher = context.get_dispatcher()?;
608 match dispatcher.block_on_jni_command(JNICommand::UciGetSessionState(session_id))? {
609 UciResponse::SessionGetStateRsp(data) => Ok(data.get_session_state() as jbyte),
610 _ => Err(UwbErr::failed()),
611 }
612 }
613
set_app_configurations<'a, T: Context<'a>>( context: &T, session_id: u32, no_of_params: u32, app_config_param_len: u32, app_config_params: jintArray, ) -> Result<SessionSetAppConfigRspPacket, UwbErr>614 fn set_app_configurations<'a, T: Context<'a>>(
615 context: &T,
616 session_id: u32,
617 no_of_params: u32,
618 app_config_param_len: u32,
619 app_config_params: jintArray,
620 ) -> Result<SessionSetAppConfigRspPacket, UwbErr> {
621 let app_configs = context.convert_byte_array(app_config_params)?;
622 let dispatcher = context.get_dispatcher()?;
623 match dispatcher.block_on_jni_command(JNICommand::UciSetAppConfig {
624 session_id,
625 no_of_params,
626 app_config_param_len,
627 app_configs,
628 })? {
629 UciResponse::SessionSetAppConfigRsp(data) => Ok(data),
630 _ => Err(UwbErr::failed()),
631 }
632 }
633
get_app_configurations<'a, T: Context<'a>>( context: &T, session_id: u32, no_of_params: u32, app_config_param_len: u32, app_config_params: jintArray, ) -> Result<SessionGetAppConfigRspPacket, UwbErr>634 fn get_app_configurations<'a, T: Context<'a>>(
635 context: &T,
636 session_id: u32,
637 no_of_params: u32,
638 app_config_param_len: u32,
639 app_config_params: jintArray,
640 ) -> Result<SessionGetAppConfigRspPacket, UwbErr> {
641 let app_configs = context.convert_byte_array(app_config_params)?;
642 let dispatcher = context.get_dispatcher()?;
643 match dispatcher.block_on_jni_command(JNICommand::UciGetAppConfig {
644 session_id,
645 no_of_params,
646 app_config_param_len,
647 app_configs,
648 })? {
649 UciResponse::SessionGetAppConfigRsp(data) => Ok(data),
650 _ => Err(UwbErr::failed()),
651 }
652 }
653
get_caps_info<'a, T: Context<'a>>(context: &T) -> Result<GetCapsInfoRspPacket, UwbErr>654 fn get_caps_info<'a, T: Context<'a>>(context: &T) -> Result<GetCapsInfoRspPacket, UwbErr> {
655 let dispatcher = context.get_dispatcher()?;
656 match dispatcher.block_on_jni_command(JNICommand::UciGetCapsInfo)? {
657 UciResponse::GetCapsInfoRsp(data) => Ok(data),
658 _ => Err(UwbErr::failed()),
659 }
660 }
661
multicast_list_update<'a, T: Context<'a>>( context: &T, session_id: u32, action: u8, no_of_controlee: u8, addresses: jshortArray, sub_session_ids: jintArray, ) -> Result<(), UwbErr>662 fn multicast_list_update<'a, T: Context<'a>>(
663 context: &T,
664 session_id: u32,
665 action: u8,
666 no_of_controlee: u8,
667 addresses: jshortArray,
668 sub_session_ids: jintArray,
669 ) -> Result<(), UwbErr> {
670 let mut address_list = vec![0i16; context.get_array_length(addresses)?.try_into().unwrap()];
671 context.get_short_array_region(addresses, 0, &mut address_list)?;
672 let mut sub_session_id_list =
673 vec![0i32; context.get_array_length(sub_session_ids)?.try_into().unwrap()];
674 context.get_int_array_region(sub_session_ids, 0, &mut sub_session_id_list)?;
675 let dispatcher = context.get_dispatcher()?;
676 let res = match dispatcher.block_on_jni_command(JNICommand::UciSessionUpdateMulticastList {
677 session_id,
678 action,
679 no_of_controlee,
680 address_list: address_list.to_vec(),
681 sub_session_id_list: sub_session_id_list.to_vec(),
682 })? {
683 UciResponse::SessionUpdateControllerMulticastListRsp(data) => data,
684 _ => return Err(UwbErr::failed()),
685 };
686 status_code_to_res(res.get_status())
687 }
688
set_country_code<'a, T: Context<'a>>( context: &T, country_code: jbyteArray, ) -> Result<(), UwbErr>689 fn set_country_code<'a, T: Context<'a>>(
690 context: &T,
691 country_code: jbyteArray,
692 ) -> Result<(), UwbErr> {
693 let code = context.convert_byte_array(country_code)?;
694 if code.len() != 2 {
695 return Err(UwbErr::failed());
696 }
697 let dispatcher = context.get_dispatcher()?;
698 let res = match dispatcher.block_on_jni_command(JNICommand::UciSetCountryCode { code })? {
699 UciResponse::AndroidSetCountryCodeRsp(data) => data,
700 _ => return Err(UwbErr::failed()),
701 };
702 status_code_to_res(res.get_status())
703 }
704
get_vendor_uci_payload(data: UciResponsePacket) -> Result<Vec<u8>, UwbErr>705 fn get_vendor_uci_payload(data: UciResponsePacket) -> Result<Vec<u8>, UwbErr> {
706 match data.specialize() {
707 UciResponseChild::UciVendor_9_Response(evt) => match evt.specialize() {
708 UciVendor_9_ResponseChild::Payload(payload) => Ok(payload.to_vec()),
709 UciVendor_9_ResponseChild::None => Ok(Vec::new()),
710 },
711 UciResponseChild::UciVendor_A_Response(evt) => match evt.specialize() {
712 UciVendor_A_ResponseChild::Payload(payload) => Ok(payload.to_vec()),
713 UciVendor_A_ResponseChild::None => Ok(Vec::new()),
714 },
715 UciResponseChild::UciVendor_B_Response(evt) => match evt.specialize() {
716 UciVendor_B_ResponseChild::Payload(payload) => Ok(payload.to_vec()),
717 UciVendor_B_ResponseChild::None => Ok(Vec::new()),
718 },
719 UciResponseChild::UciVendor_E_Response(evt) => match evt.specialize() {
720 UciVendor_E_ResponseChild::Payload(payload) => Ok(payload.to_vec()),
721 UciVendor_E_ResponseChild::None => Ok(Vec::new()),
722 },
723 UciResponseChild::UciVendor_F_Response(evt) => match evt.specialize() {
724 UciVendor_F_ResponseChild::Payload(payload) => Ok(payload.to_vec()),
725 UciVendor_F_ResponseChild::None => Ok(Vec::new()),
726 },
727 _ => {
728 error!("Invalid vendor response with gid {:?}", data.get_group_id());
729 Err(UwbErr::Specialize(data.to_vec()))
730 }
731 }
732 }
733
send_raw_vendor_cmd<'a, T: Context<'a>>( context: &T, gid: u32, oid: u32, payload: jbyteArray, ) -> Result<(i32, i32, Vec<u8>), UwbErr>734 fn send_raw_vendor_cmd<'a, T: Context<'a>>(
735 context: &T,
736 gid: u32,
737 oid: u32,
738 payload: jbyteArray,
739 ) -> Result<(i32, i32, Vec<u8>), UwbErr> {
740 let payload = context.convert_byte_array(payload)?;
741 let dispatcher = context.get_dispatcher()?;
742 match dispatcher.block_on_jni_command(JNICommand::UciRawVendorCmd { gid, oid, payload })? {
743 UciResponse::RawVendorRsp(response) => Ok((
744 response.get_group_id().to_i32().unwrap(),
745 response.get_opcode().to_i32().unwrap(),
746 get_vendor_uci_payload(response)?,
747 )),
748 _ => Err(UwbErr::failed()),
749 }
750 }
751
status_code_to_res(status_code: StatusCode) -> Result<(), UwbErr>752 fn status_code_to_res(status_code: StatusCode) -> Result<(), UwbErr> {
753 match status_code {
754 StatusCode::UciStatusOk => Ok(()),
755 _ => Err(UwbErr::StatusCode(status_code)),
756 }
757 }
758
759 /// create a dispatcher instance
760 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherNew( env: JNIEnv, obj: JObject, ) -> jlong761 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherNew(
762 env: JNIEnv,
763 obj: JObject,
764 ) -> jlong {
765 let eventmanager = match EventManager::new(env, obj) {
766 Ok(evtmgr) => evtmgr,
767 Err(err) => {
768 error!("Fail to create event manager{:?}", err);
769 return *JObject::null() as jlong;
770 }
771 };
772 match DispatcherImpl::new(eventmanager) {
773 Ok(dispatcher) => Box::into_raw(Box::new(dispatcher)) as jlong,
774 Err(err) => {
775 error!("Fail to create dispatcher {:?}", err);
776 *JObject::null() as jlong
777 }
778 }
779 }
780
781 /// destroy the dispatcher instance
782 #[no_mangle]
Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherDestroy( env: JNIEnv, obj: JObject, )783 pub extern "system" fn Java_com_android_server_uwb_jni_NativeUwbManager_nativeDispatcherDestroy(
784 env: JNIEnv,
785 obj: JObject,
786 ) {
787 let dispatcher_ptr_value = match env.get_field(obj, "mDispatcherPointer", "J") {
788 Ok(value) => value,
789 Err(err) => {
790 error!("Failed to get the pointer with: {:?}", err);
791 return;
792 }
793 };
794 let dispatcher_ptr = match dispatcher_ptr_value.j() {
795 Ok(value) => value,
796 Err(err) => {
797 error!("Failed to get the pointer with: {:?}", err);
798 return;
799 }
800 };
801 // Safety: dispatcher pointer must not be a null pointer and must point to a valid dispatcher object.
802 // This can be ensured because the dispatcher is created in an earlier stage and
803 // won't be deleted before calling this destroy function.
804 // This function will early return if the instance is already destroyed.
805 let _boxed_dispatcher = unsafe { Box::from_raw(dispatcher_ptr as *mut DispatcherImpl) };
806 info!("The dispatcher successfully destroyed.");
807 }
808
get_power_stats<'a, T: Context<'a>>(context: &T) -> Result<[JValue<'a>; 4], UwbErr>809 fn get_power_stats<'a, T: Context<'a>>(context: &T) -> Result<[JValue<'a>; 4], UwbErr> {
810 let dispatcher = context.get_dispatcher()?;
811 match dispatcher.block_on_jni_command(JNICommand::UciGetPowerStats)? {
812 UciResponse::AndroidGetPowerStatsRsp(data) => Ok([
813 JValue::Int(data.get_stats().idle_time_ms as i32),
814 JValue::Int(data.get_stats().tx_time_ms as i32),
815 JValue::Int(data.get_stats().rx_time_ms as i32),
816 JValue::Int(data.get_stats().total_wake_count as i32),
817 ]),
818 _ => Err(UwbErr::failed()),
819 }
820 }
821
uwa_get_device_info(dispatcher: &dyn Dispatcher) -> Result<UciResponse, UwbErr>822 fn uwa_get_device_info(dispatcher: &dyn Dispatcher) -> Result<UciResponse, UwbErr> {
823 let res = dispatcher.block_on_jni_command(JNICommand::UciGetDeviceInfo)?;
824 Ok(res)
825 }
826
reset_device<'a, T: Context<'a>>(context: &T, reset_config: u8) -> Result<(), UwbErr>827 fn reset_device<'a, T: Context<'a>>(context: &T, reset_config: u8) -> Result<(), UwbErr> {
828 let dispatcher = context.get_dispatcher()?;
829 let res = match dispatcher.block_on_jni_command(JNICommand::UciDeviceReset { reset_config })? {
830 UciResponse::DeviceResetRsp(data) => data,
831 _ => return Err(UwbErr::failed()),
832 };
833 status_code_to_res(res.get_status())
834 }
835
836 #[cfg(test)]
837 mod mock_context;
838 #[cfg(test)]
839 mod mock_dispatcher;
840
841 #[cfg(test)]
842 mod tests {
843 use super::*;
844
845 use crate::mock_context::MockContext;
846 use crate::mock_dispatcher::MockDispatcher;
847
848 #[test]
test_boolean_result_helper()849 fn test_boolean_result_helper() {
850 assert_eq!(true as jboolean, boolean_result_helper(Ok(()), "Foo"));
851 assert_eq!(false as jboolean, boolean_result_helper(Err(UwbErr::Undefined), "Foo"));
852 }
853
854 #[test]
test_byte_result_helper()855 fn test_byte_result_helper() {
856 assert_eq!(StatusCode::UciStatusOk.to_i8().unwrap(), byte_result_helper(Ok(()), "Foo"));
857 assert_eq!(
858 StatusCode::UciStatusFailed.to_i8().unwrap(),
859 byte_result_helper(Err(UwbErr::Undefined), "Foo")
860 );
861 assert_eq!(
862 StatusCode::UciStatusRejected.to_i8().unwrap(),
863 byte_result_helper(Err(UwbErr::StatusCode(StatusCode::UciStatusRejected)), "Foo")
864 );
865 }
866
867 #[test]
test_do_initialize()868 fn test_do_initialize() {
869 let packet = uwb_uci_packets::GetDeviceInfoRspBuilder {
870 status: StatusCode::UciStatusOk,
871 uci_version: 0,
872 mac_version: 0,
873 phy_version: 0,
874 uci_test_version: 0,
875 vendor_spec_info: vec![],
876 }
877 .build();
878
879 let mut dispatcher = MockDispatcher::new();
880 dispatcher.expect_send_jni_command(JNICommand::Enable, Ok(()));
881 dispatcher.expect_block_on_jni_command(
882 JNICommand::UciGetDeviceInfo,
883 Ok(UciResponse::GetDeviceInfoRsp(packet.clone())),
884 );
885 let mut context = MockContext::new(dispatcher);
886
887 let result = do_initialize(&context);
888 let device_info = context.get_mock_dispatcher().get_device_info().clone();
889 assert!(result.is_ok());
890 assert_eq!(device_info.unwrap().to_vec(), packet.to_vec());
891 }
892
893 #[test]
test_do_deinitialize()894 fn test_do_deinitialize() {
895 let mut dispatcher = MockDispatcher::new();
896 dispatcher.expect_send_jni_command(JNICommand::Disable(true), Ok(()));
897 dispatcher.expect_wait_for_exit(Ok(()));
898 let context = MockContext::new(dispatcher);
899
900 let result = do_deinitialize(&context);
901 assert!(result.is_ok());
902 }
903
904 #[test]
test_get_specification_info()905 fn test_get_specification_info() {
906 let packet = uwb_uci_packets::GetDeviceInfoRspBuilder {
907 status: StatusCode::UciStatusOk,
908 uci_version: 0x1234,
909 mac_version: 0x5678,
910 phy_version: 0x9ABC,
911 uci_test_version: 0x1357,
912 vendor_spec_info: vec![],
913 }
914 .build();
915 let expected_array = [
916 0x34, 0x2, 0x1, // uci_version
917 0x78, 0x6, 0x5, // mac_version.
918 0xBC, 0xA, 0x9, // phy_version.
919 0x57, 0x3, 0x1, // uci_test_version.
920 1, // fira_major_version
921 0, // fira_minor_version
922 1, // ccc_major_version
923 0, // ccc_minor_version
924 ];
925
926 let mut dispatcher = MockDispatcher::new();
927 dispatcher.set_device_info(Some(packet));
928 let context = MockContext::new(dispatcher);
929
930 let results = get_specification_info(&context).unwrap();
931 for (idx, result) in results.iter().enumerate() {
932 assert_eq!(TryInto::<jint>::try_into(*result).unwrap(), expected_array[idx]);
933 }
934 }
935
936 #[test]
test_session_init()937 fn test_session_init() {
938 let session_id = 1234;
939 let session_type = 5;
940 let packet =
941 uwb_uci_packets::SessionInitRspBuilder { status: StatusCode::UciStatusOk }.build();
942
943 let mut dispatcher = MockDispatcher::new();
944 dispatcher.expect_block_on_jni_command(
945 JNICommand::UciSessionInit(session_id, session_type),
946 Ok(UciResponse::SessionInitRsp(packet)),
947 );
948 let context = MockContext::new(dispatcher);
949
950 let result = session_init(&context, session_id, session_type);
951 assert!(result.is_ok());
952 }
953
954 #[test]
test_session_deinit()955 fn test_session_deinit() {
956 let session_id = 1234;
957 let packet =
958 uwb_uci_packets::SessionDeinitRspBuilder { status: StatusCode::UciStatusOk }.build();
959
960 let mut dispatcher = MockDispatcher::new();
961 dispatcher.expect_block_on_jni_command(
962 JNICommand::UciSessionDeinit(session_id),
963 Ok(UciResponse::SessionDeinitRsp(packet)),
964 );
965 let context = MockContext::new(dispatcher);
966
967 let result = session_deinit(&context, session_id);
968 assert!(result.is_ok());
969 }
970
971 #[test]
test_get_session_count()972 fn test_get_session_count() {
973 let session_count = 7;
974 let packet = uwb_uci_packets::SessionGetCountRspBuilder {
975 status: StatusCode::UciStatusOk,
976 session_count,
977 }
978 .build();
979
980 let mut dispatcher = MockDispatcher::new();
981 dispatcher.expect_block_on_jni_command(
982 JNICommand::UciSessionGetCount,
983 Ok(UciResponse::SessionGetCountRsp(packet)),
984 );
985 let context = MockContext::new(dispatcher);
986
987 let result = get_session_count(&context).unwrap();
988 assert_eq!(result, session_count as jbyte);
989 }
990
991 #[test]
test_ranging_start()992 fn test_ranging_start() {
993 let session_id = 1234;
994 let packet =
995 uwb_uci_packets::RangeStartRspBuilder { status: StatusCode::UciStatusOk }.build();
996
997 let mut dispatcher = MockDispatcher::new();
998 dispatcher.expect_block_on_jni_command(
999 JNICommand::UciStartRange(session_id),
1000 Ok(UciResponse::RangeStartRsp(packet)),
1001 );
1002 let context = MockContext::new(dispatcher);
1003
1004 let result = ranging_start(&context, session_id);
1005 assert!(result.is_ok());
1006 }
1007
1008 #[test]
test_ranging_stop()1009 fn test_ranging_stop() {
1010 let session_id = 1234;
1011 let packet =
1012 uwb_uci_packets::RangeStopRspBuilder { status: StatusCode::UciStatusOk }.build();
1013
1014 let mut dispatcher = MockDispatcher::new();
1015 dispatcher.expect_block_on_jni_command(
1016 JNICommand::UciStopRange(session_id),
1017 Ok(UciResponse::RangeStopRsp(packet)),
1018 );
1019 let context = MockContext::new(dispatcher);
1020
1021 let result = ranging_stop(&context, session_id);
1022 assert!(result.is_ok());
1023 }
1024
1025 #[test]
test_get_session_state()1026 fn test_get_session_state() {
1027 let session_id = 1234;
1028 let session_state = uwb_uci_packets::SessionState::SessionStateActive;
1029 let packet = uwb_uci_packets::SessionGetStateRspBuilder {
1030 status: StatusCode::UciStatusOk,
1031 session_state,
1032 }
1033 .build();
1034
1035 let mut dispatcher = MockDispatcher::new();
1036 dispatcher.expect_block_on_jni_command(
1037 JNICommand::UciGetSessionState(session_id),
1038 Ok(UciResponse::SessionGetStateRsp(packet)),
1039 );
1040 let context = MockContext::new(dispatcher);
1041
1042 let result = get_session_state(&context, session_id).unwrap();
1043 assert_eq!(result, session_state as jbyte);
1044 }
1045
1046 #[test]
test_set_app_configurations()1047 fn test_set_app_configurations() {
1048 let session_id = 1234;
1049 let no_of_params = 3;
1050 let app_config_param_len = 5;
1051 let app_configs = vec![1, 2, 3, 4, 5];
1052 let fake_app_config_params = std::ptr::null_mut();
1053 let packet = uwb_uci_packets::SessionSetAppConfigRspBuilder {
1054 status: StatusCode::UciStatusOk,
1055 cfg_status: vec![],
1056 }
1057 .build();
1058
1059 let mut dispatcher = MockDispatcher::new();
1060 dispatcher.expect_block_on_jni_command(
1061 JNICommand::UciSetAppConfig {
1062 session_id,
1063 no_of_params,
1064 app_config_param_len,
1065 app_configs: app_configs.clone(),
1066 },
1067 Ok(UciResponse::SessionSetAppConfigRsp(packet.clone())),
1068 );
1069 let mut context = MockContext::new(dispatcher);
1070 context.expect_convert_byte_array(fake_app_config_params, Ok(app_configs));
1071
1072 let result = set_app_configurations(
1073 &context,
1074 session_id,
1075 no_of_params,
1076 app_config_param_len,
1077 fake_app_config_params,
1078 )
1079 .unwrap();
1080 assert_eq!(result.to_vec(), packet.to_vec());
1081 }
1082
1083 #[test]
test_get_app_configurations()1084 fn test_get_app_configurations() {
1085 let session_id = 1234;
1086 let no_of_params = 3;
1087 let app_config_param_len = 5;
1088 let app_configs = vec![1, 2, 3, 4, 5];
1089 let fake_app_config_params = std::ptr::null_mut();
1090 let packet = uwb_uci_packets::SessionGetAppConfigRspBuilder {
1091 status: StatusCode::UciStatusOk,
1092 tlvs: vec![],
1093 }
1094 .build();
1095
1096 let mut dispatcher = MockDispatcher::new();
1097 dispatcher.expect_block_on_jni_command(
1098 JNICommand::UciGetAppConfig {
1099 session_id,
1100 no_of_params,
1101 app_config_param_len,
1102 app_configs: app_configs.clone(),
1103 },
1104 Ok(UciResponse::SessionGetAppConfigRsp(packet.clone())),
1105 );
1106 let mut context = MockContext::new(dispatcher);
1107 context.expect_convert_byte_array(fake_app_config_params, Ok(app_configs));
1108
1109 let result = get_app_configurations(
1110 &context,
1111 session_id,
1112 no_of_params,
1113 app_config_param_len,
1114 fake_app_config_params,
1115 )
1116 .unwrap();
1117 assert_eq!(result.to_vec(), packet.to_vec());
1118 }
1119
1120 #[test]
test_get_caps_info()1121 fn test_get_caps_info() {
1122 let packet = uwb_uci_packets::GetCapsInfoRspBuilder {
1123 status: StatusCode::UciStatusOk,
1124 tlvs: vec![],
1125 }
1126 .build();
1127
1128 let mut dispatcher = MockDispatcher::new();
1129 dispatcher.expect_block_on_jni_command(
1130 JNICommand::UciGetCapsInfo,
1131 Ok(UciResponse::GetCapsInfoRsp(packet.clone())),
1132 );
1133 let context = MockContext::new(dispatcher);
1134
1135 let result = get_caps_info(&context).unwrap();
1136 assert_eq!(result.to_vec(), packet.to_vec());
1137 }
1138
1139 #[test]
test_multicast_list_update()1140 fn test_multicast_list_update() {
1141 let session_id = 1234;
1142 let action = 3;
1143 let no_of_controlee = 5;
1144 let fake_addresses = std::ptr::null_mut();
1145 let address_list = Box::new([1, 3, 5, 7, 9]);
1146 let fake_sub_session_ids = std::ptr::null_mut();
1147 let sub_session_id_list = Box::new([2, 4, 6, 8, 10]);
1148 let packet = uwb_uci_packets::SessionUpdateControllerMulticastListRspBuilder {
1149 status: StatusCode::UciStatusOk,
1150 }
1151 .build();
1152
1153 let mut dispatcher = MockDispatcher::new();
1154 dispatcher.expect_block_on_jni_command(
1155 JNICommand::UciSessionUpdateMulticastList {
1156 session_id,
1157 action,
1158 no_of_controlee,
1159 address_list: address_list.to_vec(),
1160 sub_session_id_list: sub_session_id_list.to_vec(),
1161 },
1162 Ok(UciResponse::SessionUpdateControllerMulticastListRsp(packet)),
1163 );
1164 let mut context = MockContext::new(dispatcher);
1165 context.expect_get_array_length(fake_addresses, Ok(address_list.len() as jsize));
1166 context.expect_get_short_array_region(fake_addresses, 0, Ok(address_list));
1167 context
1168 .expect_get_array_length(fake_sub_session_ids, Ok(sub_session_id_list.len() as jsize));
1169 context.expect_get_int_array_region(fake_sub_session_ids, 0, Ok(sub_session_id_list));
1170
1171 let result = multicast_list_update(
1172 &context,
1173 session_id,
1174 action,
1175 no_of_controlee,
1176 fake_addresses,
1177 fake_sub_session_ids,
1178 );
1179 assert!(result.is_ok());
1180 }
1181
1182 #[test]
test_set_country_code()1183 fn test_set_country_code() {
1184 let fake_country_code = std::ptr::null_mut();
1185 let country_code = "US".as_bytes().to_vec();
1186 let packet =
1187 uwb_uci_packets::AndroidSetCountryCodeRspBuilder { status: StatusCode::UciStatusOk }
1188 .build();
1189
1190 let mut dispatcher = MockDispatcher::new();
1191 dispatcher.expect_block_on_jni_command(
1192 JNICommand::UciSetCountryCode { code: country_code.clone() },
1193 Ok(UciResponse::AndroidSetCountryCodeRsp(packet)),
1194 );
1195 let mut context = MockContext::new(dispatcher);
1196 context.expect_convert_byte_array(fake_country_code, Ok(country_code));
1197
1198 let result = set_country_code(&context, fake_country_code);
1199 assert!(result.is_ok());
1200 }
1201
1202 #[test]
test_send_raw_vendor_cmd()1203 fn test_send_raw_vendor_cmd() {
1204 let gid = 2;
1205 let oid = 4;
1206 let opcode = 6;
1207 let fake_payload = std::ptr::null_mut();
1208 let payload = vec![1, 2, 4, 8];
1209 let response = vec![3, 6, 9];
1210 let packet = uwb_uci_packets::UciVendor_9_ResponseBuilder {
1211 opcode,
1212 payload: Some(response.clone().into()),
1213 }
1214 .build()
1215 .into();
1216
1217 let mut dispatcher = MockDispatcher::new();
1218 dispatcher.expect_block_on_jni_command(
1219 JNICommand::UciRawVendorCmd { gid, oid, payload: payload.clone() },
1220 Ok(UciResponse::RawVendorRsp(packet)),
1221 );
1222 let mut context = MockContext::new(dispatcher);
1223 context.expect_convert_byte_array(fake_payload, Ok(payload));
1224
1225 let result = send_raw_vendor_cmd(&context, gid, oid, fake_payload).unwrap();
1226 assert_eq!(result.0, uwb_uci_packets::GroupId::VendorReserved9 as i32);
1227 assert_eq!(result.1, opcode as i32);
1228 assert_eq!(result.2, response);
1229 }
1230
1231 #[test]
test_get_power_stats()1232 fn test_get_power_stats() {
1233 let idle_time_ms = 5;
1234 let tx_time_ms = 4;
1235 let rx_time_ms = 3;
1236 let total_wake_count = 2;
1237 let packet = uwb_uci_packets::AndroidGetPowerStatsRspBuilder {
1238 stats: uwb_uci_packets::PowerStats {
1239 status: StatusCode::UciStatusOk,
1240 idle_time_ms,
1241 tx_time_ms,
1242 rx_time_ms,
1243 total_wake_count,
1244 },
1245 }
1246 .build();
1247
1248 let mut dispatcher = MockDispatcher::new();
1249 dispatcher.expect_block_on_jni_command(
1250 JNICommand::UciGetPowerStats,
1251 Ok(UciResponse::AndroidGetPowerStatsRsp(packet)),
1252 );
1253 let context = MockContext::new(dispatcher);
1254
1255 let result = get_power_stats(&context).unwrap();
1256 assert_eq!(TryInto::<jint>::try_into(result[0]).unwrap(), idle_time_ms as jint);
1257 assert_eq!(TryInto::<jint>::try_into(result[1]).unwrap(), tx_time_ms as jint);
1258 assert_eq!(TryInto::<jint>::try_into(result[2]).unwrap(), rx_time_ms as jint);
1259 assert_eq!(TryInto::<jint>::try_into(result[3]).unwrap(), total_wake_count as jint);
1260 }
1261
1262 #[test]
test_reset_device()1263 fn test_reset_device() {
1264 let reset_config = uwb_uci_packets::ResetConfig::UwbsReset as u8;
1265 let packet =
1266 uwb_uci_packets::DeviceResetRspBuilder { status: StatusCode::UciStatusOk }.build();
1267
1268 let mut dispatcher = MockDispatcher::new();
1269 dispatcher.expect_block_on_jni_command(
1270 JNICommand::UciDeviceReset { reset_config },
1271 Ok(UciResponse::DeviceResetRsp(packet)),
1272 );
1273 let context = MockContext::new(dispatcher);
1274
1275 let result = reset_device(&context, reset_config);
1276 assert!(result.is_ok());
1277 }
1278 }
1279