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 //! Implementation of NotificationManagerAndroid and its builder.
16 
17 use crate::jclass_name::{
18     MULTICAST_LIST_UPDATE_STATUS_CLASS, UWB_DL_TDOA_MEASUREMENT_CLASS,
19     UWB_OWR_AOA_MEASUREMENT_CLASS, UWB_RADAR_DATA_CLASS, UWB_RADAR_SWEEP_DATA_CLASS,
20     UWB_RANGING_DATA_CLASS, UWB_TWO_WAY_MEASUREMENT_CLASS,
21 };
22 
23 use std::collections::HashMap;
24 use std::sync::Arc;
25 
26 use jni::errors::Error as JNIError;
27 use jni::objects::{GlobalRef, JClass, JMethodID, JObject, JValue};
28 use jni::signature::TypeSignature;
29 use jni::sys::jvalue;
30 use jni::{AttachGuard, JavaVM};
31 use log::{debug, error};
32 use uwb_core::error::{Error as UwbError, Result as UwbResult};
33 use uwb_core::params::{ControleeStatusList, UwbAddress};
34 use uwb_core::uci::uci_manager_sync::{NotificationManager, NotificationManagerBuilder};
35 use uwb_core::uci::{
36     CoreNotification, DataRcvNotification, RadarDataRcvNotification, RangingMeasurements,
37     SessionNotification, SessionRangeData,
38 };
39 use uwb_uci_packets::{
40     radar_bytes_per_sample_value, ExtendedAddressDlTdoaRangingMeasurement,
41     ExtendedAddressOwrAoaRangingMeasurement, ExtendedAddressTwoWayRangingMeasurement,
42     MacAddressIndicator, RangingMeasurementType, SessionState,
43     ShortAddressDlTdoaRangingMeasurement, ShortAddressOwrAoaRangingMeasurement,
44     ShortAddressTwoWayRangingMeasurement, StatusCode,
45 };
46 
47 // Byte size of mac address length:
48 const SHORT_MAC_ADDRESS_LEN: i32 = 2;
49 const EXTENDED_MAC_ADDRESS_LEN: i32 = 8;
50 const MAX_ANCHOR_LOCATION_LEN: i32 = 12;
51 const MAX_RANGING_ROUNDS_LEN: i32 = 16;
52 const MAX_RADAR_VENDOR_DATA_LEN: i32 = 256;
53 
54 // Maximum allowed number of Java Object to be allocated inside with_local_frame
55 const MAX_JAVA_OBJECTS_CAPACITY: i32 = 50;
56 
57 #[derive(Debug, PartialEq)]
58 enum MacAddress {
59     Short(u16),
60     Extended(u64),
61 }
62 impl MacAddress {
into_ne_bytes(self) -> Vec<u8>63     fn into_ne_bytes(self) -> Vec<u8> {
64         match self {
65             MacAddress::Short(val) => val.to_ne_bytes().into(),
66             MacAddress::Extended(val) => val.to_ne_bytes().into(),
67         }
68     }
69 }
70 
71 struct TwoWayRangingMeasurement {
72     mac_address: MacAddress,
73     status: StatusCode,
74     nlos: u8,
75     distance: u16,
76     aoa_azimuth: u16,
77     aoa_azimuth_fom: u8,
78     aoa_elevation: u16,
79     aoa_elevation_fom: u8,
80     aoa_destination_azimuth: u16,
81     aoa_destination_azimuth_fom: u8,
82     aoa_destination_elevation: u16,
83     aoa_destination_elevation_fom: u8,
84     slot_index: u8,
85     rssi: u8,
86 }
87 
88 struct OwrAoaRangingMeasurement {
89     mac_address: MacAddress,
90     status: StatusCode,
91     nlos: u8,
92     frame_sequence_number: u8,
93     block_index: u16,
94     aoa_azimuth: u16,
95     aoa_azimuth_fom: u8,
96     aoa_elevation: u16,
97     aoa_elevation_fom: u8,
98 }
99 
100 impl From<ShortAddressTwoWayRangingMeasurement> for TwoWayRangingMeasurement {
from(measurement: ShortAddressTwoWayRangingMeasurement) -> Self101     fn from(measurement: ShortAddressTwoWayRangingMeasurement) -> Self {
102         TwoWayRangingMeasurement {
103             mac_address: MacAddress::Short(measurement.mac_address),
104             status: (measurement.status),
105             nlos: (measurement.nlos),
106             distance: (measurement.distance),
107             aoa_azimuth: (measurement.aoa_azimuth),
108             aoa_azimuth_fom: (measurement.aoa_azimuth_fom),
109             aoa_elevation: (measurement.aoa_elevation),
110             aoa_elevation_fom: (measurement.aoa_elevation_fom),
111             aoa_destination_azimuth: (measurement.aoa_destination_azimuth),
112             aoa_destination_azimuth_fom: (measurement.aoa_destination_azimuth_fom),
113             aoa_destination_elevation: (measurement.aoa_destination_elevation),
114             aoa_destination_elevation_fom: (measurement.aoa_destination_elevation_fom),
115             slot_index: (measurement.slot_index),
116             rssi: (measurement.rssi),
117         }
118     }
119 }
120 
121 impl From<ExtendedAddressTwoWayRangingMeasurement> for TwoWayRangingMeasurement {
from(measurement: ExtendedAddressTwoWayRangingMeasurement) -> Self122     fn from(measurement: ExtendedAddressTwoWayRangingMeasurement) -> Self {
123         TwoWayRangingMeasurement {
124             mac_address: MacAddress::Extended(measurement.mac_address),
125             status: (measurement.status),
126             nlos: (measurement.nlos),
127             distance: (measurement.distance),
128             aoa_azimuth: (measurement.aoa_azimuth),
129             aoa_azimuth_fom: (measurement.aoa_azimuth_fom),
130             aoa_elevation: (measurement.aoa_elevation),
131             aoa_elevation_fom: (measurement.aoa_elevation_fom),
132             aoa_destination_azimuth: (measurement.aoa_destination_azimuth),
133             aoa_destination_azimuth_fom: (measurement.aoa_destination_azimuth_fom),
134             aoa_destination_elevation: (measurement.aoa_destination_elevation),
135             aoa_destination_elevation_fom: (measurement.aoa_destination_elevation_fom),
136             slot_index: (measurement.slot_index),
137             rssi: (measurement.rssi),
138         }
139     }
140 }
141 
142 impl From<ShortAddressOwrAoaRangingMeasurement> for OwrAoaRangingMeasurement {
from(measurement: ShortAddressOwrAoaRangingMeasurement) -> Self143     fn from(measurement: ShortAddressOwrAoaRangingMeasurement) -> Self {
144         OwrAoaRangingMeasurement {
145             mac_address: MacAddress::Short(measurement.mac_address),
146             status: (measurement.status),
147             nlos: (measurement.nlos),
148             frame_sequence_number: (measurement.frame_sequence_number),
149             block_index: (measurement.block_index),
150             aoa_azimuth: (measurement.aoa_azimuth),
151             aoa_azimuth_fom: (measurement.aoa_azimuth_fom),
152             aoa_elevation: (measurement.aoa_elevation),
153             aoa_elevation_fom: (measurement.aoa_elevation_fom),
154         }
155     }
156 }
157 
158 impl From<ExtendedAddressOwrAoaRangingMeasurement> for OwrAoaRangingMeasurement {
from(measurement: ExtendedAddressOwrAoaRangingMeasurement) -> Self159     fn from(measurement: ExtendedAddressOwrAoaRangingMeasurement) -> Self {
160         OwrAoaRangingMeasurement {
161             mac_address: MacAddress::Extended(measurement.mac_address),
162             status: (measurement.status),
163             nlos: (measurement.nlos),
164             frame_sequence_number: (measurement.frame_sequence_number),
165             block_index: (measurement.block_index),
166             aoa_azimuth: (measurement.aoa_azimuth),
167             aoa_azimuth_fom: (measurement.aoa_azimuth_fom),
168             aoa_elevation: (measurement.aoa_elevation),
169             aoa_elevation_fom: (measurement.aoa_elevation_fom),
170         }
171     }
172 }
173 
174 struct DlTdoaRangingMeasurement {
175     mac_address: MacAddress,
176     pub status: u8,
177     pub message_type: u8,
178     pub message_control: u16,
179     pub block_index: u16,
180     pub round_index: u8,
181     pub nlos: u8,
182     pub aoa_azimuth: u16,
183     pub aoa_azimuth_fom: u8,
184     pub aoa_elevation: u16,
185     pub aoa_elevation_fom: u8,
186     pub rssi: u8,
187     pub tx_timestamp: u64,
188     pub rx_timestamp: u64,
189     pub anchor_cfo: u16,
190     pub cfo: u16,
191     pub initiator_reply_time: u32,
192     pub responder_reply_time: u32,
193     pub initiator_responder_tof: u16,
194     pub dt_anchor_location: Vec<u8>,
195     pub ranging_rounds: Vec<u8>,
196 }
197 
198 impl From<ExtendedAddressDlTdoaRangingMeasurement> for DlTdoaRangingMeasurement {
from(measurement: ExtendedAddressDlTdoaRangingMeasurement) -> Self199     fn from(measurement: ExtendedAddressDlTdoaRangingMeasurement) -> Self {
200         DlTdoaRangingMeasurement {
201             mac_address: MacAddress::Extended(measurement.mac_address),
202             status: (measurement.measurement.status),
203             message_type: (measurement.measurement.message_type),
204             message_control: (measurement.measurement.message_control),
205             block_index: (measurement.measurement.block_index),
206             round_index: (measurement.measurement.round_index),
207             nlos: (measurement.measurement.nlos),
208             aoa_azimuth: (measurement.measurement.aoa_azimuth),
209             aoa_azimuth_fom: (measurement.measurement.aoa_azimuth_fom),
210             aoa_elevation: (measurement.measurement.aoa_elevation),
211             aoa_elevation_fom: (measurement.measurement.aoa_elevation_fom),
212             rssi: (measurement.measurement.rssi),
213             tx_timestamp: (measurement.measurement.tx_timestamp),
214             rx_timestamp: (measurement.measurement.rx_timestamp),
215             anchor_cfo: (measurement.measurement.anchor_cfo),
216             cfo: (measurement.measurement.cfo),
217             initiator_reply_time: (measurement.measurement.initiator_reply_time),
218             responder_reply_time: (measurement.measurement.responder_reply_time),
219             initiator_responder_tof: (measurement.measurement.initiator_responder_tof),
220             dt_anchor_location: (measurement.measurement.dt_anchor_location),
221             ranging_rounds: (measurement.measurement.ranging_rounds),
222         }
223     }
224 }
225 
226 impl From<ShortAddressDlTdoaRangingMeasurement> for DlTdoaRangingMeasurement {
from(measurement: ShortAddressDlTdoaRangingMeasurement) -> Self227     fn from(measurement: ShortAddressDlTdoaRangingMeasurement) -> Self {
228         DlTdoaRangingMeasurement {
229             mac_address: MacAddress::Short(measurement.mac_address),
230             status: (measurement.measurement.status),
231             message_type: (measurement.measurement.message_type),
232             message_control: (measurement.measurement.message_control),
233             block_index: (measurement.measurement.block_index),
234             round_index: (measurement.measurement.round_index),
235             nlos: (measurement.measurement.nlos),
236             aoa_azimuth: (measurement.measurement.aoa_azimuth),
237             aoa_azimuth_fom: (measurement.measurement.aoa_azimuth_fom),
238             aoa_elevation: (measurement.measurement.aoa_elevation),
239             aoa_elevation_fom: (measurement.measurement.aoa_elevation_fom),
240             rssi: (measurement.measurement.rssi),
241             tx_timestamp: (measurement.measurement.tx_timestamp),
242             rx_timestamp: (measurement.measurement.rx_timestamp),
243             anchor_cfo: (measurement.measurement.anchor_cfo),
244             cfo: (measurement.measurement.cfo),
245             initiator_reply_time: (measurement.measurement.initiator_reply_time),
246             responder_reply_time: (measurement.measurement.responder_reply_time),
247             initiator_responder_tof: (measurement.measurement.initiator_responder_tof),
248             dt_anchor_location: (measurement.measurement.dt_anchor_location),
249             ranging_rounds: (measurement.measurement.ranging_rounds),
250         }
251     }
252 }
253 
254 pub(crate) struct NotificationManagerAndroid {
255     pub chip_id: String,
256     // 'static annotation is needed as env is 'sent' by tokio::task::spawn_local.
257     pub env: AttachGuard<'static>,
258     /// Global reference to the class loader object (java/lang/ClassLoader) from the java thread
259     /// that local java UCI classes can be loaded.
260     /// See http://yangyingchao.github.io/android/2015/01/13/Android-JNI-FindClass-Error.html
261     pub class_loader_obj: GlobalRef,
262     /// Global reference to the java class holding the various UCI notification callback functions.
263     pub callback_obj: GlobalRef,
264     // *_jmethod_id are cached for faster callback using call_method_unchecked
265     pub jmethod_id_map: HashMap<String, JMethodID>,
266     // jclass are cached for faster callback
267     pub jclass_map: HashMap<String, GlobalRef>,
268 }
269 
270 // TODO(b/246678053): Need to add callbacks for Data Packet Rx, and Data Packet Tx events (like
271 // DATA_CREDIT_NTF, DATA_STATUS_NTF).
272 impl NotificationManagerAndroid {
273     /// Finds JClass stored in jclass map. Should be a member function, but disjoint field borrow
274     /// checker fails and mutability of individual fields has to be annotated.
find_local_class<'a>( jclass_map: &'a mut HashMap<String, GlobalRef>, class_loader_obj: &'a GlobalRef, env: &'a AttachGuard<'static>, class_name: &'a str, ) -> Result<JClass<'a>, JNIError>275     fn find_local_class<'a>(
276         jclass_map: &'a mut HashMap<String, GlobalRef>,
277         class_loader_obj: &'a GlobalRef,
278         env: &'a AttachGuard<'static>,
279         class_name: &'a str,
280     ) -> Result<JClass<'a>, JNIError> {
281         // Look for cached class
282         if jclass_map.get(class_name).is_none() {
283             // Find class using the class loader object, needed as this call is initiated from a
284             // different native thread.
285 
286             let env_class_name = *env.new_string(class_name).map_err(|e| {
287                 error!("UCI JNI: failed to create Java String: {e:?}");
288                 e
289             })?;
290             let class_value = env
291                 .call_method(
292                     class_loader_obj.as_obj(),
293                     "findClass",
294                     "(Ljava/lang/String;)Ljava/lang/Class;",
295                     &[JValue::Object(env_class_name)],
296                 )
297                 .map_err(|e| {
298                     error!("UCI JNI: failed to find java class {}: {:?}", class_name, e);
299                     e
300                 })?;
301             let jclass = match class_value.l() {
302                 Ok(obj) => Ok(JClass::from(obj)),
303                 Err(e) => {
304                     error!("UCI JNI: failed to find java class {}: {:?}", class_name, e);
305                     Err(e)
306                 }
307             }?;
308             // Cache JClass as a global reference.
309             jclass_map.insert(
310                 class_name.to_owned(),
311                 env.new_global_ref(jclass).map_err(|e| {
312                     error!("UCI JNI: global reference conversion failed: {:?}", e);
313                     e
314                 })?,
315             );
316         }
317         // Return JClass
318         Ok(jclass_map.get(class_name).unwrap().as_obj().into())
319     }
320 
cached_jni_call( &mut self, name: &str, sig: &str, args: &[jvalue], ) -> Result<JObject, JNIError>321     fn cached_jni_call(
322         &mut self,
323         name: &str,
324         sig: &str,
325         args: &[jvalue],
326     ) -> Result<JObject, JNIError> {
327         debug!("UCI JNI: callback {}", name);
328         let type_signature = TypeSignature::from_str(sig).map_err(|e| {
329             error!("UCI JNI: Invalid type signature: {:?}", e);
330             e
331         })?;
332         if type_signature.args.len() != args.len() {
333             error!(
334                 "UCI: type_signature requires {} args, but {} is provided",
335                 type_signature.args.len(),
336                 args.len()
337             );
338             return Err(jni::errors::Error::InvalidArgList(type_signature));
339         }
340         let name_signature = name.to_owned() + sig;
341         if !self.jmethod_id_map.contains_key(&name_signature) {
342             self.jmethod_id_map.insert(
343                 name_signature.clone(),
344                 self.env.get_method_id(self.callback_obj.as_obj(), name, sig).map_err(|e| {
345                     error!("UCI JNI: failed to get method: {:?}", e);
346                     e
347                 })?,
348             );
349         }
350         match self.env.call_method_unchecked(
351             self.callback_obj.as_obj(),
352             self.jmethod_id_map.get(&name_signature).unwrap().to_owned(),
353             type_signature.ret,
354             args,
355         ) {
356             Ok(_) => Ok(JObject::null()),
357             Err(e) => {
358                 error!("UCI JNI: callback {} failed!", name);
359                 Err(e)
360             }
361         }
362     }
363 
on_session_status_notification( &mut self, session_id: u32, session_token: u32, session_state: SessionState, reason_code: u8, ) -> Result<JObject, JNIError>364     fn on_session_status_notification(
365         &mut self,
366         session_id: u32,
367         session_token: u32,
368         session_state: SessionState,
369         reason_code: u8,
370     ) -> Result<JObject, JNIError> {
371         self.cached_jni_call(
372             "onSessionStatusNotificationReceived",
373             "(JIII)V",
374             &[
375                 jvalue::from(JValue::Long(session_id as i64)),
376                 jvalue::from(JValue::Int(session_token as i32)),
377                 jvalue::from(JValue::Int(session_state as i32)),
378                 jvalue::from(JValue::Int(reason_code as i32)),
379             ],
380         )
381     }
382 
on_session_update_multicast_notification( &mut self, session_id: u32, remaining_multicast_list_size: usize, status_list: ControleeStatusList, ) -> Result<JObject, JNIError>383     fn on_session_update_multicast_notification(
384         &mut self,
385         session_id: u32,
386         remaining_multicast_list_size: usize,
387         status_list: ControleeStatusList,
388     ) -> Result<JObject, JNIError> {
389         let remaining_multicast_list_size: i32 =
390             remaining_multicast_list_size.try_into().map_err(|_| JNIError::InvalidCtorReturn)?;
391         let mac_address_vec: Vec<[u8; 2]>;
392         let subsession_id_vec: Vec<_>;
393         let status_vec: Vec<_>;
394         let count: i32;
395         match status_list {
396             ControleeStatusList::V1(status_list) => {
397                 count = status_list.len().try_into().map_err(|_| JNIError::InvalidCtorReturn)?;
398                 (mac_address_vec, (subsession_id_vec, status_vec)) = status_list
399                     .into_iter()
400                     .map(|cs| (cs.mac_address, (cs.subsession_id as i64, i32::from(cs.status))))
401                     .unzip();
402             }
403             ControleeStatusList::V2(status_list) => {
404                 count = status_list.len().try_into().map_err(|_| JNIError::InvalidCtorReturn)?;
405                 (mac_address_vec, (subsession_id_vec, status_vec)) = status_list
406                     .into_iter()
407                     .map(|cs| (cs.mac_address, (0_i64, i32::from(cs.status))))
408                     .unzip();
409             }
410         }
411         let subsession_id_jlongarray = self.env.new_long_array(count)?;
412         let status_jintarray = self.env.new_int_array(count)?;
413 
414         let mac_address_vec_i8 =
415             mac_address_vec.iter().flat_map(|&[a, b]| vec![a as i8, b as i8]).collect::<Vec<i8>>();
416         let mac_address_slice: &[i8] = &mac_address_vec_i8;
417         let mac_address_jbytearray = self.env.new_byte_array(mac_address_slice.len() as i32)?;
418 
419         self.env.set_byte_array_region(mac_address_jbytearray, 0, mac_address_slice)?;
420         self.env.set_long_array_region(subsession_id_jlongarray, 0, &subsession_id_vec)?;
421         self.env.set_int_array_region(status_jintarray, 0, &status_vec)?;
422         let multicast_update_jclass = NotificationManagerAndroid::find_local_class(
423             &mut self.jclass_map,
424             &self.class_loader_obj,
425             &self.env,
426             MULTICAST_LIST_UPDATE_STATUS_CLASS,
427         )?;
428         let method_sig = "(L".to_owned() + MULTICAST_LIST_UPDATE_STATUS_CLASS + ";)V";
429 
430         // Safety: mac_address_jintarray is safely instantiated above.
431         let mac_address_jobject = unsafe { JObject::from_raw(mac_address_jbytearray) };
432 
433         // Safety: subsession_id_jlongarray is safely instantiated above.
434         let subsession_id_jobject = unsafe { JObject::from_raw(subsession_id_jlongarray) };
435 
436         // Safety: status_jintarray is safely instantiated above.
437         let status_jobject = unsafe { JObject::from_raw(status_jintarray) };
438 
439         let multicast_update_jobject = self.env.new_object(
440             multicast_update_jclass,
441             "(JII[B[J[I)V",
442             &[
443                 JValue::Long(session_id as i64),
444                 JValue::Int(remaining_multicast_list_size),
445                 JValue::Int(count),
446                 JValue::Object(mac_address_jobject),
447                 JValue::Object(subsession_id_jobject),
448                 JValue::Object(status_jobject),
449             ],
450         )?;
451         self.cached_jni_call(
452             "onMulticastListUpdateNotificationReceived",
453             &method_sig,
454             &[jvalue::from(JValue::Object(multicast_update_jobject))],
455         )
456     }
457 
458     // TODO(b/246678053): Re-factor usage of the RangingMeasurement enum below, to extract the
459     // fields in a common/caller method (and preferably not handle TwoWay/OwrAoa in this method).
on_session_dl_tdoa_range_data_notification( &mut self, range_data: SessionRangeData, ) -> Result<JObject, JNIError>460     fn on_session_dl_tdoa_range_data_notification(
461         &mut self,
462         range_data: SessionRangeData,
463     ) -> Result<JObject, JNIError> {
464         let raw_notification_jbytearray =
465             self.env.byte_array_from_slice(&range_data.raw_ranging_data)?;
466         let measurement_jclass = NotificationManagerAndroid::find_local_class(
467             &mut self.jclass_map,
468             &self.class_loader_obj,
469             &self.env,
470             UWB_DL_TDOA_MEASUREMENT_CLASS,
471         )?;
472         let bytearray_len: i32 = match &range_data.ranging_measurements {
473             uwb_core::uci::RangingMeasurements::ShortAddressTwoWay(_) => SHORT_MAC_ADDRESS_LEN,
474             uwb_core::uci::RangingMeasurements::ExtendedAddressTwoWay(_) => {
475                 EXTENDED_MAC_ADDRESS_LEN
476             }
477             uwb_core::uci::RangingMeasurements::ShortAddressDltdoa(_) => SHORT_MAC_ADDRESS_LEN,
478             uwb_core::uci::RangingMeasurements::ExtendedAddressDltdoa(_) => {
479                 EXTENDED_MAC_ADDRESS_LEN
480             }
481             _ => {
482                 return Err(JNIError::InvalidCtorReturn);
483             }
484         };
485         let address_jbytearray = self.env.new_byte_array(bytearray_len)?;
486         let anchor_location = self.env.new_byte_array(MAX_ANCHOR_LOCATION_LEN)?;
487         let active_ranging_rounds = self.env.new_byte_array(MAX_RANGING_ROUNDS_LEN)?;
488 
489         // Safety: address_jbytearray is safely instantiated above.
490         let address_jobject = unsafe { JObject::from_raw(address_jbytearray) };
491         // Safety: anchor_location is safely instantiated above.
492         let anchor_jobject = unsafe { JObject::from_raw(anchor_location) };
493         // Safety: active_ranging_rounds is safely instantiated above.
494         let active_ranging_rounds_jobject = unsafe { JObject::from_raw(active_ranging_rounds) };
495 
496         let zero_initiated_measurement_jobject = self
497             .env
498             .new_object(
499                 measurement_jclass,
500                 "([BIIIIIIIIIIIJJIIJJI[B[B)V",
501                 &[
502                     JValue::Object(address_jobject),
503                     JValue::Int(0),
504                     JValue::Int(0),
505                     JValue::Int(0),
506                     JValue::Int(0),
507                     JValue::Int(0),
508                     JValue::Int(0),
509                     JValue::Int(0),
510                     JValue::Int(0),
511                     JValue::Int(0),
512                     JValue::Int(0),
513                     JValue::Int(0),
514                     JValue::Long(0),
515                     JValue::Long(0),
516                     JValue::Int(0),
517                     JValue::Int(0),
518                     JValue::Long(0),
519                     JValue::Long(0),
520                     JValue::Int(0),
521                     JValue::Object(anchor_jobject),
522                     JValue::Object(active_ranging_rounds_jobject),
523                 ],
524             )
525             .map_err(|e| {
526                 error!("UCI JNI: measurement object creation failed: {:?}", e);
527                 e
528             })?;
529         let measurement_count: i32 = match &range_data.ranging_measurements {
530             RangingMeasurements::ShortAddressTwoWay(v) => v.len(),
531             RangingMeasurements::ExtendedAddressTwoWay(v) => v.len(),
532             RangingMeasurements::ShortAddressDltdoa(v) => v.len(),
533             RangingMeasurements::ExtendedAddressDltdoa(v) => v.len(),
534             _ => {
535                 return Err(JNIError::InvalidCtorReturn);
536             }
537         }
538         .try_into()
539         .map_err(|_| JNIError::InvalidCtorReturn)?;
540         let mac_indicator = match &range_data.ranging_measurements {
541             RangingMeasurements::ShortAddressTwoWay(_) => MacAddressIndicator::ShortAddress,
542             RangingMeasurements::ExtendedAddressTwoWay(_) => MacAddressIndicator::ExtendedAddress,
543             RangingMeasurements::ShortAddressDltdoa(_) => MacAddressIndicator::ShortAddress,
544             RangingMeasurements::ExtendedAddressDltdoa(_) => MacAddressIndicator::ExtendedAddress,
545             _ => {
546                 return Err(JNIError::InvalidCtorReturn);
547             }
548         };
549 
550         let measurements_jobjectarray = self.env.new_object_array(
551             measurement_count,
552             measurement_jclass,
553             zero_initiated_measurement_jobject,
554         )?;
555 
556         for (i, measurement) in match range_data.ranging_measurements {
557             RangingMeasurements::ShortAddressDltdoa(v) => {
558                 v.into_iter().map(DlTdoaRangingMeasurement::from).collect::<Vec<_>>()
559             }
560             RangingMeasurements::ExtendedAddressDltdoa(v) => {
561                 v.into_iter().map(DlTdoaRangingMeasurement::from).collect::<Vec<_>>()
562             }
563             _ => Vec::new(),
564         }
565         .into_iter()
566         .enumerate()
567         {
568             // cast to i8 as java do not support unsigned:
569             let mac_address_i8 = measurement
570                 .mac_address
571                 .into_ne_bytes()
572                 .iter()
573                 .map(|b| b.to_owned() as i8)
574                 .collect::<Vec<_>>();
575             let mac_address_jbytearray = self.env.new_byte_array(mac_address_i8.len() as i32)?;
576             self.env.set_byte_array_region(mac_address_jbytearray, 0, &mac_address_i8)?;
577 
578             let dt_anchor_location_jbytearray =
579                 self.env.byte_array_from_slice(&measurement.dt_anchor_location)?;
580 
581             let ranging_rounds_jbytearray =
582                 self.env.byte_array_from_slice(&measurement.ranging_rounds)?;
583 
584             // Safety: mac_address_jbytearray is safely instantiated above.
585             let mac_address_jobject = unsafe { JObject::from_raw(mac_address_jbytearray) };
586             let dt_anchor_location_jobject =
587             // Safety: dt_anchor_location_jbytearray is safely instantiated above.
588                 unsafe { JObject::from_raw(dt_anchor_location_jbytearray) };
589             // Safety: ranging_rounds_jbytearray is safely instantiated above.
590             let ranging_rounds_jobject = unsafe { JObject::from_raw(ranging_rounds_jbytearray) };
591 
592             let measurement_jobject = self
593                 .env
594                 .new_object(
595                     measurement_jclass,
596                     "([BIIIIIIIIIIIJJIIJJI[B[B)V",
597                     &[
598                         JValue::Object(mac_address_jobject),
599                         JValue::Int(measurement.status as i32),
600                         JValue::Int(measurement.message_type as i32),
601                         JValue::Int(measurement.message_control as i32),
602                         JValue::Int(measurement.block_index as i32),
603                         JValue::Int(measurement.round_index as i32),
604                         JValue::Int(measurement.nlos as i32),
605                         JValue::Int(measurement.aoa_azimuth as i32),
606                         JValue::Int(measurement.aoa_azimuth_fom as i32),
607                         JValue::Int(measurement.aoa_elevation as i32),
608                         JValue::Int(measurement.aoa_elevation_fom as i32),
609                         JValue::Int(measurement.rssi as i32),
610                         JValue::Long(measurement.tx_timestamp as i64),
611                         JValue::Long(measurement.rx_timestamp as i64),
612                         JValue::Int(measurement.anchor_cfo as i32),
613                         JValue::Int(measurement.cfo as i32),
614                         JValue::Long(measurement.initiator_reply_time as i64),
615                         JValue::Long(measurement.responder_reply_time as i64),
616                         JValue::Int(measurement.initiator_responder_tof as i32),
617                         JValue::Object(dt_anchor_location_jobject),
618                         JValue::Object(ranging_rounds_jobject),
619                     ],
620                 )
621                 .map_err(|e| {
622                     error!("UCI JNI: measurement object creation failed: {:?}", e);
623                     e
624                 })?;
625             self.env
626                 .set_object_array_element(measurements_jobjectarray, i as i32, measurement_jobject)
627                 .map_err(|e| {
628                     error!("UCI JNI: measurement object copy failed: {:?}", e);
629                     e
630                 })?;
631         }
632         // Create UwbRangingData
633         let ranging_data_jclass = NotificationManagerAndroid::find_local_class(
634             &mut self.jclass_map,
635             &self.class_loader_obj,
636             &self.env,
637             UWB_RANGING_DATA_CLASS,
638         )?;
639 
640         let method_sig = "(JJIJIII[L".to_owned() + UWB_DL_TDOA_MEASUREMENT_CLASS + ";[B)V";
641 
642         // Safety: measurements_jobjectarray is safely instantiated above.
643         let measurements_jobject = unsafe { JObject::from_raw(measurements_jobjectarray) };
644         // Safety: raw_notification_jbytearray is safely instantiated above.
645         let raw_notification_jobject = unsafe { JObject::from_raw(raw_notification_jbytearray) };
646 
647         let range_data_jobject = self
648             .env
649             .new_object(
650                 ranging_data_jclass,
651                 &method_sig,
652                 &[
653                     JValue::Long(range_data.sequence_number as i64),
654                     // session_token below has already been mapped to session_id by uci layer.
655                     JValue::Long(range_data.session_token as i64),
656                     JValue::Int(range_data.rcr_indicator as i32),
657                     JValue::Long(range_data.current_ranging_interval_ms as i64),
658                     JValue::Int(range_data.ranging_measurement_type as i32),
659                     JValue::Int(mac_indicator as i32),
660                     JValue::Int(measurement_count),
661                     JValue::Object(measurements_jobject),
662                     JValue::Object(raw_notification_jobject),
663                 ],
664             )
665             .map_err(|e| {
666                 error!("UCI JNI: Ranging Data object creation failed: {:?}", e);
667                 e
668             })?;
669 
670         let method_sig = "(L".to_owned() + UWB_RANGING_DATA_CLASS + ";)V";
671         self.cached_jni_call(
672             "onRangeDataNotificationReceived",
673             &method_sig,
674             &[jvalue::from(JValue::Object(range_data_jobject))],
675         )
676     }
677 
on_two_way_range_data_notification( &mut self, bytearray_len: i32, measurement_count: i32, measurements: Vec<TwoWayRangingMeasurement>, ) -> Result<jni::sys::jobjectArray, JNIError>678     fn on_two_way_range_data_notification(
679         &mut self,
680         bytearray_len: i32,
681         measurement_count: i32,
682         measurements: Vec<TwoWayRangingMeasurement>,
683     ) -> Result<jni::sys::jobjectArray, JNIError> {
684         let measurement_jclass = NotificationManagerAndroid::find_local_class(
685             &mut self.jclass_map,
686             &self.class_loader_obj,
687             &self.env,
688             UWB_TWO_WAY_MEASUREMENT_CLASS,
689         )?;
690         let address_jbytearray = self.env.new_byte_array(bytearray_len)?;
691 
692         // Safety: address_jbytearray is safely instantiated above.
693         let address_jobject = unsafe { JObject::from_raw(address_jbytearray) };
694 
695         let zero_initiated_measurement_jobject = self
696             .env
697             .new_object(
698                 measurement_jclass,
699                 "([BIIIIIIIIIIIII)V",
700                 &[
701                     JValue::Object(address_jobject),
702                     JValue::Int(0),
703                     JValue::Int(0),
704                     JValue::Int(0),
705                     JValue::Int(0),
706                     JValue::Int(0),
707                     JValue::Int(0),
708                     JValue::Int(0),
709                     JValue::Int(0),
710                     JValue::Int(0),
711                     JValue::Int(0),
712                     JValue::Int(0),
713                     JValue::Int(0),
714                     JValue::Int(0),
715                 ],
716             )
717             .map_err(|e| {
718                 error!("UCI JNI: measurement object creation failed: {:?}", e);
719                 e
720             })?;
721 
722         let measurements_jobjectarray = self.env.new_object_array(
723             measurement_count,
724             measurement_jclass,
725             zero_initiated_measurement_jobject,
726         )?;
727         for (i, measurement) in measurements.into_iter().enumerate() {
728             // cast to i8 as java do not support unsigned:
729             let mac_address_i8 = measurement
730                 .mac_address
731                 .into_ne_bytes()
732                 .iter()
733                 .map(|b| b.to_owned() as i8)
734                 .collect::<Vec<_>>();
735             let mac_address_jbytearray = self.env.new_byte_array(mac_address_i8.len() as i32)?;
736             self.env.set_byte_array_region(mac_address_jbytearray, 0, &mac_address_i8)?;
737             // casting as i32 is fine since it is wider than actual integer type.
738 
739             // Safety: mac_address_jbytearray is safely instantiated above.
740             let mac_address_jobject = unsafe { JObject::from_raw(mac_address_jbytearray) };
741             let measurement_jobject = self
742                 .env
743                 .new_object(
744                     measurement_jclass,
745                     "([BIIIIIIIIIIIII)V",
746                     &[
747                         JValue::Object(mac_address_jobject),
748                         JValue::Int(i32::from(measurement.status)),
749                         JValue::Int(measurement.nlos as i32),
750                         JValue::Int(measurement.distance as i32),
751                         JValue::Int(measurement.aoa_azimuth as i32),
752                         JValue::Int(measurement.aoa_azimuth_fom as i32),
753                         JValue::Int(measurement.aoa_elevation as i32),
754                         JValue::Int(measurement.aoa_elevation_fom as i32),
755                         JValue::Int(measurement.aoa_destination_azimuth as i32),
756                         JValue::Int(measurement.aoa_destination_azimuth_fom as i32),
757                         JValue::Int(measurement.aoa_destination_elevation as i32),
758                         JValue::Int(measurement.aoa_destination_elevation_fom as i32),
759                         JValue::Int(measurement.slot_index as i32),
760                         JValue::Int(measurement.rssi as i32),
761                     ],
762                 )
763                 .map_err(|e| {
764                     error!("UCI JNI: measurement object creation failed: {:?}", e);
765                     e
766                 })?;
767             self.env
768                 .set_object_array_element(measurements_jobjectarray, i as i32, measurement_jobject)
769                 .map_err(|e| {
770                     error!("UCI JNI: measurement object copy failed: {:?}", e);
771                     e
772                 })?;
773         }
774 
775         Ok(measurements_jobjectarray)
776     }
777 
on_session_owr_aoa_range_data_notification( &mut self, range_data: SessionRangeData, ) -> Result<JObject, JNIError>778     fn on_session_owr_aoa_range_data_notification(
779         &mut self,
780         range_data: SessionRangeData,
781     ) -> Result<JObject, JNIError> {
782         if range_data.ranging_measurement_type != RangingMeasurementType::OwrAoa {
783             return Err(JNIError::InvalidCtorReturn);
784         }
785 
786         let raw_notification_jbytearray =
787             self.env.byte_array_from_slice(&range_data.raw_ranging_data)?;
788 
789         let (mac_indicator, measurement): (MacAddressIndicator, OwrAoaRangingMeasurement) =
790             match range_data.ranging_measurements {
791                 RangingMeasurements::ExtendedAddressOwrAoa(m) => {
792                     (MacAddressIndicator::ExtendedAddress, m.into())
793                 }
794                 RangingMeasurements::ShortAddressOwrAoa(m) => {
795                     (MacAddressIndicator::ShortAddress, m.into())
796                 }
797                 _ => {
798                     return Err(JNIError::InvalidCtorReturn);
799                 }
800             };
801 
802         // cast to i8 as java do not support unsigned.
803         let mac_address_i8 = measurement
804             .mac_address
805             .into_ne_bytes()
806             .iter()
807             .map(|b| b.to_owned() as i8)
808             .collect::<Vec<_>>();
809         // casting as i32 is fine since it is wider than actual integer type.
810         let mac_address_jbytearray = self.env.new_byte_array(mac_address_i8.len() as i32)?;
811         self.env.set_byte_array_region(mac_address_jbytearray, 0, &mac_address_i8)?;
812         // Safety: mac_address_jbytearray is safely instantiated above.
813         let mac_address_jobject = unsafe { JObject::from_raw(mac_address_jbytearray) };
814 
815         let measurement_jclass = NotificationManagerAndroid::find_local_class(
816             &mut self.jclass_map,
817             &self.class_loader_obj,
818             &self.env,
819             UWB_OWR_AOA_MEASUREMENT_CLASS,
820         )?;
821         let measurement_jobject = self
822             .env
823             .new_object(
824                 measurement_jclass,
825                 "([BIIIIIIII)V",
826                 &[
827                     JValue::Object(mac_address_jobject),
828                     JValue::Int(i32::from(measurement.status)),
829                     JValue::Int(measurement.nlos as i32),
830                     JValue::Int(measurement.frame_sequence_number as i32),
831                     JValue::Int(measurement.block_index as i32),
832                     JValue::Int(measurement.aoa_azimuth as i32),
833                     JValue::Int(measurement.aoa_azimuth_fom as i32),
834                     JValue::Int(measurement.aoa_elevation as i32),
835                     JValue::Int(measurement.aoa_elevation_fom as i32),
836                 ],
837             )
838             .map_err(|e| {
839                 error!("UCI JNI: OwrAoA measurement jobject creation failed: {:?}", e);
840                 e
841             })?;
842 
843         // Create UwbRangingData
844         let ranging_data_jclass = NotificationManagerAndroid::find_local_class(
845             &mut self.jclass_map,
846             &self.class_loader_obj,
847             &self.env,
848             UWB_RANGING_DATA_CLASS,
849         )?;
850         let method_sig = "(JJIJIIIL".to_owned() + UWB_OWR_AOA_MEASUREMENT_CLASS + ";[B)V";
851 
852         // Safety: raw_notification_jobject is safely instantiated above.
853         let raw_notification_jobject = unsafe { JObject::from_raw(raw_notification_jbytearray) };
854 
855         let range_data_jobject = self
856             .env
857             .new_object(
858                 ranging_data_jclass,
859                 &method_sig,
860                 &[
861                     JValue::Long(range_data.sequence_number as i64),
862                     // session_token below has already been mapped to session_id by uci layer.
863                     JValue::Long(range_data.session_token as i64),
864                     JValue::Int(range_data.rcr_indicator as i32),
865                     JValue::Long(range_data.current_ranging_interval_ms as i64),
866                     JValue::Int(range_data.ranging_measurement_type as i32),
867                     JValue::Int(mac_indicator as i32),
868                     JValue::Int(1), // measurement_count
869                     JValue::Object(measurement_jobject),
870                     JValue::Object(raw_notification_jobject),
871                 ],
872             )
873             .map_err(|e| {
874                 error!("UCI JNI: Ranging Data object creation failed: {:?}", e);
875                 e
876             })?;
877         let method_sig = "(L".to_owned() + UWB_RANGING_DATA_CLASS + ";)V";
878         self.cached_jni_call(
879             "onRangeDataNotificationReceived",
880             &method_sig,
881             &[jvalue::from(JValue::Object(range_data_jobject))],
882         )
883     }
884 
on_session_two_way_range_data_notification( &mut self, range_data: SessionRangeData, ) -> Result<JObject, JNIError>885     fn on_session_two_way_range_data_notification(
886         &mut self,
887         range_data: SessionRangeData,
888     ) -> Result<JObject, JNIError> {
889         let raw_notification_jbytearray =
890             self.env.byte_array_from_slice(&range_data.raw_ranging_data)?;
891 
892         let (bytearray_len, mac_indicator) = match &range_data.ranging_measurements {
893             RangingMeasurements::ExtendedAddressTwoWay(_) => {
894                 (EXTENDED_MAC_ADDRESS_LEN, MacAddressIndicator::ExtendedAddress)
895             }
896             RangingMeasurements::ShortAddressTwoWay(_) => {
897                 (SHORT_MAC_ADDRESS_LEN, MacAddressIndicator::ShortAddress)
898             }
899             _ => {
900                 return Err(JNIError::InvalidCtorReturn);
901             }
902         };
903 
904         let measurement_count: i32 = match &range_data.ranging_measurements {
905             RangingMeasurements::ShortAddressTwoWay(v) => v.len().try_into(),
906             RangingMeasurements::ExtendedAddressTwoWay(v) => v.len().try_into(),
907             _ => {
908                 return Err(JNIError::InvalidCtorReturn);
909             }
910         }
911         .map_err(|_| JNIError::InvalidCtorReturn)?;
912 
913         let measurements_jobjectarray = match range_data.ranging_measurement_type {
914             RangingMeasurementType::TwoWay => {
915                 let measurements = match range_data.ranging_measurements {
916                     RangingMeasurements::ExtendedAddressTwoWay(v) => {
917                         v.into_iter().map(TwoWayRangingMeasurement::from).collect::<Vec<_>>()
918                     }
919                     RangingMeasurements::ShortAddressTwoWay(v) => {
920                         v.into_iter().map(TwoWayRangingMeasurement::from).collect::<Vec<_>>()
921                     }
922                     _ => return Err(JNIError::InvalidCtorReturn),
923                 };
924                 self.on_two_way_range_data_notification(
925                     bytearray_len,
926                     measurement_count,
927                     measurements,
928                 )?
929             }
930             _ => {
931                 return Err(JNIError::InvalidCtorReturn);
932             }
933         };
934 
935         // Create UwbRangingData
936         let ranging_data_jclass = NotificationManagerAndroid::find_local_class(
937             &mut self.jclass_map,
938             &self.class_loader_obj,
939             &self.env,
940             UWB_RANGING_DATA_CLASS,
941         )?;
942         let method_sig = "(JJIJIII[L".to_owned() + UWB_TWO_WAY_MEASUREMENT_CLASS + ";[B)V";
943 
944         // Safety: measurements_jobjectarray is safely instantiated above.
945         let measurements_jobject = unsafe { JObject::from_raw(measurements_jobjectarray) };
946         // Safety: raw_notification_jobject is safely instantiated above.
947         let raw_notification_jobject = unsafe { JObject::from_raw(raw_notification_jbytearray) };
948         let range_data_jobject = self
949             .env
950             .new_object(
951                 ranging_data_jclass,
952                 &method_sig,
953                 &[
954                     JValue::Long(range_data.sequence_number as i64),
955                     // session_token below has already been mapped to session_id by uci layer.
956                     JValue::Long(range_data.session_token as i64),
957                     JValue::Int(range_data.rcr_indicator as i32),
958                     JValue::Long(range_data.current_ranging_interval_ms as i64),
959                     JValue::Int(range_data.ranging_measurement_type as i32),
960                     JValue::Int(mac_indicator as i32),
961                     JValue::Int(measurement_count),
962                     JValue::Object(measurements_jobject),
963                     JValue::Object(raw_notification_jobject),
964                 ],
965             )
966             .map_err(|e| {
967                 error!("UCI JNI: Ranging Data object creation failed: {:?}", e);
968                 e
969             })?;
970         let method_sig = "(L".to_owned() + UWB_RANGING_DATA_CLASS + ";)V";
971         self.cached_jni_call(
972             "onRangeDataNotificationReceived",
973             &method_sig,
974             &[jvalue::from(JValue::Object(range_data_jobject))],
975         )
976     }
977 
on_data_transfer_status_notification( &mut self, session_id: u32, uci_sequence_number: u16, status_code: u8, tx_count: u8, ) -> Result<JObject, JNIError>978     fn on_data_transfer_status_notification(
979         &mut self,
980         session_id: u32,
981         uci_sequence_number: u16,
982         status_code: u8,
983         tx_count: u8,
984     ) -> Result<JObject, JNIError> {
985         self.cached_jni_call(
986             "onDataSendStatus",
987             "(JIJI)V",
988             &[
989                 jvalue::from(JValue::Long(session_id as i64)),
990                 jvalue::from(JValue::Int(status_code as i32)),
991                 jvalue::from(JValue::Long(uci_sequence_number as i64)),
992                 jvalue::from(JValue::Int(tx_count as i32)),
993             ],
994         )
995     }
996 
on_data_transfer_phase_config_notification( &mut self, session_id: u32, status_code: u8, ) -> Result<JObject, JNIError>997     fn on_data_transfer_phase_config_notification(
998         &mut self,
999         session_id: u32,
1000         status_code: u8,
1001     ) -> Result<JObject, JNIError> {
1002         self.cached_jni_call(
1003             "onDataTransferPhaseConfigNotificationReceived",
1004             "(JI)V",
1005             &[
1006                 jvalue::from(JValue::Long(session_id as i64)),
1007                 jvalue::from(JValue::Int(status_code as i32)),
1008             ],
1009         )
1010     }
1011 }
1012 
1013 impl NotificationManager for NotificationManagerAndroid {
on_core_notification(&mut self, core_notification: CoreNotification) -> UwbResult<()>1014     fn on_core_notification(&mut self, core_notification: CoreNotification) -> UwbResult<()> {
1015         debug!("UCI JNI: core notification callback.");
1016         let env = *self.env;
1017         env.with_local_frame(MAX_JAVA_OBJECTS_CAPACITY, || {
1018             let env_chip_id_jobject = *env.new_string(&self.chip_id).map_err(|e| {
1019                 error!("UCI JNI: failed to create Java String: {e:?}");
1020                 e
1021             })?;
1022 
1023             match core_notification {
1024                 CoreNotification::DeviceStatus(device_state) => self.cached_jni_call(
1025                     "onDeviceStatusNotificationReceived",
1026                     "(ILjava/lang/String;)V",
1027                     &[
1028                         jvalue::from(JValue::Int(device_state as i32)),
1029                         jvalue::from(JValue::Object(env_chip_id_jobject)),
1030                     ],
1031                 ),
1032                 CoreNotification::GenericError(generic_error) => self.cached_jni_call(
1033                     "onCoreGenericErrorNotificationReceived",
1034                     "(ILjava/lang/String;)V",
1035                     &[
1036                         jvalue::from(JValue::Int(i32::from(generic_error))),
1037                         jvalue::from(JValue::Object(env_chip_id_jobject)),
1038                     ],
1039                 ),
1040             }
1041         })
1042         .map_err(|_| UwbError::ForeignFunctionInterface)?;
1043 
1044         Ok(())
1045     }
1046 
on_session_notification( &mut self, session_notification: SessionNotification, ) -> UwbResult<()>1047     fn on_session_notification(
1048         &mut self,
1049         session_notification: SessionNotification,
1050     ) -> UwbResult<()> {
1051         debug!("UCI JNI: session notification callback.");
1052         let env = *self.env;
1053         env.with_local_frame(MAX_JAVA_OBJECTS_CAPACITY, || {
1054             match session_notification {
1055                 SessionNotification::Status {
1056                     session_id,
1057                     session_token,
1058                     session_state,
1059                     reason_code,
1060                 } => self.on_session_status_notification(
1061                     session_id,
1062                     session_token,
1063                     session_state,
1064                     reason_code,
1065                 ),
1066                 SessionNotification::UpdateControllerMulticastListV1 {
1067                     session_token,
1068                     remaining_multicast_list_size,
1069                     status_list,
1070                 } => self.on_session_update_multicast_notification(
1071                     session_token,
1072                     remaining_multicast_list_size,
1073                     ControleeStatusList::V1(status_list),
1074                 ),
1075                 SessionNotification::UpdateControllerMulticastListV2 {
1076                     session_token,
1077                     status_list,
1078                 } => self.on_session_update_multicast_notification(
1079                     session_token,
1080                     0_usize,
1081                     ControleeStatusList::V2(status_list),
1082                 ),
1083                 // TODO(b/246678053): Match here on range_data.ranging_measurement_type instead.
1084                 SessionNotification::SessionInfo(range_data) => {
1085                     match range_data.ranging_measurements {
1086                         uwb_core::uci::RangingMeasurements::ShortAddressTwoWay(_) => {
1087                             self.on_session_two_way_range_data_notification(range_data)
1088                         }
1089                         uwb_core::uci::RangingMeasurements::ExtendedAddressTwoWay(_) => {
1090                             self.on_session_two_way_range_data_notification(range_data)
1091                         }
1092                         uwb_core::uci::RangingMeasurements::ShortAddressOwrAoa(_) => {
1093                             self.on_session_owr_aoa_range_data_notification(range_data)
1094                         }
1095                         uwb_core::uci::RangingMeasurements::ExtendedAddressOwrAoa(_) => {
1096                             self.on_session_owr_aoa_range_data_notification(range_data)
1097                         }
1098                         uwb_core::uci::RangingMeasurements::ShortAddressDltdoa(_) => {
1099                             self.on_session_dl_tdoa_range_data_notification(range_data)
1100                         }
1101                         uwb_core::uci::RangingMeasurements::ExtendedAddressDltdoa(_) => {
1102                             self.on_session_dl_tdoa_range_data_notification(range_data)
1103                         }
1104                     }
1105                 }
1106                 SessionNotification::DataTransferStatus {
1107                     session_token,
1108                     uci_sequence_number,
1109                     status,
1110                     tx_count,
1111                 } => self.on_data_transfer_status_notification(
1112                     session_token,
1113                     uci_sequence_number,
1114                     u8::from(status),
1115                     tx_count,
1116                 ),
1117                 // This session notification should not come here, as it's handled within
1118                 // UciManager, for internal state management related to sending data packet(s).
1119                 SessionNotification::DataCredit { session_token, credit_availability } => {
1120                     error!(
1121                         "UCI JNI: Received unexpected DataCredit notification for \
1122                             session_token {}, credit_availability {:?}",
1123                         session_token, credit_availability
1124                     );
1125                     Err(JNIError::InvalidCtorReturn)
1126                 }
1127                 SessionNotification::DataTransferPhaseConfig { session_token, status } => {
1128                     self.on_data_transfer_phase_config_notification(session_token, u8::from(status))
1129                 }
1130             }
1131         })
1132         .map_err(|_| UwbError::ForeignFunctionInterface)?;
1133         Ok(())
1134     }
1135 
on_vendor_notification( &mut self, vendor_notification: uwb_core::params::RawUciMessage, ) -> UwbResult<()>1136     fn on_vendor_notification(
1137         &mut self,
1138         vendor_notification: uwb_core::params::RawUciMessage,
1139     ) -> UwbResult<()> {
1140         debug!("UCI JNI: vendor notification callback.");
1141         let env = *self.env;
1142         env.with_local_frame(MAX_JAVA_OBJECTS_CAPACITY, || {
1143             let payload_jbytearray =
1144                 self.env.byte_array_from_slice(&vendor_notification.payload)?;
1145 
1146             // Safety: payload_jbytearray safely instantiated above.
1147             let payload_jobject = unsafe { JObject::from_raw(payload_jbytearray) };
1148             self.cached_jni_call(
1149                 "onVendorUciNotificationReceived",
1150                 "(II[B)V",
1151                 &[
1152                     // Java only has signed integer. The range for signed int32 should be sufficient.
1153                     jvalue::from(JValue::Int(
1154                         vendor_notification
1155                             .gid
1156                             .try_into()
1157                             .map_err(|_| JNIError::InvalidCtorReturn)?,
1158                     )),
1159                     jvalue::from(JValue::Int(
1160                         vendor_notification
1161                             .oid
1162                             .try_into()
1163                             .map_err(|_| JNIError::InvalidCtorReturn)?,
1164                     )),
1165                     jvalue::from(JValue::Object(payload_jobject)),
1166                 ],
1167             )
1168         })
1169         .map_err(|_| UwbError::ForeignFunctionInterface)?;
1170         Ok(())
1171     }
1172 
on_data_rcv_notification( &mut self, data_rcv_notification: DataRcvNotification, ) -> UwbResult<()>1173     fn on_data_rcv_notification(
1174         &mut self,
1175         data_rcv_notification: DataRcvNotification,
1176     ) -> UwbResult<()> {
1177         debug!("UCI JNI: Data Rcv notification callback.");
1178         let env = *self.env;
1179         env.with_local_frame(MAX_JAVA_OBJECTS_CAPACITY, || {
1180             let source_address_jbytearray = match &data_rcv_notification.source_address {
1181                 UwbAddress::Short(a) => self.env.byte_array_from_slice(a)?,
1182                 UwbAddress::Extended(a) => self.env.byte_array_from_slice(a)?,
1183             };
1184             let payload_jbytearray =
1185                 self.env.byte_array_from_slice(&data_rcv_notification.payload)?;
1186             // Safety: source_address_jbytearray safely instantiated above.
1187             let source_address_jobject = unsafe { JObject::from_raw(source_address_jbytearray) };
1188             // Safety: payload_jbytearray safely instantiated above.
1189             let payload_jobject = unsafe { JObject::from_raw(payload_jbytearray) };
1190             self.cached_jni_call(
1191                 "onDataReceived",
1192                 "(JIJ[B[B)V",
1193                 &[
1194                     // session_token below has already been mapped to session_id by uci layer.
1195                     jvalue::from(JValue::Long(data_rcv_notification.session_token as i64)),
1196                     jvalue::from(JValue::Int(i32::from(data_rcv_notification.status))),
1197                     jvalue::from(JValue::Long(data_rcv_notification.uci_sequence_num as i64)),
1198                     jvalue::from(JValue::Object(source_address_jobject)),
1199                     jvalue::from(JValue::Object(payload_jobject)),
1200                 ],
1201             )
1202         })
1203         .map_err(|_| UwbError::ForeignFunctionInterface)?;
1204         Ok(())
1205     }
1206 
on_radar_data_rcv_notification( &mut self, radar_data_rcv_notification: RadarDataRcvNotification, ) -> UwbResult<()>1207     fn on_radar_data_rcv_notification(
1208         &mut self,
1209         radar_data_rcv_notification: RadarDataRcvNotification,
1210     ) -> UwbResult<()> {
1211         debug!("UCI JNI: Radar Data Rcv notification callback.");
1212         let env = *self.env;
1213         env.with_local_frame(MAX_JAVA_OBJECTS_CAPACITY, || {
1214             let radar_sweep_data_jclass = NotificationManagerAndroid::find_local_class(
1215                 &mut self.jclass_map,
1216                 &self.class_loader_obj,
1217                 &self.env,
1218                 UWB_RADAR_SWEEP_DATA_CLASS,
1219             )?;
1220 
1221             let max_sample_data_length =
1222                 radar_bytes_per_sample_value(radar_data_rcv_notification.bits_per_sample) as i32
1223                     * radar_data_rcv_notification.samples_per_sweep as i32;
1224             let sample_data_jbytearray = self.env.new_byte_array(max_sample_data_length)?;
1225             let vendor_data_jbytearray = self.env.new_byte_array(MAX_RADAR_VENDOR_DATA_LEN)?;
1226 
1227             // Safety: sample_data_jbytearray is safely instantiated above.
1228             let sample_data_jobject = unsafe { JObject::from_raw(sample_data_jbytearray) };
1229             // Safety: vendor_data_jbytearray is safely instantiated above.
1230             let vendor_data_jobject = unsafe { JObject::from_raw(vendor_data_jbytearray) };
1231 
1232             let sweep_data_sig: &str = "(JJ[B[B)V";
1233 
1234             let zero_initiated_sweep_data = self
1235                 .env
1236                 .new_object(
1237                     radar_sweep_data_jclass,
1238                     sweep_data_sig,
1239                     &[
1240                         JValue::Long(0),
1241                         JValue::Long(0),
1242                         JValue::Object(vendor_data_jobject),
1243                         JValue::Object(sample_data_jobject),
1244                     ],
1245                 )
1246                 .map_err(|e| {
1247                     error!(
1248                         "UCI JNI: zero initiated RadarSweepData object creation failed: {:?}",
1249                         e
1250                     );
1251                     e
1252                 })?;
1253 
1254             let radar_sweep_data_jobjectarray = self
1255                 .env
1256                 .new_object_array(
1257                     radar_data_rcv_notification.sweep_data.len() as i32,
1258                     radar_sweep_data_jclass,
1259                     zero_initiated_sweep_data,
1260                 )
1261                 .map_err(|e| {
1262                     error!("UCI JNI: RadarSweepData object array creation failed: {:?}", e);
1263                     e
1264                 })?;
1265 
1266             for (i, sweep_data) in radar_data_rcv_notification.sweep_data.into_iter().enumerate() {
1267                 let vendor_data_jbytearray =
1268                     self.env.byte_array_from_slice(&sweep_data.vendor_specific_data)?;
1269                 let sample_data_jbytearray =
1270                     self.env.byte_array_from_slice(&sweep_data.sample_data)?;
1271                 // Safety: vendor_data_jbytearray instantiated above
1272                 let vendor_data_jobject = unsafe { JObject::from_raw(vendor_data_jbytearray) };
1273                 // Safety: sample_data_jbytearray instantiated above
1274                 let sample_data_jobject = unsafe { JObject::from_raw(sample_data_jbytearray) };
1275                 let sweep_data_jobject = self
1276                     .env
1277                     .new_object(
1278                         radar_sweep_data_jclass,
1279                         sweep_data_sig,
1280                         &[
1281                             JValue::Long(sweep_data.sequence_number as i64),
1282                             JValue::Long(sweep_data.timestamp as i64),
1283                             JValue::Object(vendor_data_jobject),
1284                             JValue::Object(sample_data_jobject),
1285                         ],
1286                     )
1287                     .map_err(|e| {
1288                         error!("UCI JNI: RadarSweepData object creation failed: {:?}", e);
1289                         e
1290                     })?;
1291 
1292                 self.env
1293                     .set_object_array_element(
1294                         radar_sweep_data_jobjectarray,
1295                         i as i32,
1296                         sweep_data_jobject,
1297                     )
1298                     .map_err(|e| {
1299                         error!(
1300                             "UCI JNI: sweep_data_jobject copy into jobjectarray failed: {:?}",
1301                             e
1302                         );
1303                         e
1304                     })?;
1305             }
1306 
1307             let radar_sweep_data_array_jobject =
1308                 // Safety: radar_sweep_data_jobjectarray is safely instantiated above.
1309                 unsafe { JObject::from_raw(radar_sweep_data_jobjectarray) };
1310 
1311             let radar_data_jclass = NotificationManagerAndroid::find_local_class(
1312                 &mut self.jclass_map,
1313                 &self.class_loader_obj,
1314                 &self.env,
1315                 UWB_RADAR_DATA_CLASS,
1316             )?;
1317 
1318             let radar_data_jobject = self
1319                 .env
1320                 .new_object(
1321                     radar_data_jclass,
1322                     "(JIIIII[L".to_owned() + UWB_RADAR_SWEEP_DATA_CLASS + ";)V",
1323                     &[
1324                         // session_token below has already been mapped to session_id by uci layer.
1325                         JValue::Long(radar_data_rcv_notification.session_token as i64),
1326                         JValue::Int(radar_data_rcv_notification.status as i32),
1327                         JValue::Int(radar_data_rcv_notification.radar_data_type as i32),
1328                         JValue::Int(radar_data_rcv_notification.samples_per_sweep as i32),
1329                         JValue::Int(radar_data_rcv_notification.bits_per_sample as i32),
1330                         JValue::Int(radar_data_rcv_notification.sweep_offset as i32),
1331                         JValue::Object(radar_sweep_data_array_jobject),
1332                     ],
1333                 )
1334                 .map_err(|e| {
1335                     error!("UCI JNI: UwbRadarData object creation failed: {:?}", e);
1336                     e
1337                 })?;
1338 
1339             let method_sig = "(L".to_owned() + UWB_RADAR_DATA_CLASS + ";)V";
1340 
1341             self.cached_jni_call(
1342                 "onRadarDataMessageReceived",
1343                 &method_sig,
1344                 &[jvalue::from(JValue::Object(radar_data_jobject))],
1345             )
1346         })
1347         .map_err(|_| UwbError::ForeignFunctionInterface)?;
1348         Ok(())
1349     }
1350 }
1351 pub(crate) struct NotificationManagerAndroidBuilder {
1352     pub chip_id: String,
1353     pub vm: &'static Arc<JavaVM>,
1354     pub class_loader_obj: GlobalRef,
1355     pub callback_obj: GlobalRef,
1356 }
1357 
1358 impl NotificationManagerBuilder for NotificationManagerAndroidBuilder {
1359     type NotificationManager = NotificationManagerAndroid;
1360 
build(self) -> Option<Self::NotificationManager>1361     fn build(self) -> Option<Self::NotificationManager> {
1362         if let Ok(env) = self.vm.attach_current_thread() {
1363             Some(NotificationManagerAndroid {
1364                 chip_id: self.chip_id,
1365                 env,
1366                 class_loader_obj: self.class_loader_obj,
1367                 callback_obj: self.callback_obj,
1368                 jmethod_id_map: HashMap::new(),
1369                 jclass_map: HashMap::new(),
1370             })
1371         } else {
1372             None
1373         }
1374     }
1375 }
1376 
1377 #[cfg(test)]
1378 mod tests {
1379     use super::*;
1380 
1381     #[test]
test_get_two_way_ranigng_measurement_from_short_address_two_way_ranging_measurement()1382     fn test_get_two_way_ranigng_measurement_from_short_address_two_way_ranging_measurement() {
1383         let short_address_measurement = ShortAddressTwoWayRangingMeasurement {
1384             mac_address: 0x1234,
1385             status: StatusCode::UciStatusOk,
1386             nlos: 0,
1387             distance: 1,
1388             aoa_azimuth: 2,
1389             aoa_azimuth_fom: 3,
1390             aoa_elevation: 4,
1391             aoa_elevation_fom: 5,
1392             aoa_destination_azimuth: 6,
1393             aoa_destination_azimuth_fom: 7,
1394             aoa_destination_elevation: 8,
1395             aoa_destination_elevation_fom: 9,
1396             slot_index: 10,
1397             rssi: 11,
1398         };
1399         let measurement = TwoWayRangingMeasurement::from(short_address_measurement.clone());
1400         assert_eq!(
1401             measurement.mac_address,
1402             MacAddress::Short(short_address_measurement.mac_address)
1403         );
1404         assert_eq!(measurement.status, short_address_measurement.status);
1405         assert_eq!(measurement.nlos, short_address_measurement.nlos);
1406         assert_eq!(measurement.distance, short_address_measurement.distance);
1407         assert_eq!(measurement.aoa_azimuth, short_address_measurement.aoa_azimuth);
1408         assert_eq!(measurement.aoa_azimuth_fom, short_address_measurement.aoa_azimuth_fom);
1409         assert_eq!(measurement.aoa_elevation, short_address_measurement.aoa_elevation);
1410         assert_eq!(measurement.aoa_elevation_fom, short_address_measurement.aoa_elevation_fom);
1411         assert_eq!(
1412             measurement.aoa_destination_azimuth,
1413             short_address_measurement.aoa_destination_azimuth
1414         );
1415         assert_eq!(
1416             measurement.aoa_destination_azimuth_fom,
1417             short_address_measurement.aoa_destination_azimuth_fom
1418         );
1419         assert_eq!(
1420             measurement.aoa_destination_elevation,
1421             short_address_measurement.aoa_destination_elevation
1422         );
1423         assert_eq!(
1424             measurement.aoa_destination_elevation_fom,
1425             short_address_measurement.aoa_destination_elevation_fom
1426         );
1427         assert_eq!(measurement.slot_index, short_address_measurement.slot_index);
1428         assert_eq!(measurement.rssi, short_address_measurement.rssi);
1429     }
1430 
1431     #[test]
test_get_two_way_ranigng_measurement_from_extended_address_two_way_ranging_measurement()1432     fn test_get_two_way_ranigng_measurement_from_extended_address_two_way_ranging_measurement() {
1433         let extended_address_measurement = ExtendedAddressTwoWayRangingMeasurement {
1434             mac_address: 0x1234_5678,
1435             status: StatusCode::UciStatusOk,
1436             nlos: 0,
1437             distance: 1,
1438             aoa_azimuth: 2,
1439             aoa_azimuth_fom: 3,
1440             aoa_elevation: 4,
1441             aoa_elevation_fom: 5,
1442             aoa_destination_azimuth: 6,
1443             aoa_destination_azimuth_fom: 7,
1444             aoa_destination_elevation: 8,
1445             aoa_destination_elevation_fom: 9,
1446             slot_index: 10,
1447             rssi: 11,
1448         };
1449         let measurement = TwoWayRangingMeasurement::from(extended_address_measurement.clone());
1450         assert_eq!(
1451             measurement.mac_address,
1452             MacAddress::Extended(extended_address_measurement.mac_address)
1453         );
1454         assert_eq!(measurement.status, extended_address_measurement.status);
1455         assert_eq!(measurement.nlos, extended_address_measurement.nlos);
1456         assert_eq!(measurement.distance, extended_address_measurement.distance);
1457         assert_eq!(measurement.aoa_azimuth, extended_address_measurement.aoa_azimuth);
1458         assert_eq!(measurement.aoa_azimuth_fom, extended_address_measurement.aoa_azimuth_fom);
1459         assert_eq!(measurement.aoa_elevation, extended_address_measurement.aoa_elevation);
1460         assert_eq!(measurement.aoa_elevation_fom, extended_address_measurement.aoa_elevation_fom);
1461         assert_eq!(
1462             measurement.aoa_destination_azimuth,
1463             extended_address_measurement.aoa_destination_azimuth
1464         );
1465         assert_eq!(
1466             measurement.aoa_destination_azimuth_fom,
1467             extended_address_measurement.aoa_destination_azimuth_fom
1468         );
1469         assert_eq!(
1470             measurement.aoa_destination_elevation,
1471             extended_address_measurement.aoa_destination_elevation
1472         );
1473         assert_eq!(
1474             measurement.aoa_destination_elevation_fom,
1475             extended_address_measurement.aoa_destination_elevation_fom
1476         );
1477         assert_eq!(measurement.slot_index, extended_address_measurement.slot_index);
1478         assert_eq!(measurement.rssi, extended_address_measurement.rssi);
1479     }
1480 
1481     #[test]
test_get_owr_aoa_ranging_measurement_from_short_address_measurement()1482     fn test_get_owr_aoa_ranging_measurement_from_short_address_measurement() {
1483         let short_address_measurement = ShortAddressOwrAoaRangingMeasurement {
1484             mac_address: 0x1234,
1485             status: StatusCode::UciStatusOk,
1486             nlos: 0,
1487             frame_sequence_number: 1,
1488             block_index: 2,
1489             aoa_azimuth: 3,
1490             aoa_azimuth_fom: 4,
1491             aoa_elevation: 5,
1492             aoa_elevation_fom: 6,
1493         };
1494         let measurement = OwrAoaRangingMeasurement::from(short_address_measurement.clone());
1495         assert_eq!(
1496             measurement.mac_address,
1497             MacAddress::Short(short_address_measurement.mac_address)
1498         );
1499         assert_eq!(measurement.status, short_address_measurement.status);
1500         assert_eq!(measurement.nlos, short_address_measurement.nlos);
1501         assert_eq!(
1502             measurement.frame_sequence_number,
1503             short_address_measurement.frame_sequence_number
1504         );
1505         assert_eq!(measurement.block_index, short_address_measurement.block_index);
1506         assert_eq!(measurement.aoa_azimuth, short_address_measurement.aoa_azimuth);
1507         assert_eq!(measurement.aoa_azimuth_fom, short_address_measurement.aoa_azimuth_fom);
1508         assert_eq!(measurement.aoa_elevation, short_address_measurement.aoa_elevation);
1509         assert_eq!(measurement.aoa_elevation_fom, short_address_measurement.aoa_elevation_fom);
1510     }
1511 
1512     #[test]
test_get_owr_aoa_ranging_measurement_from_extended_address_measurement()1513     fn test_get_owr_aoa_ranging_measurement_from_extended_address_measurement() {
1514         let extended_address_measurement = ExtendedAddressOwrAoaRangingMeasurement {
1515             mac_address: 0x1234_5678,
1516             status: StatusCode::UciStatusOk,
1517             nlos: 0,
1518             frame_sequence_number: 1,
1519             block_index: 2,
1520             aoa_azimuth: 3,
1521             aoa_azimuth_fom: 4,
1522             aoa_elevation: 5,
1523             aoa_elevation_fom: 6,
1524         };
1525         let measurement = OwrAoaRangingMeasurement::from(extended_address_measurement.clone());
1526         assert_eq!(
1527             measurement.mac_address,
1528             MacAddress::Extended(extended_address_measurement.mac_address)
1529         );
1530         assert_eq!(measurement.status, extended_address_measurement.status);
1531         assert_eq!(measurement.nlos, extended_address_measurement.nlos);
1532         assert_eq!(
1533             measurement.frame_sequence_number,
1534             extended_address_measurement.frame_sequence_number
1535         );
1536         assert_eq!(measurement.block_index, extended_address_measurement.block_index);
1537         assert_eq!(measurement.aoa_azimuth, extended_address_measurement.aoa_azimuth);
1538         assert_eq!(measurement.aoa_azimuth_fom, extended_address_measurement.aoa_azimuth_fom);
1539         assert_eq!(measurement.aoa_elevation, extended_address_measurement.aoa_elevation);
1540         assert_eq!(measurement.aoa_elevation_fom, extended_address_measurement.aoa_elevation_fom);
1541     }
1542 
1543     #[test]
test_get_dl_tdoa_ranging_measurement_from_short_address_measurement()1544     fn test_get_dl_tdoa_ranging_measurement_from_short_address_measurement() {
1545         let bytes = [
1546             // All Fields in Little Endian (LE)
1547             0x0a, 0x01, 0x33, 0x05, // 2(Mac address), Status, Message Type
1548             0x53, 0x05, 0x02, 0x05, // 2(Message control), 2(Block Index)
1549             0x07, 0x09, 0x0a, 0x01, // Round Index, NLoS, 2(AoA Azimuth)
1550             0x02, 0x05, 0x07, 0x09, // AoA Azimuth FOM, 2(AoA Elevation), AoA Elevation FOM
1551             0x0a, 0x01, 0x02, 0x05, // RSSI, 3(Tx Timestamp..)
1552             0x07, 0x09, 0x0a, 0x01, // 4(Tx Timestamp..)
1553             0x02, 0x05, 0x07, 0x09, // Tx Timestamp, 3(Rx Timestamp..)
1554             0x05, 0x07, 0x09, 0x0a, // 2(Rx Timestamp), 2(Anchor Cfo)
1555             0x01, 0x02, 0x05, 0x07, // 2(Cfo), 2(Initiator Reply Time..)
1556             0x09, 0x05, 0x07, 0x09, // 2(Initiator Reply Time), 2(Responder Reply Time..)
1557             0x0a, 0x01, 0x02, 0x05, // 2(Responder Reply Time), 2(Initiator-Responder ToF)
1558             0x07, 0x09, 0x07, 0x09, // 4(Anchor Location..)
1559             0x05, 0x07, 0x09, 0x0a, // 4(Anchor Location..)
1560             0x01, 0x02, 0x05, 0x07, // 2(Anchor Location..), 2(Active Ranging Rounds..)
1561             0x09, 0x0a, 0x01, 0x02, // 4(Active Ranging Rounds..)
1562             0x05, 0x07, 0x09, 0x05, // 4(Active Ranging Rounds)
1563         ];
1564         let short_address_measurement_vec =
1565             ShortAddressDlTdoaRangingMeasurement::parse(&bytes, 1).unwrap();
1566         let short_address_measurement = &short_address_measurement_vec[0];
1567         let measurement = DlTdoaRangingMeasurement::from(short_address_measurement.clone());
1568         assert_eq!(
1569             measurement.mac_address,
1570             MacAddress::Short(short_address_measurement.mac_address)
1571         );
1572         assert_eq!(measurement.status, short_address_measurement.measurement.status);
1573         assert_eq!(measurement.message_type, short_address_measurement.measurement.message_type);
1574         assert_eq!(
1575             measurement.message_control,
1576             short_address_measurement.measurement.message_control
1577         );
1578         assert_eq!(measurement.block_index, short_address_measurement.measurement.block_index);
1579         assert_eq!(measurement.round_index, short_address_measurement.measurement.round_index);
1580         assert_eq!(measurement.nlos, short_address_measurement.measurement.nlos);
1581         assert_eq!(measurement.aoa_azimuth, short_address_measurement.measurement.aoa_azimuth);
1582         assert_eq!(
1583             measurement.aoa_azimuth_fom,
1584             short_address_measurement.measurement.aoa_azimuth_fom
1585         );
1586         assert_eq!(measurement.aoa_elevation, short_address_measurement.measurement.aoa_elevation);
1587         assert_eq!(
1588             measurement.aoa_elevation_fom,
1589             short_address_measurement.measurement.aoa_elevation_fom
1590         );
1591         assert_eq!(measurement.rssi, short_address_measurement.measurement.rssi);
1592         assert_eq!(measurement.tx_timestamp, short_address_measurement.measurement.tx_timestamp);
1593         assert_eq!(measurement.rx_timestamp, short_address_measurement.measurement.rx_timestamp);
1594         assert_eq!(measurement.anchor_cfo, short_address_measurement.measurement.anchor_cfo);
1595         assert_eq!(measurement.cfo, short_address_measurement.measurement.cfo);
1596         assert_eq!(
1597             measurement.initiator_reply_time,
1598             short_address_measurement.measurement.initiator_reply_time
1599         );
1600         assert_eq!(
1601             measurement.responder_reply_time,
1602             short_address_measurement.measurement.responder_reply_time
1603         );
1604         assert_eq!(
1605             measurement.initiator_responder_tof,
1606             short_address_measurement.measurement.initiator_responder_tof
1607         );
1608         assert_eq!(
1609             measurement.dt_anchor_location,
1610             short_address_measurement.measurement.dt_anchor_location
1611         );
1612         assert_eq!(
1613             measurement.ranging_rounds,
1614             short_address_measurement.measurement.ranging_rounds
1615         );
1616     }
1617 
1618     #[test]
test_get_dl_tdoa_ranging_measurement_from_extended_address_measurement()1619     fn test_get_dl_tdoa_ranging_measurement_from_extended_address_measurement() {
1620         let bytes = [
1621             // All Fields in Little Endian (LE)
1622             0x0a, 0x01, 0x33, 0x05, // 4(Mac address..)
1623             0x33, 0x05, 0x02, 0x05, // 4(Mac address)
1624             0x07, 0x09, 0x0a, 0x01, // Status, Message Type, 2(Message control),
1625             0x02, 0x05, 0x07, 0x09, // 2(Block Index), Round Index, NLoS,
1626             0x0a, 0x01, 0x02, 0x05, // 2(AoA Azimuth), AoA Azimuth FOM, 1(AoA Elevation..)
1627             0x07, 0x09, 0x0a, // 1(AoA Elevation), AoA Elevation FOM, RSSI,
1628             0x01, 0x02, 0x05, 0x07, // 4(Tx Timestamp..)
1629             0x09, 0x05, 0x07, 0x09, // 4(Tx Timestamp),
1630             0x0a, 0x01, 0x02, 0x05, // 4(Rx Timestamp..)
1631             0x07, 0x09, 0x05, 0x07, // 4(Rx Timestamp)
1632             0x09, 0x0a, 0x01, 0x02, // 2(Anchor Cfo), 2(Cfo),
1633             0x05, 0x07, 0x09, 0x05, // 4(Initiator Reply Time)
1634             0x07, 0x09, 0x0a, 0x01, // 4(Responder Reply Time),
1635             0x02, 0x05, 0x02, 0x05, // 2(Initiator-Responder ToF), 2(Active Ranging Rounds)
1636         ];
1637         let extended_address_measurement_vec =
1638             ExtendedAddressDlTdoaRangingMeasurement::parse(&bytes, 1).unwrap();
1639         let extended_address_measurement = &extended_address_measurement_vec[0];
1640 
1641         let measurement = DlTdoaRangingMeasurement::from(extended_address_measurement.clone());
1642         assert_eq!(
1643             measurement.mac_address,
1644             MacAddress::Extended(extended_address_measurement.mac_address)
1645         );
1646         assert_eq!(measurement.status, extended_address_measurement.measurement.status);
1647         assert_eq!(measurement.message_type, extended_address_measurement.measurement.message_type);
1648         assert_eq!(
1649             measurement.message_control,
1650             extended_address_measurement.measurement.message_control
1651         );
1652         assert_eq!(measurement.block_index, extended_address_measurement.measurement.block_index);
1653         assert_eq!(measurement.round_index, extended_address_measurement.measurement.round_index);
1654         assert_eq!(measurement.nlos, extended_address_measurement.measurement.nlos);
1655         assert_eq!(measurement.aoa_azimuth, extended_address_measurement.measurement.aoa_azimuth);
1656         assert_eq!(
1657             measurement.aoa_azimuth_fom,
1658             extended_address_measurement.measurement.aoa_azimuth_fom
1659         );
1660         assert_eq!(
1661             measurement.aoa_elevation,
1662             extended_address_measurement.measurement.aoa_elevation
1663         );
1664         assert_eq!(
1665             measurement.aoa_elevation_fom,
1666             extended_address_measurement.measurement.aoa_elevation_fom
1667         );
1668         assert_eq!(measurement.rssi, extended_address_measurement.measurement.rssi);
1669         assert_eq!(measurement.tx_timestamp, extended_address_measurement.measurement.tx_timestamp);
1670         assert_eq!(measurement.rx_timestamp, extended_address_measurement.measurement.rx_timestamp);
1671         assert_eq!(measurement.anchor_cfo, extended_address_measurement.measurement.anchor_cfo);
1672         assert_eq!(measurement.cfo, extended_address_measurement.measurement.cfo);
1673         assert_eq!(
1674             measurement.initiator_reply_time,
1675             extended_address_measurement.measurement.initiator_reply_time
1676         );
1677         assert_eq!(
1678             measurement.responder_reply_time,
1679             extended_address_measurement.measurement.responder_reply_time
1680         );
1681         assert_eq!(
1682             measurement.initiator_responder_tof,
1683             extended_address_measurement.measurement.initiator_responder_tof
1684         );
1685         assert_eq!(
1686             measurement.dt_anchor_location,
1687             extended_address_measurement.measurement.dt_anchor_location
1688         );
1689         assert_eq!(
1690             measurement.ranging_rounds,
1691             extended_address_measurement.measurement.ranging_rounds
1692         );
1693     }
1694 }
1695