summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-05-10 16:24:34 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-05-10 16:24:34 +0000
commit8bdc95edf6ec07c35b8c8c46cb54fc215652260e (patch)
treeddd7c6ac6629c209a0e02f18a213cc0b0753b0be
parent6a0b33a9662237b8982002992196642bc603c2d4 (diff)
parent1a86b7006f9919c1bdeeb128ee773f5b8e21c59d (diff)
downloaduwb-android13-mainline-tzdata4-release.tar.gz
Snap for 10102166 from 1a86b7006f9919c1bdeeb128ee773f5b8e21c59d to mainline-tzdata4-releaseaml_tz4_332714070aml_tz4_332714050aml_tz4_332714010aml_tz4_331910000android13-mainline-tzdata4-releaseaml_tz4_332714010
Change-Id: Iced10414419407f626e6976505cb349aa43630d7
-rwxr-xr-xsrc/Android.bp285
-rw-r--r--src/TEST_MAPPING3
-rw-r--r--src/fuzz/fuzzer.rs618
-rwxr-xr-xsrc/gki/common/uwb_gki.h6
-rwxr-xr-xsrc/gki/common/uwb_gki_buffer.cc2
-rwxr-xr-xsrc/gki/ulinux/uwb_gki_ulinux.cc4
-rwxr-xr-xsrc/include/uwb_hal_int.h4
-rwxr-xr-xsrc/include/uwb_types.h8
-rw-r--r--src/rust/adaptation/mock_adaptation.rs293
-rw-r--r--src/rust/adaptation/mock_hal.rs260
-rw-r--r--src/rust/adaptation/mod.rs886
-rw-r--r--src/rust/error.rs73
-rw-r--r--src/rust/event_manager/mock_event_manager.rs239
-rw-r--r--src/rust/event_manager/mod.rs756
-rw-r--r--src/rust/lib.rs24
-rw-r--r--src/rust/uci/mock_uci_logger.rs76
-rw-r--r--src/rust/uci/mod.rs1129
-rw-r--r--src/rust/uci/uci_hmsgs.rs190
-rw-r--r--src/rust/uci/uci_hrcv.rs209
-rw-r--r--src/rust/uci/uci_logger.rs693
-rw-r--r--src/rust/uci_hal_android/error.rs143
-rw-r--r--src/rust/uci_hal_android/uci_hal_android.rs50
-rw-r--r--src/rust/uwb_core/Cargo.toml10
-rw-r--r--src/rust/uwb_core/README.md73
-rw-r--r--src/rust/uwb_core/build.rs59
-rw-r--r--src/rust/uwb_core/examples/main.rs68
-rw-r--r--src/rust/uwb_core/fuzz/.gitignore4
-rw-r--r--src/rust/uwb_core/fuzz/Cargo.toml26
-rw-r--r--src/rust/uwb_core/fuzz/proto_uwb_service_fuzzer.rs87
-rw-r--r--src/rust/uwb_core/protos/uwb_service.proto665
-rw-r--r--src/rust/uwb_core/src/error.rs8
-rw-r--r--src/rust/uwb_core/src/lib.rs2
-rw-r--r--src/rust/uwb_core/src/params/app_config_params.rs2
-rw-r--r--src/rust/uwb_core/src/params/fira_app_config_params.rs6
-rw-r--r--src/rust/uwb_core/src/params/uci_packets.rs62
-rw-r--r--src/rust/uwb_core/src/proto.rs21
-rw-r--r--src/rust/uwb_core/src/proto/mappings.rs1208
-rw-r--r--src/rust/uwb_core/src/proto/utils.rs36
-rw-r--r--src/rust/uwb_core/src/service.rs8
-rw-r--r--src/rust/uwb_core/src/service/proto_uwb_service.rs325
-rw-r--r--src/rust/uwb_core/src/service/uwb_service.rs108
-rw-r--r--src/rust/uwb_core/src/service/uwb_service_builder.rs6
-rw-r--r--src/rust/uwb_core/src/session/session_manager.rs62
-rw-r--r--src/rust/uwb_core/src/session/uwb_session.rs10
-rw-r--r--src/rust/uwb_core/src/uci.rs11
-rw-r--r--src/rust/uwb_core/src/uci/command.rs291
-rw-r--r--src/rust/uwb_core/src/uci/message.rs8
-rw-r--r--src/rust/uwb_core/src/uci/mock_uci_hal.rs61
-rw-r--r--src/rust/uwb_core/src/uci/mock_uci_logger.rs8
-rw-r--r--src/rust/uwb_core/src/uci/mock_uci_manager.rs342
-rw-r--r--src/rust/uwb_core/src/uci/notification.rs435
-rw-r--r--src/rust/uwb_core/src/uci/pcapng_block.rs6
-rw-r--r--src/rust/uwb_core/src/uci/pcapng_uci_logger_factory.rs79
-rw-r--r--src/rust/uwb_core/src/uci/response.rs161
-rw-r--r--src/rust/uwb_core/src/uci/timeout_uci_hal.rs22
-rw-r--r--src/rust/uwb_core/src/uci/uci_hal.rs24
-rw-r--r--src/rust/uwb_core/src/uci/uci_logger.rs96
-rw-r--r--src/rust/uwb_core/src/uci/uci_logger_factory.rs15
-rw-r--r--src/rust/uwb_core/src/uci/uci_logger_pcapng.rs16
-rw-r--r--src/rust/uwb_core/src/uci/uci_manager.rs1542
-rw-r--r--src/rust/uwb_core/src/uci/uci_manager_sync.rs396
-rw-r--r--src/rust/uwb_uci_packets/build.rs15
-rw-r--r--src/rust/uwb_uci_packets/src/lib.rs945
-rw-r--r--src/rust/uwb_uci_packets/uci_packets.pdl574
-rwxr-xr-xsrc/uci/include/uci_defs.h60
-rwxr-xr-xsrc/uwa/dm/uwa_dm_act.cc150
-rwxr-xr-xsrc/uwa/dm/uwa_dm_api.cc114
-rwxr-xr-xsrc/uwa/dm/uwa_dm_main.cc8
-rwxr-xr-xsrc/uwa/include/uwa_api.h153
-rwxr-xr-xsrc/uwa/include/uwa_dm_int.h43
-rwxr-xr-xsrc/uwb/include/uci_hmsgs.h14
-rwxr-xr-xsrc/uwb/include/uwb_api.h192
-rwxr-xr-xsrc/uwb/include/uwb_int.h42
-rwxr-xr-xsrc/uwb/uci/uci_hmsgs.cc184
-rwxr-xr-xsrc/uwb/uci/uci_hrcv.cc22
-rwxr-xr-xsrc/uwb/uwb/uwb_main.cc141
-rwxr-xr-xsrc/uwb/uwb/uwb_ucif.cc713
77 files changed, 8727 insertions, 6963 deletions
diff --git a/src/Android.bp b/src/Android.bp
index d1db35b..55f04cf 100755
--- a/src/Android.bp
+++ b/src/Android.bp
@@ -3,96 +3,6 @@ package {
}
rust_defaults {
- name: "libuwb_uci_defaults",
- srcs: [
- "rust/lib.rs",
- ],
- crate_name: "uwb_uci_rust",
- lints: "android",
- clippy_lints: "android",
- rustlibs: [
- "android.hardware.uwb-V1-rust",
- "libanyhow",
- "libbinder_ndk_sys",
- "libbinder_rs",
- "libbinder_tokio_rs",
- "libbytes",
- "libjni",
- "liblazy_static",
- "liblog_rust",
- "liblogger",
- "libnum_traits",
- "libthiserror",
- "libtokio",
- "libuwb_uci_packets",
- ],
- target: {
- android: {
- rustlibs: [
- "librustutils",
- ],
- },
- },
- rlibs: [
- "libarbitrary",
- ],
- proc_macros: [
- "libasync_trait",
- ],
- apex_available: [
- "com.android.uwb",
- ],
- min_sdk_version: "Tiramisu",
- host_supported: true,
-}
-
-rust_library {
- name: "libuwb_uci_rust",
- defaults: ["libuwb_uci_defaults"],
-}
-
-rust_test {
- name: "libuwb_uci_rust_tests",
- defaults: ["libuwb_uci_defaults"],
- target: {
- android: {
- test_suites: [
- "general-tests",
- "mts-uwb"
- ],
- test_config_template: "uwb_rust_test_config_template.xml",
- },
- host: {
- test_suites: [
- "general-tests",
- ],
- data_libs: [
- "libandroid_runtime_lazy",
- "libbase",
- "libbinder",
- "libbinder_ndk",
- "libcutils",
- "liblog",
- "libutils",
- ],
- },
- },
- // Support multilib variants (using different suffix per sub-architecture), which is needed on
- // build targets with secondary architectures, as the MTS test suite packaging logic flattens
- // all test artifacts into a single `testcases` directory.
- compile_multilib: "both",
- multilib: {
- lib32: {
- suffix: "32",
- },
- lib64: {
- suffix: "64",
- },
- },
- auto_gen_config: true,
-}
-
-rust_defaults {
name: "libuwb_uci_packet_defaults",
srcs: [
"rust/uwb_uci_packets/src/lib.rs",
@@ -125,6 +35,8 @@ rust_test {
test_suites: [
"general-tests",
],
+ // See b/268061150
+ stem: "libuwb_uci_packet_tests_host",
},
},
// Support multilib variants (using different suffix per sub-architecture), which is needed on
@@ -140,6 +52,7 @@ rust_test {
},
},
auto_gen_config: true,
+ min_sdk_version: "33",
}
rust_library {
@@ -156,10 +69,7 @@ rust_library {
genrule {
name: "UwbGeneratedPackets_rust",
- tools: [
- "bluetooth_packetgen",
- ],
- cmd: "$(location bluetooth_packetgen) --include=external/uwb/src --out=$(genDir) $(in) --rust",
+ defaults: ["pdl_rust_generator_defaults"],
srcs: [
"rust/uwb_uci_packets/uci_packets.pdl",
],
@@ -200,6 +110,16 @@ rust_library {
],
}
+// Builds uwb_core library with "mock-utils" enabled.
+// This enables mock methods to be used for testing external crates.
+rust_library {
+ name: "libuwb_core_with_mock",
+ defaults: ["libuwb_core_defaults"],
+ crate_name: "uwb_core",
+ features: ["mock-utils"],
+ host_supported: true,
+}
+
rust_test {
name: "libuwb_core_tests",
defaults: ["libuwb_core_defaults"],
@@ -207,9 +127,43 @@ rust_test {
"libenv_logger",
"libtempfile",
],
- test_suites: [
- "general-tests",
- ],
+ target: {
+ android: {
+ test_suites: [
+ "general-tests",
+ "mts-uwb"
+ ],
+ test_config_template: "uwb_rust_test_config_template.xml",
+ },
+ host: {
+ test_suites: [
+ "general-tests",
+ ],
+ data_libs: [
+ "libandroid_runtime_lazy",
+ "libbase",
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+ // See b/268061150
+ stem: "libuwb_core_tests_host",
+ },
+ },
+ // Support multilib variants (using different suffix per sub-architecture), which is needed on
+ // build targets with secondary architectures, as the MTS test suite packaging logic flattens
+ // all test artifacts into a single `testcases` directory.
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+ auto_gen_config: true,
+ min_sdk_version: "33",
}
rust_binary {
@@ -231,19 +185,59 @@ rust_binary {
host_supported: true,
}
+// Build the uwb_core library with "proto" feature enabled.
+// It's used for fuzzer test.
+rust_library {
+ name: "libuwb_core_with_proto",
+ defaults: ["libuwb_core_defaults"],
+ crate_name: "uwb_core",
+ srcs: [
+ // Generate the protobuf bindings.
+ // These genrule follows the logic of rust/uwb_core/build.rs.
+ ":gen_uwb_core_proto",
+ ":include_uwb_core_proto",
+ ],
+ rustlibs: [
+ "libprotobuf",
+ ],
+ features: ["proto"],
+ host_supported: true,
+}
+
+genrule {
+ name: "gen_uwb_core_proto",
+ tools: ["aprotoc", "protoc-gen-rust"],
+ cmd: "$(location aprotoc)" +
+ " --proto_path=`dirname $(in)`" +
+ " --dependency_out=$(depfile)" +
+ " --plugin=$(location protoc-gen-rust)" +
+ " --rust_out=$(genDir) $(in)",
+ srcs: [
+ "rust/uwb_core/protos/uwb_service.proto",
+ ],
+ out: [
+ "uwb_service.rs",
+ ],
+ depfile: true,
+}
+
+genrule {
+ name: "include_uwb_core_proto",
+ cmd: "echo '#[path = \"uwb_service.rs\"]' > $(out);" +
+ "echo 'pub mod bindings;' >> $(out);",
+ out: [
+ "proto_bindings.rs",
+ ],
+}
+
rust_fuzz {
- name: "uwb_uci_rust_fuzzer",
+ name: "uwb_core_fuzzer",
srcs: [
- "fuzz/fuzzer.rs",
+ "rust/uwb_core/fuzz/proto_uwb_service_fuzzer.rs",
],
rustlibs: [
- "android.hardware.uwb-V1-rust",
"libarbitrary",
- "liblog_rust",
- "libnum_traits",
- "libtokio",
- "libuwb_uci_packets",
- "libuwb_uci_rust",
+ "libuwb_core_with_proto",
],
fuzz_config: {
cc: [
@@ -255,15 +249,14 @@ rust_fuzz {
},
}
-rust_library {
- name: "libuci_hal_android",
+rust_defaults {
+ name: "libuci_hal_android_defaults",
crate_name: "uci_hal_android",
lints: "android",
clippy_lints: "android",
rustlibs: [
"android.hardware.uwb-V1-rust",
"libanyhow",
- "libbinder_ndk_sys",
"libbinder_rs",
"libbinder_tokio_rs",
"libbytes",
@@ -271,7 +264,6 @@ rust_library {
"liblog_rust",
"libthiserror",
"libtokio",
- "libuwb_core",
"libuwb_uci_packets",
],
target: {
@@ -294,11 +286,77 @@ rust_library {
],
}
+rust_library {
+ name: "libuci_hal_android",
+ defaults: ["libuci_hal_android_defaults"],
+ rustlibs: [
+ "libuwb_core",
+ ],
+}
+
+// uci_hal_android built with uwb_core_with_mock.
+// Used to replace uci_hal_android in place where mock version of uwb_core is
+// used.
+rust_library {
+ name: "libuci_hal_android_with_mock",
+ defaults: ["libuci_hal_android_defaults"],
+ rustlibs: [
+ "libuwb_core_with_mock",
+ ],
+}
+
+rust_test {
+ name: "libuci_hal_android_tests",
+ defaults: ["libuci_hal_android_defaults"],
+ rustlibs: [
+ "libenv_logger",
+ "libtempfile",
+ "libuwb_core",
+ ],
+ target: {
+ android: {
+ test_suites: [
+ "general-tests",
+ "mts-uwb"
+ ],
+ test_config_template: "uwb_rust_test_config_template.xml",
+ },
+ host: {
+ test_suites: [
+ "general-tests",
+ ],
+ data_libs: [
+ "libandroid_runtime_lazy",
+ "libbase",
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+ // See b/268061150
+ stem: "libuci_hal_android_tests_host",
+ },
+ },
+ // Support multilib variants (using different suffix per sub-architecture), which is needed on
+ // build targets with secondary architectures, as the MTS test suite packaging logic flattens
+ // all test artifacts into a single `testcases` directory.
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+ auto_gen_config: true,
+ min_sdk_version: "33",
+}
+
// Generate the artifacts zip for uwb_core library and its dependencies.
genrule {
name: "uwb_core_artifacts",
tools: [
- "bluetooth_packetgen",
+ "pdl",
"soong_zip",
],
cmd:
@@ -310,10 +368,9 @@ genrule {
" $(genDir)/artifacts;" +
// Generate uci_packets.rs at $(genDir)/artifacts/uwb_uci_packets/.
- "$(location bluetooth_packetgen) --rust " +
- " --include=external/uwb/src/rust" +
- " --out=$(genDir)/artifacts " +
- " external/uwb/src/rust/uwb_uci_packets/uci_packets.pdl;" +
+ "$(location pdl) --output-format rust " +
+ " external/uwb/src/rust/uwb_uci_packets/uci_packets.pdl " +
+ " > $(genDir)/artifacts/uwb_uci_packets/uci_packets.rs;" +
// Pack the artifacts directory and clean up the directory.
"$(location soong_zip) -o $(out) " +
diff --git a/src/TEST_MAPPING b/src/TEST_MAPPING
index f098f13..94263af 100644
--- a/src/TEST_MAPPING
+++ b/src/TEST_MAPPING
@@ -6,9 +6,6 @@
// "host": true
// },
{
- "name": "libuwb_uci_rust_tests"
- },
- {
"name": "libuwb_uci_packet_tests"
},
{
diff --git a/src/fuzz/fuzzer.rs b/src/fuzz/fuzzer.rs
deleted file mode 100644
index 7386a38..0000000
--- a/src/fuzz/fuzzer.rs
+++ /dev/null
@@ -1,618 +0,0 @@
-#![no_main]
-#![allow(missing_docs)]
-
-use android_hardware_uwb::aidl::android::hardware::uwb::{
- IUwbChip::IUwbChipAsync, UwbEvent::UwbEvent, UwbStatus::UwbStatus,
-};
-use android_hardware_uwb::binder::{DeathRecipient, Strong};
-use libfuzzer_sys::{arbitrary::Arbitrary, fuzz_target};
-use log::{error, info};
-use num_traits::cast::FromPrimitive;
-use std::collections::HashMap;
-use std::sync::Arc;
-use tokio::runtime::Builder;
-use tokio::sync::{mpsc, Mutex};
-use uwb_uci_packets::{
- AndroidGetPowerStatsCmdBuilder, AndroidGetPowerStatsRspBuilder,
- AndroidSetCountryCodeCmdBuilder, AndroidSetCountryCodeRspBuilder, ControleeStatus,
- DeviceResetRspBuilder, DeviceState, DeviceStatusNtfBuilder,
- ExtendedAddressTwoWayRangingMeasurement, ExtendedMacTwoWayRangeDataNtfBuilder,
- GenericErrorBuilder, GetCapsInfoCmdBuilder, GetCapsInfoRspBuilder, GetDeviceInfoCmdBuilder,
- GetDeviceInfoRspBuilder, MessageControl, MulticastUpdateStatusCode, Packet, PowerStats,
- RangeStartCmdBuilder, RangeStartRspBuilder, RangeStopCmdBuilder, RangeStopRspBuilder,
- ReasonCode, SessionDeinitCmdBuilder, SessionDeinitRspBuilder, SessionGetAppConfigCmdBuilder,
- SessionGetAppConfigRspBuilder, SessionGetCountCmdBuilder, SessionGetCountRspBuilder,
- SessionGetStateCmdBuilder, SessionGetStateRspBuilder, SessionInitCmdBuilder,
- SessionInitRspBuilder, SessionSetAppConfigRspBuilder, SessionState, SessionStatusNtfBuilder,
- SessionType, SessionUpdateControllerMulticastListNtfBuilder,
- SessionUpdateControllerMulticastListRspBuilder, ShortAddressTwoWayRangingMeasurement,
- ShortMacTwoWayRangeDataNtfBuilder, StatusCode, UciCommandPacket, UciPacketChild,
- UciPacketHalPacket, UciPacketPacket, UciVendor_9_ResponseBuilder,
-};
-use uwb_uci_rust::adaptation::{mock_hal::MockHal, UwbAdaptationImpl};
-use uwb_uci_rust::error::UwbErr;
-use uwb_uci_rust::event_manager::mock_event_manager::MockEventManager;
-use uwb_uci_rust::uci::{
- uci_hmsgs, uci_hrcv, Dispatcher, DispatcherImpl, HalCallback, JNICommand, SyncUwbAdaptation,
-};
-
-#[derive(Debug, Clone, Arbitrary)]
-enum UciNotification {
- GenericError {
- status: u8,
- },
- DeviceStatusNtf {
- device_state: u8,
- },
- SessionStatusNtf {
- session_id: u32,
- session_state: u8,
- reason_code: u8,
- },
- ShortMacTwoWayRangeDataNtf {
- sequence_number: u32,
- session_id: u32,
- rcr_indicator: u8,
- current_ranging_interval: u32,
- two_way_ranging_measurements: Vec<ShortAddressMeasurement>,
- },
- ExtendedMacTwoWayRangeDataNtf {
- sequence_number: u32,
- session_id: u32,
- rcr_indicator: u8,
- current_ranging_interval: u32,
- two_way_ranging_measurements: Vec<ExtendedAddressMeasurement>,
- },
- SessionUpdateControllerMulticastListNtf {
- session_id: u32,
- remaining_multicast_list_size: u8,
- controlee_status: Vec<MockControleeStatus>,
- },
-}
-
-#[derive(Debug, Clone, Arbitrary)]
-struct ShortAddressMeasurement {
- mac_address: u16,
- status: u8,
- nlos: u8,
- distance: u16,
- aoa_azimuth: u16,
- aoa_azimuth_fom: u8,
- aoa_elevation: u16,
- aoa_elevation_fom: u8,
- aoa_destination_azimuth: u16,
- aoa_destination_azimuth_fom: u8,
- aoa_destination_elevation: u16,
- aoa_destination_elevation_fom: u8,
- slot_index: u8,
- rssi: u8,
-}
-
-impl ShortAddressMeasurement {
- fn convert(&self) -> Result<ShortAddressTwoWayRangingMeasurement, UwbErr> {
- Ok(ShortAddressTwoWayRangingMeasurement {
- mac_address: self.mac_address,
- status: StatusCode::from_u8(self.status).ok_or(UwbErr::InvalidArgs)?,
- nlos: self.nlos,
- distance: self.distance,
- aoa_azimuth: self.aoa_azimuth,
- aoa_azimuth_fom: self.aoa_azimuth_fom,
- aoa_elevation: self.aoa_elevation,
- aoa_elevation_fom: self.aoa_elevation_fom,
- aoa_destination_azimuth: self.aoa_destination_azimuth,
- aoa_destination_azimuth_fom: self.aoa_destination_azimuth_fom,
- aoa_destination_elevation: self.aoa_destination_elevation,
- aoa_destination_elevation_fom: self.aoa_destination_elevation_fom,
- slot_index: self.slot_index,
- rssi: self.rssi,
- })
- }
-}
-
-#[derive(Debug, Clone, Arbitrary)]
-struct ExtendedAddressMeasurement {
- mac_address: u64,
- status: u8,
- nlos: u8,
- distance: u16,
- aoa_azimuth: u16,
- aoa_azimuth_fom: u8,
- aoa_elevation: u16,
- aoa_elevation_fom: u8,
- aoa_destination_azimuth: u16,
- aoa_destination_azimuth_fom: u8,
- aoa_destination_elevation: u16,
- aoa_destination_elevation_fom: u8,
- slot_index: u8,
- rssi: u8,
-}
-
-impl ExtendedAddressMeasurement {
- fn convert(&self) -> Result<ExtendedAddressTwoWayRangingMeasurement, UwbErr> {
- Ok(ExtendedAddressTwoWayRangingMeasurement {
- mac_address: self.mac_address,
- status: StatusCode::from_u8(self.status).ok_or(UwbErr::InvalidArgs)?,
- nlos: self.nlos,
- distance: self.distance,
- aoa_azimuth: self.aoa_azimuth,
- aoa_azimuth_fom: self.aoa_azimuth_fom,
- aoa_elevation: self.aoa_elevation,
- aoa_elevation_fom: self.aoa_elevation_fom,
- aoa_destination_azimuth: self.aoa_destination_azimuth,
- aoa_destination_azimuth_fom: self.aoa_destination_azimuth_fom,
- aoa_destination_elevation: self.aoa_destination_elevation,
- aoa_destination_elevation_fom: self.aoa_destination_elevation_fom,
- slot_index: self.slot_index,
- rssi: self.rssi,
- })
- }
-}
-
-#[derive(Debug, Clone, Arbitrary)]
-struct MockControleeStatus {
- mac_address: u16,
- subsession_id: u32,
- status: u8,
-}
-
-impl MockControleeStatus {
- fn convert(&self) -> Result<ControleeStatus, UwbErr> {
- Ok(ControleeStatus {
- mac_address: self.mac_address,
- subsession_id: self.subsession_id,
- status: MulticastUpdateStatusCode::from_u8(self.status).ok_or(UwbErr::InvalidArgs)?,
- })
- }
-}
-
-#[derive(Debug, Clone, Arbitrary)]
-enum Command {
- JNICmd(JNICommand),
- UciNtf(UciNotification),
-}
-
-async fn create_dispatcher_with_mock_adaptation(
- msgs: Vec<Command>,
-) -> Result<(DispatcherImpl, mpsc::UnboundedSender<(HalCallback, String)>), UwbErr> {
- let (rsp_sender, rsp_receiver) = mpsc::unbounded_channel::<(HalCallback, String)>();
- let mut mock_hal = MockHal::new(Some(rsp_sender.clone()));
- let mut mock_event_manager = MockEventManager::new();
- for msg in &msgs {
- match msg {
- Command::JNICmd(cmd) => match cmd {
- JNICommand::Enable => {
- mock_hal.expect_open(Ok(()));
- mock_hal.expect_core_init(Ok(()));
- }
- JNICommand::Disable(_graceful) => {
- break;
- }
- _ => {
- let (cmd, rsp) = match generate_fake_cmd_rsp(cmd) {
- Ok((command, response)) => (command, response),
- Err(e) => {
- mock_hal.clear_expected_calls();
- mock_event_manager.clear_expected_calls();
- return Err(e);
- }
- };
- let cmd_packet: UciPacketPacket = cmd.clone().into();
- let mut cmd_frag_packets: Vec<UciPacketHalPacket> = cmd_packet.into();
- let cmd_frag_data = cmd_frag_packets.pop().unwrap().to_vec();
- let cmd_frag_data_len = cmd_frag_data.len();
- mock_hal.expect_send_uci_message(
- cmd_frag_data,
- Some(rsp),
- Ok(cmd_frag_data_len.try_into().unwrap()),
- )
- }
- },
- Command::UciNtf(ntf) => match ntf {
- UciNotification::GenericError { status } => {
- if StatusCode::from_u8(*status).is_none() {
- mock_hal.clear_expected_calls();
- mock_event_manager.clear_expected_calls();
- return Err(UwbErr::InvalidArgs);
- }
- mock_event_manager.expect_core_generic_error_notification_received(Ok(()))
- }
- UciNotification::DeviceStatusNtf { device_state } => {
- if DeviceState::from_u8(*device_state).is_none() {
- mock_hal.clear_expected_calls();
- mock_event_manager.clear_expected_calls();
- return Err(UwbErr::InvalidArgs);
- }
- mock_event_manager.expect_device_status_notification_received(Ok(()))
- }
- UciNotification::SessionStatusNtf {
- session_id: _session_id,
- session_state,
- reason_code,
- } => {
- if SessionState::from_u8(*session_state).is_none()
- || ReasonCode::from_u8(*reason_code).is_none()
- || *session_state == 0
- {
- mock_hal.clear_expected_calls();
- mock_event_manager.clear_expected_calls();
- return Err(UwbErr::InvalidArgs);
- }
- mock_event_manager.expect_session_status_notification_received(Ok(()))
- }
- UciNotification::ShortMacTwoWayRangeDataNtf {
- sequence_number: _sequence_number,
- session_id: _session_id,
- rcr_indicator: _rcr_indicator,
- current_ranging_interval: _current_ranging_interval,
- two_way_ranging_measurements,
- } => {
- for measurement in two_way_ranging_measurements.iter() {
- if StatusCode::from_u8(measurement.status).is_none() {
- mock_hal.clear_expected_calls();
- mock_event_manager.clear_expected_calls();
- return Err(UwbErr::InvalidArgs);
- }
- }
- mock_event_manager.expect_short_range_data_notification_received(Ok(()))
- }
- UciNotification::ExtendedMacTwoWayRangeDataNtf {
- sequence_number: _sequence_number,
- session_id: _session_id,
- rcr_indicator: _rcr_indicator,
- current_ranging_interval: _current_ranging_interval,
- two_way_ranging_measurements,
- } => {
- for measurement in two_way_ranging_measurements.iter() {
- if StatusCode::from_u8(measurement.status).is_none() {
- mock_hal.clear_expected_calls();
- mock_event_manager.clear_expected_calls();
- return Err(UwbErr::InvalidArgs);
- }
- }
- mock_event_manager.expect_extended_range_data_notification_received(Ok(()))
- }
- UciNotification::SessionUpdateControllerMulticastListNtf {
- session_id: _session_id,
- remaining_multicast_list_size: _remaining_multicast_list_size,
- controlee_status,
- } => {
- for status in controlee_status.iter() {
- if MulticastUpdateStatusCode::from_u8(status.status).is_none() {
- mock_hal.clear_expected_calls();
- mock_event_manager.clear_expected_calls();
- return Err(UwbErr::InvalidArgs);
- }
- }
- mock_event_manager
- .expect_session_update_controller_multicast_list_notification_received(Ok(
- (),
- ))
- }
- },
- }
- }
- mock_hal.expect_close(Ok(()));
- let mut adaptation = Arc::new(
- UwbAdaptationImpl::new_with_args(
- rsp_sender.clone(),
- HashMap::from([(
- String::from("chip_id"),
- Strong::new(Box::new(mock_hal) as Box<dyn IUwbChipAsync<_> + 'static>),
- )]),
- Arc::new(Mutex::new(Vec::from([DeathRecipient::new(|| {})]))),
- )
- .await?,
- );
- Ok((
- DispatcherImpl::new_for_testing(
- mock_event_manager,
- adaptation as SyncUwbAdaptation,
- rsp_receiver,
- )?,
- rsp_sender,
- ))
-}
-
-fn generate_fake_cmd_rsp(
- msg: &JNICommand,
-) -> Result<(UciCommandPacket, uci_hrcv::UciResponse), UwbErr> {
- match msg {
- JNICommand::UciSessionInit(session_id, session_type) => Ok((
- uci_hmsgs::build_session_init_cmd(*session_id, *session_type)?.build().into(),
- uci_hrcv::UciResponse::SessionInitRsp(
- SessionInitRspBuilder { status: StatusCode::UciStatusOk }.build(),
- ),
- )),
- JNICommand::UciGetCapsInfo => Ok((
- GetCapsInfoCmdBuilder {}.build().into(),
- uci_hrcv::UciResponse::GetCapsInfoRsp(
- GetCapsInfoRspBuilder { status: StatusCode::UciStatusOk, tlvs: vec![] }.build(),
- ),
- )),
- JNICommand::UciGetDeviceInfo => Ok((
- GetDeviceInfoCmdBuilder {}.build().into(),
- uci_hrcv::UciResponse::GetDeviceInfoRsp(
- GetDeviceInfoRspBuilder {
- status: StatusCode::UciStatusOk,
- uci_version: 0,
- mac_version: 0,
- phy_version: 0,
- uci_test_version: 0,
- vendor_spec_info: vec![],
- }
- .build(),
- ),
- )),
- JNICommand::UciSessionDeinit(session_id) => Ok((
- SessionDeinitCmdBuilder { session_id: *session_id }.build().into(),
- uci_hrcv::UciResponse::SessionDeinitRsp(
- SessionDeinitRspBuilder { status: StatusCode::UciStatusOk }.build(),
- ),
- )),
- JNICommand::UciSessionGetCount => Ok((
- SessionGetCountCmdBuilder {}.build().into(),
- uci_hrcv::UciResponse::SessionGetCountRsp(
- SessionGetCountRspBuilder { status: StatusCode::UciStatusOk, session_count: 1 }
- .build(),
- ),
- )),
- JNICommand::UciStartRange(session_id) => Ok((
- RangeStartCmdBuilder { session_id: *session_id }.build().into(),
- uci_hrcv::UciResponse::RangeStartRsp(
- RangeStartRspBuilder { status: StatusCode::UciStatusOk }.build(),
- ),
- )),
- JNICommand::UciStopRange(session_id) => Ok((
- RangeStopCmdBuilder { session_id: *session_id }.build().into(),
- uci_hrcv::UciResponse::RangeStopRsp(
- RangeStopRspBuilder { status: StatusCode::UciStatusOk }.build(),
- ),
- )),
- JNICommand::UciGetSessionState(session_id) => Ok((
- SessionGetStateCmdBuilder { session_id: *session_id }.build().into(),
- uci_hrcv::UciResponse::SessionGetStateRsp(
- SessionGetStateRspBuilder {
- status: StatusCode::UciStatusOk,
- session_state: SessionState::SessionStateInit,
- }
- .build(),
- ),
- )),
- JNICommand::UciSessionUpdateMulticastList {
- session_id,
- action,
- no_of_controlee,
- address_list,
- sub_session_id_list,
- message_control,
- sub_session_key_list,
- } => Ok((
- uci_hmsgs::build_multicast_list_update_cmd(
- *session_id,
- *action,
- *no_of_controlee,
- address_list,
- sub_session_id_list,
- match *message_control {
- -1 => None,
- _ => Some(
- MessageControl::from_i32(*message_control).ok_or(UwbErr::InvalidArgs)?,
- ),
- },
- sub_session_key_list,
- )?
- .build()
- .into(),
- uci_hrcv::UciResponse::SessionUpdateControllerMulticastListRsp(
- SessionUpdateControllerMulticastListRspBuilder { status: StatusCode::UciStatusOk }
- .build(),
- ),
- )),
- JNICommand::UciSetCountryCode { code } => Ok((
- uci_hmsgs::build_set_country_code_cmd(&code)?.build().into(),
- uci_hrcv::UciResponse::AndroidSetCountryCodeRsp(
- AndroidSetCountryCodeRspBuilder { status: StatusCode::UciStatusOk }.build(),
- ),
- )),
- JNICommand::UciSetAppConfig {
- session_id,
- no_of_params,
- app_config_param_len,
- app_configs,
- } => Ok((
- uci_hmsgs::build_set_app_config_cmd(*session_id, *no_of_params, app_configs)?
- .build()
- .into(),
- uci_hrcv::UciResponse::SessionSetAppConfigRsp(
- SessionSetAppConfigRspBuilder {
- status: StatusCode::UciStatusOk,
- cfg_status: vec![],
- }
- .build(),
- ),
- )),
- JNICommand::UciGetAppConfig {
- session_id,
- no_of_params,
- app_config_param_len,
- app_configs,
- } => Ok((
- SessionGetAppConfigCmdBuilder {
- session_id: *session_id,
- app_cfg: app_configs.to_vec(),
- }
- .build()
- .into(),
- uci_hrcv::UciResponse::SessionGetAppConfigRsp(
- SessionGetAppConfigRspBuilder { status: StatusCode::UciStatusOk, tlvs: vec![] }
- .build(),
- ),
- )),
- JNICommand::UciRawVendorCmd { gid, oid, payload } => Ok((
- uci_hmsgs::build_uci_vendor_cmd_packet(*gid, *oid, payload.to_vec())?.into(),
- uci_hrcv::UciResponse::RawVendorRsp(
- UciVendor_9_ResponseBuilder { opcode: 0, payload: None }.build().into(),
- ),
- )),
- JNICommand::UciDeviceReset { reset_config } => Ok((
- uci_hmsgs::build_device_reset_cmd(*reset_config)?.build().into(),
- uci_hrcv::UciResponse::DeviceResetRsp(
- DeviceResetRspBuilder { status: StatusCode::UciStatusOk }.build(),
- ),
- )),
- JNICommand::UciGetPowerStats => Ok((
- AndroidGetPowerStatsCmdBuilder {}.build().into(),
- uci_hrcv::UciResponse::AndroidGetPowerStatsRsp(
- AndroidGetPowerStatsRspBuilder {
- stats: PowerStats {
- status: StatusCode::UciStatusOk,
- idle_time_ms: 0,
- tx_time_ms: 0,
- rx_time_ms: 0,
- total_wake_count: 0,
- },
- }
- .build(),
- ),
- )),
- _ => Err(UwbErr::Exit),
- }
-}
-
-fn consume_command(msgs: Vec<Command>) -> Result<(), UwbErr> {
- let rt = Builder::new_current_thread().enable_all().build()?;
- let (mut mock_dispatcher, mut rsp_sender) =
- rt.block_on(create_dispatcher_with_mock_adaptation(msgs.clone()))?;
- let chip_id = String::from("chip_id");
- for msg in msgs {
- match msg {
- Command::JNICmd(cmd) => match cmd {
- JNICommand::Enable => {
- mock_dispatcher
- .send_jni_command(JNICommand::Enable, chip_id.clone())
- .expect(format!("Failed to send {:?}", cmd).as_str());
- }
- JNICommand::Disable(_graceful) => {
- break;
- }
- _ => {
- mock_dispatcher
- .block_on_jni_command(cmd.clone(), chip_id.clone())
- .expect(format!("Failed to send {:?}", cmd).as_str());
- }
- },
- Command::UciNtf(ntf) => {
- let evt = match ntf {
- UciNotification::GenericError { status } => {
- uci_hrcv::UciNotification::GenericError(
- GenericErrorBuilder {
- status: StatusCode::from_u8(status).ok_or(UwbErr::InvalidArgs)?,
- }
- .build(),
- )
- }
- UciNotification::DeviceStatusNtf { device_state } => {
- uci_hrcv::UciNotification::DeviceStatusNtf(
- DeviceStatusNtfBuilder {
- device_state: DeviceState::from_u8(device_state)
- .ok_or(UwbErr::InvalidArgs)?,
- }
- .build(),
- )
- }
- UciNotification::SessionStatusNtf {
- session_id,
- session_state,
- reason_code,
- } => uci_hrcv::UciNotification::SessionStatusNtf(
- SessionStatusNtfBuilder {
- session_id,
- session_state: SessionState::from_u8(session_state)
- .ok_or(UwbErr::InvalidArgs)?,
- reason_code: ReasonCode::from_u8(reason_code)
- .ok_or(UwbErr::InvalidArgs)?,
- }
- .build(),
- ),
- UciNotification::ShortMacTwoWayRangeDataNtf {
- sequence_number,
- session_id,
- rcr_indicator,
- current_ranging_interval,
- two_way_ranging_measurements,
- } => {
- let mut measurements = Vec::new();
- for measurement in two_way_ranging_measurements.iter() {
- measurements.push(measurement.convert()?);
- }
- uci_hrcv::UciNotification::ShortMacTwoWayRangeDataNtf(
- ShortMacTwoWayRangeDataNtfBuilder {
- sequence_number,
- session_id,
- rcr_indicator,
- current_ranging_interval,
- two_way_ranging_measurements: measurements,
- }
- .build(),
- )
- }
- UciNotification::ExtendedMacTwoWayRangeDataNtf {
- sequence_number,
- session_id,
- rcr_indicator,
- current_ranging_interval,
- two_way_ranging_measurements,
- } => {
- let mut measurements = Vec::new();
- for measurement in two_way_ranging_measurements.iter() {
- measurements.push(measurement.convert()?);
- }
- uci_hrcv::UciNotification::ExtendedMacTwoWayRangeDataNtf(
- ExtendedMacTwoWayRangeDataNtfBuilder {
- sequence_number,
- session_id,
- rcr_indicator,
- current_ranging_interval,
- two_way_ranging_measurements: measurements,
- }
- .build(),
- )
- }
- UciNotification::SessionUpdateControllerMulticastListNtf {
- session_id,
- remaining_multicast_list_size,
- controlee_status,
- } => {
- let mut status_vec = Vec::new();
- for status in controlee_status.iter() {
- status_vec.push(status.convert()?);
- }
- uci_hrcv::UciNotification::SessionUpdateControllerMulticastListNtf(
- SessionUpdateControllerMulticastListNtfBuilder {
- session_id,
- remaining_multicast_list_size,
- controlee_status: status_vec,
- }
- .build(),
- )
- }
- };
- rsp_sender
- .send((HalCallback::UciNtf(evt.clone()), chip_id.clone()))
- .expect(format!("Error sending uci notification: {:?}", evt).as_str());
- }
- }
- }
- mock_dispatcher
- .send_jni_command(JNICommand::Disable(true), chip_id)
- .expect("Failed to send JNICommand::Disable cmd.");
- mock_dispatcher.wait_for_exit()?;
- Ok(())
-}
-
-fuzz_target!(|msgs: Vec<Command>| {
- match consume_command(msgs) {
- Ok(()) => info!("fuzzing success"),
- Err(e) => error!("fuzzing failed: {:?}", e),
- };
-});
diff --git a/src/gki/common/uwb_gki.h b/src/gki/common/uwb_gki.h
index 4cae456..3451093 100755
--- a/src/gki/common/uwb_gki.h
+++ b/src/gki/common/uwb_gki.h
@@ -122,6 +122,12 @@ typedef struct {
uint16_t count;
} BUFFER_Q;
+typedef struct {
+ BUFFER_Q tx_data_pkt_q;
+ uint32_t session_id;
+ uint8_t credit_available;
+} DATA_BUFFER_Q;
+
/* Task constants
*/
#ifndef TASKPTR
diff --git a/src/gki/common/uwb_gki_buffer.cc b/src/gki/common/uwb_gki_buffer.cc
index 82858f7..566b31d 100755
--- a/src/gki/common/uwb_gki_buffer.cc
+++ b/src/gki/common/uwb_gki_buffer.cc
@@ -93,7 +93,7 @@ static bool phUwb_gki_alloc_free_queue(uint8_t id) {
if (Q->p_first == 0) {
uint32_t requested_size;
bool overflow = __builtin_mul_overflow(Q->size + BUFFER_PADDING_SIZE,
- Q->total, &requested_size)
+ Q->total, &requested_size);
if (overflow) {
phUwb_GKI_exception(GKI_ERROR_BUF_SIZE_TOOBIG,
"gki_alloc_free_queue: Buffer overflow");
diff --git a/src/gki/ulinux/uwb_gki_ulinux.cc b/src/gki/ulinux/uwb_gki_ulinux.cc
index 40af99d..084ca07 100755
--- a/src/gki/ulinux/uwb_gki_ulinux.cc
+++ b/src/gki/ulinux/uwb_gki_ulinux.cc
@@ -1,7 +1,7 @@
/******************************************************************************
*
* Copyright (C) 1999-2012 Broadcom Corporation
- * Copyright 2019 NXP
+ * Copyright 2019,2022 NXP
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -647,9 +647,7 @@ void phUwb_GKI_enable(void) {
*******************************************************************************/
void phUwb_GKI_disable(void) {
- UCI_TRACE_I("GKI_disable");
pthread_mutex_lock(&gki_cb.os.GKI_mutex);
- UCI_TRACE_I("Leaving GKI_disable");
return;
}
diff --git a/src/include/uwb_hal_int.h b/src/include/uwb_hal_int.h
index b5fced1..f328b9e 100755
--- a/src/include/uwb_hal_int.h
+++ b/src/include/uwb_hal_int.h
@@ -32,7 +32,9 @@
enum {
HAL_UWB_OPEN_CPLT_EVT = 0x00,
HAL_UWB_CLOSE_CPLT_EVT = 0x01,
- HAL_UWB_ERROR_EVT = 0x02
+ HAL_UWB_INIT_CPLT_EVT = 0x02,
+ HAL_UWB_ERROR_EVT = 0x03,
+ HAL_UWB_HW_RESET = 0x04
};
typedef uint8_t uwb_event_t;
diff --git a/src/include/uwb_types.h b/src/include/uwb_types.h
index 410f072..5e141b2 100755
--- a/src/include/uwb_types.h
+++ b/src/include/uwb_types.h
@@ -165,6 +165,14 @@ typedef struct {
((((uint32_t)(*((p) + 3)))) << 24)); \
(p) += 4; \
}
+#define STREAM_TO_UINT40(u40, p) \
+ { \
+ u40 = (((uint64_t)(*(p))) + ((((uint64_t)(*((p) + 1)))) << 8) + \
+ ((((uint64_t)(*((p) + 2)))) << 16) + \
+ ((((uint64_t)(*((p) + 3)))) << 24) + \
+ ((((uint64_t)(*((p) + 4)))) << 32)); \
+ (p) += 5; \
+ }
#define STREAM_TO_UINT64(u64, p) \
{ \
u64 = (((uint64_t)(*(p))) + ((((uint64_t)(*((p) + 1)))) << 8) + \
diff --git a/src/rust/adaptation/mock_adaptation.rs b/src/rust/adaptation/mock_adaptation.rs
deleted file mode 100644
index 078aa5d..0000000
--- a/src/rust/adaptation/mock_adaptation.rs
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//! MockUwbAdaptation
-
-use crate::adaptation::UwbAdaptation;
-use crate::error::UwbErr;
-use crate::uci::uci_hrcv;
-use crate::uci::HalCallback;
-use android_hardware_uwb::aidl::android::hardware::uwb::{
- UwbEvent::UwbEvent, UwbStatus::UwbStatus,
-};
-use async_trait::async_trait;
-use log::warn;
-use std::collections::VecDeque;
-use std::sync::Mutex as StdMutex;
-use tokio::sync::mpsc;
-use uwb_uci_packets::{Packet, UciCommandPacket};
-
-type Result<T> = std::result::Result<T, UwbErr>;
-
-#[cfg(any(test, fuzzing))]
-enum ExpectedCall {
- Finalize {
- expected_exit_status: bool,
- },
- HalOpen {
- out: Result<()>,
- },
- HalClose {
- out: Result<()>,
- },
- CoreInitialization {
- out: Result<()>,
- },
- SessionInitialization {
- expected_session_id: i32,
- out: Result<()>,
- },
- SendUciMessage {
- expected_cmd: UciCommandPacket,
- rsp: Option<uci_hrcv::UciResponse>,
- notf: Option<uci_hrcv::UciNotification>,
- out: Result<()>,
- },
-}
-
-#[cfg(any(test, fuzzing))]
-pub struct MockUwbAdaptation {
- rsp_sender: mpsc::UnboundedSender<(HalCallback, String)>,
- expected_calls: StdMutex<VecDeque<ExpectedCall>>,
-}
-
-#[cfg(any(test, fuzzing))]
-impl MockUwbAdaptation {
- pub fn new(rsp_sender: mpsc::UnboundedSender<(HalCallback, String)>) -> Self {
- Self { rsp_sender, expected_calls: StdMutex::new(VecDeque::new()) }
- }
-
- pub fn expect_finalize(&self, expected_exit_status: bool) {
- self.expected_calls
- .lock()
- .unwrap()
- .push_back(ExpectedCall::Finalize { expected_exit_status });
- }
- pub fn expect_hal_open(&self, out: Result<()>) {
- self.expected_calls.lock().unwrap().push_back(ExpectedCall::HalOpen { out });
- }
- pub fn expect_hal_close(&self, out: Result<()>) {
- self.expected_calls.lock().unwrap().push_back(ExpectedCall::HalClose { out });
- }
- pub fn expect_core_initialization(&self, out: Result<()>) {
- self.expected_calls.lock().unwrap().push_back(ExpectedCall::CoreInitialization { out });
- }
- pub fn expect_session_initialization(&self, expected_session_id: i32, out: Result<()>) {
- self.expected_calls
- .lock()
- .unwrap()
- .push_back(ExpectedCall::SessionInitialization { expected_session_id, out });
- }
- pub fn expect_send_uci_message(
- &self,
- expected_cmd: UciCommandPacket,
- rsp: Option<uci_hrcv::UciResponse>,
- notf: Option<uci_hrcv::UciNotification>,
- out: Result<()>,
- ) {
- self.expected_calls.lock().unwrap().push_back(ExpectedCall::SendUciMessage {
- expected_cmd,
- rsp,
- notf,
- out,
- });
- }
-
- pub fn clear_expected_calls(&self) {
- self.expected_calls.lock().unwrap().clear();
- }
-
- async fn send_hal_event(&self, event: UwbEvent, event_status: UwbStatus) {
- self.rsp_sender
- .send((HalCallback::Event { event, event_status }, String::from("default")))
- .unwrap();
- }
-
- async fn send_uci_response(&self, rsp: uci_hrcv::UciResponse) {
- self.rsp_sender.send((HalCallback::UciRsp(rsp), String::from("default"))).unwrap();
- }
-
- async fn send_uci_notification(&self, ntf: uci_hrcv::UciNotification) {
- self.rsp_sender.send((HalCallback::UciNtf(ntf), String::from("default"))).unwrap();
- }
-}
-
-#[cfg(any(test, fuzzing))]
-impl Drop for MockUwbAdaptation {
- fn drop(&mut self) {
- assert!(self.expected_calls.lock().unwrap().is_empty());
- }
-}
-
-#[cfg(any(test, fuzzing))]
-#[async_trait]
-impl UwbAdaptation for MockUwbAdaptation {
- async fn finalize(&mut self, exit_status: bool) {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::Finalize { expected_exit_status })
- if expected_exit_status == exit_status =>
- {
- return;
- }
- Some(call) => {
- expected_calls.push_front(call);
- }
- None => {}
- }
- warn!("unpected finalize() called");
- }
-
- async fn hal_open(&self, _chip_id: &str) -> Result<()> {
- let expected_out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::HalOpen { out }) => Some(out),
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- match expected_out {
- Some(out) => {
- let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED };
- self.send_hal_event(UwbEvent::OPEN_CPLT, status).await;
- out
- }
- None => {
- warn!("unpected hal_open() called");
- Err(UwbErr::Undefined)
- }
- }
- }
-
- async fn hal_close(&self, _chip_id: &str) -> Result<()> {
- let expected_out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::HalClose { out }) => Some(out),
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- match expected_out {
- Some(out) => {
- let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED };
- self.send_hal_event(UwbEvent::CLOSE_CPLT, status).await;
- out
- }
- None => {
- warn!("unpected hal_close() called");
- Err(UwbErr::Undefined)
- }
- }
- }
-
- async fn core_initialization(&self, _chip_id: &str) -> Result<()> {
- let expected_out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::CoreInitialization { out }) => Some(out),
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- match expected_out {
- Some(out) => {
- let status = if out.is_ok() { UwbStatus::OK } else { UwbStatus::FAILED };
- self.send_hal_event(UwbEvent::POST_INIT_CPLT, status).await;
- out
- }
- None => {
- warn!("unpected core_initialization() called");
- Err(UwbErr::Undefined)
- }
- }
- }
-
- async fn session_initialization(&self, session_id: i32, _chip_id: &str) -> Result<()> {
- let expected_out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::SessionInitialization { expected_session_id, out })
- if expected_session_id == session_id =>
- {
- Some(out)
- }
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- match expected_out {
- Some(out) => out,
- None => {
- warn!("unpected session_initialization() called");
- Err(UwbErr::Undefined)
- }
- }
- }
-
- async fn send_uci_message(&self, cmd: UciCommandPacket, _chip_id: &str) -> Result<()> {
- let expected_out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::SendUciMessage {
- expected_cmd,
- rsp,
- notf,
- out,
- // PDL generated packets do not implement PartialEq, so use the raw bytes for comparison.
- }) if expected_cmd.clone().to_bytes() == cmd.to_bytes() => Some((rsp, notf, out)),
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- match expected_out {
- Some((rsp, notf, out)) => {
- if let Some(notf) = notf {
- self.send_uci_notification(notf).await;
- }
- if let Some(rsp) = rsp {
- self.send_uci_response(rsp).await;
- }
- out
- }
- None => {
- warn!("unpected send_uci_message() called");
- Err(UwbErr::Undefined)
- }
- }
- }
-}
diff --git a/src/rust/adaptation/mock_hal.rs b/src/rust/adaptation/mock_hal.rs
deleted file mode 100644
index db43edb..0000000
--- a/src/rust/adaptation/mock_hal.rs
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//! MockHal
-
-use crate::uci::{uci_hrcv, HalCallback};
-use android_hardware_uwb::aidl::android::hardware::uwb::{
- IUwbChip::IUwbChipAsync, IUwbClientCallback::IUwbClientCallback, UwbEvent::UwbEvent,
- UwbStatus::UwbStatus,
-};
-use android_hardware_uwb::binder::{Result as BinderResult, Strong};
-use async_trait::async_trait;
-use binder::{SpIBinder, StatusCode};
-use log::info;
-use std::collections::VecDeque;
-use std::sync::Mutex as StdMutex;
-use tokio::sync::mpsc;
-
-#[cfg(any(test, fuzzing))]
-enum ExpectedHalCall {
- Open {
- out: BinderResult<()>,
- },
- Close {
- out: BinderResult<()>,
- },
- CoreInit {
- out: BinderResult<()>,
- },
- SessionInit {
- expected_session_id: i32,
- out: BinderResult<()>,
- },
- SendUciMessage {
- expected_data: Vec<u8>,
- expected_rsp: Option<uci_hrcv::UciResponse>,
- out: BinderResult<i32>,
- },
-}
-
-#[cfg(any(test, fuzzing))]
-pub struct MockHal {
- rsp_sender: Option<mpsc::UnboundedSender<(HalCallback, String)>>,
- expected_calls: StdMutex<VecDeque<ExpectedHalCall>>,
-}
-
-#[cfg(any(test, fuzzing))]
-impl MockHal {
- pub fn new(rsp_sender: Option<mpsc::UnboundedSender<(HalCallback, String)>>) -> Self {
- logger::init(
- logger::Config::default().with_tag_on_device("uwb").with_min_level(log::Level::Debug),
- );
- info!("created mock hal.");
- Self { rsp_sender, expected_calls: StdMutex::new(VecDeque::new()) }
- }
- #[allow(dead_code)]
- pub fn expect_open(&self, out: BinderResult<()>) {
- self.expected_calls.lock().unwrap().push_back(ExpectedHalCall::Open { out });
- }
- #[allow(dead_code)]
- pub fn expect_close(&self, out: BinderResult<()>) {
- self.expected_calls.lock().unwrap().push_back(ExpectedHalCall::Close { out });
- }
- #[allow(dead_code)]
- pub fn expect_core_init(&self, out: BinderResult<()>) {
- self.expected_calls.lock().unwrap().push_back(ExpectedHalCall::CoreInit { out });
- }
- #[allow(dead_code)]
- pub fn expect_session_init(&self, expected_session_id: i32, out: BinderResult<()>) {
- self.expected_calls
- .lock()
- .unwrap()
- .push_back(ExpectedHalCall::SessionInit { expected_session_id, out });
- }
- pub fn expect_send_uci_message(
- &self,
- expected_data: Vec<u8>,
- expected_rsp: Option<uci_hrcv::UciResponse>,
- out: BinderResult<i32>,
- ) {
- self.expected_calls.lock().unwrap().push_back(ExpectedHalCall::SendUciMessage {
- expected_data,
- expected_rsp,
- out,
- });
- }
- pub fn clear_expected_calls(&self) {
- self.expected_calls.lock().unwrap().clear();
- }
-}
-
-#[cfg(any(test, fuzzing))]
-impl Drop for MockHal {
- fn drop(&mut self) {
- assert!(self.expected_calls.lock().unwrap().is_empty());
- }
-}
-
-#[cfg(any(test, fuzzing))]
-impl Default for MockHal {
- fn default() -> Self {
- Self::new(None)
- }
-}
-
-#[cfg(any(test, fuzzing))]
-impl binder::Interface for MockHal {}
-
-#[cfg(any(test, fuzzing))]
-impl binder::FromIBinder for MockHal {
- fn try_from(_ibinder: SpIBinder) -> std::result::Result<Strong<Self>, binder::StatusCode> {
- Err(binder::StatusCode::OK)
- }
-}
-
-#[cfg(any(test, fuzzing))]
-#[async_trait]
-impl<P: binder::BinderAsyncPool> IUwbChipAsync<P> for MockHal {
- fn getName(&self) -> binder::BoxFuture<BinderResult<String>> {
- Box::pin(std::future::ready(Ok("default".into())))
- }
-
- fn open<'a>(
- &'a self,
- _cb: &'a binder::Strong<dyn IUwbClientCallback>,
- ) -> binder::BoxFuture<'a, BinderResult<()>> {
- let expected_out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedHalCall::Open { out }) => Some(out),
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- match expected_out {
- Some(out) => Box::pin(std::future::ready(out)),
- None => Box::pin(std::future::ready(Err(StatusCode::UNKNOWN_ERROR.into()))),
- }
- }
-
- fn close(&self) -> binder::BoxFuture<BinderResult<()>> {
- let expected_out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedHalCall::Close { out }) => {
- if let Some(sender) = self.rsp_sender.as_ref() {
- sender
- .send((
- HalCallback::Event {
- event: UwbEvent::CLOSE_CPLT,
- event_status: UwbStatus::OK,
- },
- String::from("default"),
- ))
- .unwrap();
- }
- Some(out)
- }
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- match expected_out {
- Some(out) => Box::pin(std::future::ready(out)),
- None => Box::pin(std::future::ready(Err(StatusCode::UNKNOWN_ERROR.into()))),
- }
- }
-
- fn coreInit(&self) -> binder::BoxFuture<BinderResult<()>> {
- let expected_out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedHalCall::CoreInit { out }) => Some(out),
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- match expected_out {
- Some(out) => Box::pin(std::future::ready(out)),
- None => Box::pin(std::future::ready(Err(StatusCode::UNKNOWN_ERROR.into()))),
- }
- }
-
- fn sessionInit(&self, session_id: i32) -> binder::BoxFuture<BinderResult<()>> {
- let expected_out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedHalCall::SessionInit { expected_session_id, out })
- if expected_session_id == session_id =>
- {
- Some(out)
- }
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- match expected_out {
- Some(out) => Box::pin(std::future::ready(out)),
- None => Box::pin(std::future::ready(Err(StatusCode::UNKNOWN_ERROR.into()))),
- }
- }
-
- fn getSupportedAndroidUciVersion(&self) -> binder::BoxFuture<BinderResult<i32>> {
- Box::pin(std::future::ready(Ok(0)))
- }
-
- fn sendUciMessage(&self, cmd: &[u8]) -> binder::BoxFuture<BinderResult<i32>> {
- let expected_out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedHalCall::SendUciMessage { expected_data, expected_rsp, out })
- if expected_data == cmd =>
- {
- if let (Some(rsp), Some(sender)) = (expected_rsp, self.rsp_sender.as_ref()) {
- sender.send((HalCallback::UciRsp(rsp), String::from("default"))).unwrap();
- }
- Some(out)
- }
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
- match expected_out {
- Some(out) => Box::pin(std::future::ready(out)),
- None => Box::pin(std::future::ready(Err(StatusCode::UNKNOWN_ERROR.into()))),
- }
- }
-}
diff --git a/src/rust/adaptation/mod.rs b/src/rust/adaptation/mod.rs
deleted file mode 100644
index d16bae4..0000000
--- a/src/rust/adaptation/mod.rs
+++ /dev/null
@@ -1,886 +0,0 @@
-//! HAL interface.
-
-use crate::error::UwbErr;
-use crate::uci::uci_hrcv;
-use crate::uci::uci_logger::{RealFileFactory, UciLogMode, UciLogger, UciLoggerImpl};
-use crate::uci::HalCallback;
-use android_hardware_uwb::aidl::android::hardware::uwb::{
- IUwb::IUwbAsync,
- IUwbChip::IUwbChipAsync,
- IUwbClientCallback::{BnUwbClientCallback, IUwbClientCallbackAsyncServer},
- UwbEvent::UwbEvent,
- UwbStatus::UwbStatus,
-};
-use android_hardware_uwb::binder::{
- BinderFeatures, DeathRecipient, Interface, Result as BinderResult, Strong,
-};
-use async_trait::async_trait;
-use binder::IBinder;
-use binder_tokio::{Tokio, TokioRuntime};
-use log::error;
-#[cfg(target_os = "android")]
-use rustutils::system_properties;
-use std::collections::hash_map::HashMap;
-use std::sync::Arc;
-use tokio::runtime::Handle;
-use tokio::sync::{mpsc, Mutex};
-use uwb_uci_packets::{
- Packet, PacketDefrager, UciCommandPacket, UciPacketChild, UciPacketHalPacket, UciPacketPacket,
-};
-
-type Result<T> = std::result::Result<T, UwbErr>;
-type SyncUciLogger = Arc<dyn UciLogger + Send + Sync>;
-
-const UCI_LOG_DEFAULT: UciLogMode = UciLogMode::Disabled;
-
-pub struct UwbClientCallback {
- rsp_sender: mpsc::UnboundedSender<(HalCallback, String)>,
- logger: SyncUciLogger,
- defrager: Mutex<PacketDefrager>,
- chip_id: String,
-}
-
-impl UwbClientCallback {
- fn new(
- rsp_sender: mpsc::UnboundedSender<(HalCallback, String)>,
- logger: SyncUciLogger,
- chip_id: String,
- ) -> Self {
- UwbClientCallback { rsp_sender, logger, defrager: Default::default(), chip_id }
- }
-
- async fn log_uci_packet(&self, packet: UciPacketPacket) {
- match packet.specialize() {
- UciPacketChild::UciResponse(pkt) => self.logger.log_uci_response(pkt).await,
- UciPacketChild::UciNotification(pkt) => self.logger.log_uci_notification(pkt).await,
- _ => {}
- }
- }
-}
-
-impl Interface for UwbClientCallback {}
-
-#[async_trait]
-impl IUwbClientCallbackAsyncServer for UwbClientCallback {
- async fn onHalEvent(&self, event: UwbEvent, event_status: UwbStatus) -> BinderResult<()> {
- self.rsp_sender
- .send((HalCallback::Event { event, event_status }, self.chip_id.clone()))
- .unwrap_or_else(|e| error!("Error sending evt callback: {:?}", e));
- Ok(())
- }
-
- async fn onUciMessage(&self, data: &[u8]) -> BinderResult<()> {
- if let Some(packet) = self.defrager.lock().await.defragment_packet(data) {
- // all fragments for the packet received.
- self.log_uci_packet(packet.clone()).await;
- let packet_msg = uci_hrcv::uci_message(packet);
- match packet_msg {
- Ok(uci_hrcv::UciMessage::Response(evt)) => self
- .rsp_sender
- .send((HalCallback::UciRsp(evt), self.chip_id.clone()))
- .unwrap_or_else(|e| error!("Error sending uci response: {:?}", e)),
- Ok(uci_hrcv::UciMessage::Notification(evt)) => self
- .rsp_sender
- .send((HalCallback::UciNtf(evt), self.chip_id.clone()))
- .unwrap_or_else(|e| error!("Error sending uci notification: {:?}", e)),
- _ => error!("UCI message which is neither a UCI RSP or NTF: {:?}", data),
- }
- }
- Ok(())
- }
-}
-
-async fn get_hal_service(
- chip_ids: &[String],
-) -> Result<HashMap<String, Strong<dyn IUwbChipAsync<Tokio>>>> {
- let service_name: &str = "android.hardware.uwb.IUwb/default";
- let i_uwb: Strong<dyn IUwbAsync<Tokio>> =
- binder_tokio::wait_for_interface(service_name).await?;
- let mut hal_map = HashMap::new();
- let chips = i_uwb.getChips().await?;
-
- // If this is a single-chip system with chip_id == "default", then the name of the chip
- // doesn't matter. In that case, just grab the first IUwbChip from the list returned by getChips
- if *chip_ids == vec![String::from("default")] {
- if chips.is_empty() {
- error!("No chips are provided by vendor");
- return Err(UwbErr::UwbStatus(UwbStatus::FAILED));
- }
- let i_uwb_chip = i_uwb.getChip(chips.get(0).unwrap()).await?.into_async();
- hal_map.insert(String::from("default"), i_uwb_chip);
- return Ok(hal_map);
- }
-
- for chip_id in chip_ids {
- if !chips.contains(chip_id) {
- error!("Chip {} is not present in list of chip ids provided by vendor", chip_id);
- return Err(UwbErr::UwbStatus(UwbStatus::FAILED));
- }
- let i_uwb_chip = i_uwb.getChip(chip_id).await?.into_async();
- hal_map.insert(chip_id.clone(), i_uwb_chip);
- }
-
- Ok(hal_map)
-}
-
-#[async_trait]
-pub trait UwbAdaptation {
- async fn finalize(&mut self, exit_status: bool);
- async fn hal_open(&self, chip_id: &str) -> Result<()>;
- async fn hal_close(&self, chip_id: &str) -> Result<()>;
- async fn core_initialization(&self, chip_id: &str) -> Result<()>;
- async fn session_initialization(&self, session_id: i32, chip_id: &str) -> Result<()>;
- async fn send_uci_message(&self, cmd: UciCommandPacket, chip_id: &str) -> Result<()>;
-}
-
-#[derive(Clone)]
-pub struct UwbAdaptationImpl {
- hal_map: HashMap<String, Strong<dyn IUwbChipAsync<Tokio>>>,
- #[allow(dead_code)]
- // Need to store the death recipient since link_to_death stores a weak pointer.
- hal_death_recipients: Arc<Mutex<Vec<DeathRecipient>>>,
- rsp_sender: mpsc::UnboundedSender<(HalCallback, String)>,
- logger: SyncUciLogger,
-}
-
-impl UwbAdaptationImpl {
- #[cfg(target_os = "android")]
- fn get_uci_log_mode() -> UciLogMode {
- match system_properties::read("persist.uwb.uci_logger_mode") {
- Ok(Some(logger_mode)) => match logger_mode.as_str() {
- "disabled" => UciLogMode::Disabled,
- "filtered" => UciLogMode::Filtered,
- "enabled" => UciLogMode::Enabled,
- str => {
- error!("Logger mode not recognized! Value: {:?}", str);
- UCI_LOG_DEFAULT
- }
- },
- Ok(None) => UCI_LOG_DEFAULT,
- Err(e) => {
- error!("Failed to get uci_logger_mode {:?}", e);
- UCI_LOG_DEFAULT
- }
- }
- }
-
- #[cfg(not(target_os = "android"))]
- fn get_uci_log_mode() -> UciLogMode {
- // system_properties is not supported on host builds.
- UCI_LOG_DEFAULT
- }
-
- pub async fn new_with_args(
- rsp_sender: mpsc::UnboundedSender<(HalCallback, String)>,
- hal_map: HashMap<String, Strong<dyn IUwbChipAsync<Tokio>>>,
- hal_death_recipients: Arc<Mutex<Vec<DeathRecipient>>>,
- ) -> Result<Self> {
- let logger = UciLoggerImpl::new(
- UwbAdaptationImpl::get_uci_log_mode(),
- Arc::new(Mutex::new(RealFileFactory::default())),
- )
- .await;
- Ok(UwbAdaptationImpl {
- hal_map,
- rsp_sender,
- logger: Arc::new(logger),
- hal_death_recipients,
- })
- }
-
- pub async fn new(
- rsp_sender: mpsc::UnboundedSender<(HalCallback, String)>,
- chip_ids: &[String],
- ) -> Result<Self> {
- let hal_map = get_hal_service(chip_ids).await?;
-
- let mut hal_death_recipients = Vec::new();
- // Register for death notification.
- for chip_id in chip_ids {
- let rsp_sender_clone = rsp_sender.clone();
- let mut hal_death_recipient = DeathRecipient::new({
- let chip_id_clone = chip_id.clone();
-
- move || {
- error!("UWB HAL died. Resetting stack...");
- // Send error HAL event to trigger stack recovery.
- rsp_sender_clone
- .send((
- HalCallback::Event {
- event: UwbEvent::ERROR,
- event_status: UwbStatus::FAILED,
- },
- chip_id_clone.clone(),
- ))
- .unwrap_or_else(|e| error!("Error sending error evt callback: {:?}", e));
- }
- });
- hal_map.get(chip_id).unwrap().as_binder().link_to_death(&mut hal_death_recipient)?;
- hal_death_recipients.push(hal_death_recipient);
- }
- Self::new_with_args(rsp_sender, hal_map, Arc::new(Mutex::new(hal_death_recipients))).await
- }
-}
-
-#[async_trait]
-impl UwbAdaptation for UwbAdaptationImpl {
- async fn finalize(&mut self, _exit_status: bool) {}
-
- async fn hal_open(&self, chip_id: &str) -> Result<()> {
- let m_cback = BnUwbClientCallback::new_async_binder(
- UwbClientCallback::new(
- self.rsp_sender.clone(),
- self.logger.clone(),
- chip_id.to_string(),
- ),
- TokioRuntime(Handle::current()),
- BinderFeatures::default(),
- );
- match self.hal_map.get(chip_id) {
- Some(chip) => Ok(chip.open(&m_cback).await?),
- _ => Err(UwbErr::UwbStatus(UwbStatus::FAILED)),
- }
- }
-
- async fn hal_close(&self, chip_id: &str) -> Result<()> {
- self.logger.close_file().await;
- Ok(self.hal_map.get(chip_id).unwrap().close().await?)
- }
-
- async fn core_initialization(&self, chip_id: &str) -> Result<()> {
- Ok(self.hal_map.get(chip_id).unwrap().coreInit().await?)
- }
-
- async fn session_initialization(&self, session_id: i32, chip_id: &str) -> Result<()> {
- Ok(self.hal_map.get(chip_id).unwrap().sessionInit(session_id).await?)
- }
-
- async fn send_uci_message(&self, cmd: UciCommandPacket, chip_id: &str) -> Result<()> {
- self.logger.log_uci_command(cmd.clone()).await;
- let packet: UciPacketPacket = cmd.into();
- // fragment packet.
- let fragmented_packets: Vec<UciPacketHalPacket> = packet.into();
- for packet in fragmented_packets {
- self.hal_map.get(chip_id).unwrap().sendUciMessage(&packet.to_vec()).await?;
- }
- // TODO should we be validating the returned number?
- Ok(())
- }
-}
-
-#[cfg(any(test, fuzzing))]
-pub mod mock_adaptation;
-#[cfg(any(test, fuzzing))]
-pub mod mock_hal;
-
-#[cfg(test)]
-pub mod tests {
- use super::*;
- use crate::adaptation::mock_hal::MockHal;
- use crate::uci::mock_uci_logger::MockUciLogger;
- use bytes::Bytes;
- use uwb_uci_packets::*;
-
- fn create_uwb_client_callback(
- rsp_sender: mpsc::UnboundedSender<(HalCallback, String)>,
- ) -> UwbClientCallback {
- // Add tests for the mock logger.
- UwbClientCallback::new(rsp_sender, Arc::new(MockUciLogger::new()), String::from("default"))
- }
-
- fn setup_client_callback() -> (mpsc::UnboundedReceiver<(HalCallback, String)>, UwbClientCallback)
- {
- // TODO: Remove this once we call it somewhere real.
- logger::init(
- logger::Config::default()
- .with_tag_on_device("uwb_test")
- .with_min_level(log::Level::Debug),
- );
- let (rsp_sender, rsp_receiver) = mpsc::unbounded_channel::<(HalCallback, String)>();
- let uwb_client_callback = create_uwb_client_callback(rsp_sender);
- (rsp_receiver, uwb_client_callback)
- }
-
- #[tokio::test]
- async fn test_on_hal_event() {
- let event = UwbEvent(0);
- let event_status = UwbStatus(1);
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onHalEvent(event, event_status).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(response, Some((HalCallback::Event { event: _, event_status: _ }, _))));
- }
-
- #[tokio::test]
- async fn test_get_device_info_rsp() {
- let data = [
- 0x40, 0x02, 0x00, 0x0b, 0x01, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01,
- 0x0a,
- ];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::GetDeviceInfoRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_get_caps_info_rsp() {
- let data = [0x40, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x01];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::GetCapsInfoRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_set_config_rsp() {
- let data = [0x40, 0x04, 0x00, 0x04, 0x01, 0x01, 0x01, 0x01];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::SetConfigRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_get_config_rsp() {
- let data = [0x40, 0x05, 0x00, 0x05, 0x01, 0x01, 0x00, 0x01, 0x01];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::GetConfigRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_device_reset_rsp() {
- let data = [0x40, 0x00, 0x00, 0x01, 0x00];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::DeviceResetRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_session_init_rsp() {
- let data = [0x41, 0x00, 0x00, 0x01, 0x11];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::SessionInitRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_session_deinit_rsp() {
- let data = [0x41, 0x01, 0x00, 0x01, 0x00];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::SessionDeinitRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_session_get_app_config_rsp() {
- let data = [0x41, 0x04, 0x00, 0x02, 0x01, 0x00];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::SessionGetAppConfigRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_session_set_app_config_rsp() {
- let data = [0x41, 0x03, 0x00, 0x04, 0x01, 0x01, 0x01, 0x00];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::SessionSetAppConfigRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_session_get_state_rsp() {
- let data = [0x41, 0x06, 0x00, 0x02, 0x00, 0x01];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::SessionGetStateRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_session_get_count_rsp() {
- let data = [0x41, 0x05, 0x00, 0x02, 0x00, 0x01];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::SessionGetCountRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_session_update_controller_multicast_list_rsp() {
- let data = [0x41, 0x07, 0x00, 0x01, 0x00];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((
- HalCallback::UciRsp(
- uci_hrcv::UciResponse::SessionUpdateControllerMulticastListRsp(_)
- ),
- _
- ))
- ));
- }
-
- #[tokio::test]
- async fn test_range_start_rsp() {
- let data = [0x42, 0x00, 0x00, 0x01, 0x00];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::RangeStartRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_range_stop_rsp() {
- let data = [0x42, 0x01, 0x00, 0x01, 0x00];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::RangeStopRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_android_set_country_code_rsp() {
- let data = [0x4c, 0x01, 0x00, 0x01, 0x00];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::AndroidSetCountryCodeRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_android_get_power_stats_rsp() {
- let data = [
- 0x4c, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::AndroidGetPowerStatsRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_raw_vendor_rsp_fragmented_packet() {
- let fragment_1 = [
- 0x59, 0x01, 0x00, 0xff, 0x81, 0x93, 0xf8, 0x56, 0x53, 0x74, 0x5d, 0xcf, 0x45, 0xfa,
- 0x34, 0xbd, 0xf1, 0x56, 0x53, 0x8f, 0x13, 0xff, 0x9b, 0xdd, 0xee, 0xaf, 0x0e, 0xff,
- 0x1e, 0x63, 0xb6, 0xd7, 0xd4, 0x7b, 0xb7, 0x78, 0x30, 0xc7, 0x92, 0xd0, 0x8a, 0x5e,
- 0xf0, 0x00, 0x1d, 0x05, 0xea, 0xf9, 0x56, 0xce, 0x8b, 0xbc, 0x8b, 0x1b, 0xc2, 0xd4,
- 0x2a, 0xb8, 0x14, 0x82, 0x8b, 0xed, 0x12, 0xe5, 0x83, 0xe6, 0xb0, 0xb8, 0xa0, 0xb9,
- 0xd0, 0x90, 0x6e, 0x09, 0x4e, 0x2e, 0x22, 0x38, 0x39, 0x03, 0x66, 0xf5, 0x95, 0x14,
- 0x1c, 0xd7, 0x60, 0xbf, 0x28, 0x58, 0x9d, 0x47, 0x18, 0x1a, 0x93, 0x59, 0xbb, 0x0d,
- 0x88, 0xf7, 0x7c, 0xce, 0x13, 0xa8, 0x2f, 0x3d, 0x0e, 0xd9, 0x5c, 0x19, 0x45, 0x5d,
- 0xe8, 0xc3, 0xe0, 0x3a, 0xf3, 0x71, 0x09, 0x6e, 0x73, 0x07, 0x96, 0xa9, 0x1f, 0xf4,
- 0x57, 0x84, 0x2e, 0x59, 0x6a, 0xf6, 0x90, 0x28, 0x47, 0xc1, 0x51, 0x7c, 0x59, 0x7e,
- 0x95, 0xfc, 0xa6, 0x4d, 0x1b, 0xe6, 0xfe, 0x97, 0xa0, 0x39, 0x91, 0xa8, 0x28, 0xc9,
- 0x1d, 0x7e, 0xfc, 0xec, 0x71, 0x1d, 0x43, 0x38, 0xcb, 0xbd, 0x50, 0xea, 0x02, 0xfd,
- 0x2c, 0x7a, 0xde, 0x06, 0xdd, 0x77, 0x69, 0x4d, 0x2f, 0x57, 0xf5, 0x4b, 0x97, 0x51,
- 0x58, 0x66, 0x7a, 0x8a, 0xcb, 0x7b, 0x91, 0x18, 0xbe, 0x4e, 0x94, 0xe4, 0xf1, 0xed,
- 0x52, 0x06, 0xa7, 0xe8, 0x6b, 0xe1, 0x8f, 0x4a, 0x06, 0xe8, 0x2c, 0x9f, 0xc7, 0xcb,
- 0xd2, 0x10, 0xb0, 0x0b, 0x71, 0x80, 0x2c, 0xd1, 0xf1, 0x03, 0xc2, 0x79, 0x7e, 0x7f,
- 0x70, 0xf4, 0x8c, 0xc9, 0xcf, 0x9f, 0xcf, 0xa2, 0x8e, 0x6a, 0xe4, 0x1a, 0x28, 0x05,
- 0xa8, 0xfe, 0x7d, 0xec, 0xd9, 0x5f, 0xa7, 0xd0, 0x29, 0x63, 0x1a, 0xba, 0x39, 0xf7,
- 0xfa, 0x5e, 0xff, 0xb8, 0x5a, 0xbd, 0x35,
- ];
- let fragment_2 = [
- 0x49, 0x01, 0x00, 0x91, 0xe7, 0x26, 0xfb, 0xc4, 0x48, 0x68, 0x42, 0x93, 0x23, 0x1f,
- 0x87, 0xf6, 0x12, 0x5e, 0x60, 0xc8, 0x6a, 0x9d, 0x98, 0xbb, 0xb2, 0xb0, 0x47, 0x2f,
- 0xaa, 0xa5, 0xce, 0xdb, 0x32, 0x88, 0x86, 0x0d, 0x6a, 0x5a, 0xfe, 0xc8, 0xda, 0xa1,
- 0xc0, 0x06, 0x37, 0x08, 0xda, 0x67, 0x49, 0x6a, 0xa7, 0x04, 0x62, 0x95, 0xf3, 0x1e,
- 0xcd, 0x71, 0x00, 0x99, 0x68, 0xb4, 0x03, 0xb3, 0x15, 0x64, 0x8b, 0xde, 0xbc, 0x8f,
- 0x41, 0x64, 0xdf, 0x34, 0x6e, 0xff, 0x48, 0xc8, 0xe2, 0xbf, 0x02, 0x15, 0xc5, 0xbc,
- 0x0f, 0xf8, 0xa1, 0x49, 0x91, 0x71, 0xdd, 0xb4, 0x37, 0x1c, 0xfa, 0x60, 0xcb, 0x0f,
- 0xce, 0x6a, 0x0e, 0x90, 0xaf, 0x14, 0x30, 0xf2, 0x5b, 0x21, 0x6f, 0x85, 0xd3, 0x1b,
- 0x89, 0xc9, 0xba, 0x3f, 0x07, 0x11, 0xbd, 0x56, 0xda, 0xdc, 0x88, 0xb4, 0xb0, 0x57,
- 0x0b, 0x0c, 0x44, 0xd9, 0xb9, 0xd2, 0x38, 0x4c, 0xb6, 0xff, 0x83, 0xfe, 0xc8, 0x65,
- 0xbc, 0x2a, 0x10, 0xed, 0x18, 0x62, 0xd2, 0x1b, 0x87,
- ];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result1 = uwb_client_callback.onUciMessage(&fragment_1).await;
- assert_eq!(result1, Ok(()));
- let result2 = uwb_client_callback.onUciMessage(&fragment_2).await;
- assert_eq!(result2, Ok(()));
- // One defragmented packet sent as response
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciRsp(uci_hrcv::UciResponse::RawVendorRsp(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_generic_error_ntf() {
- let data = [0x60, 0x07, 0x00, 0x01, 0x01];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciNtf(uci_hrcv::UciNotification::GenericError(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_device_status_ntf() {
- let data = [0x60, 0x01, 0x00, 0x01, 0x01];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciNtf(uci_hrcv::UciNotification::DeviceStatusNtf(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_session_status_ntf() {
- let data = [0x61, 0x02, 0x00, 0x06, 0x01, 0x02, 0x03, 0x04, 0x02, 0x21];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciNtf(uci_hrcv::UciNotification::SessionStatusNtf(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_session_update_controller_multicast_list_ntf() {
- let data = [0x61, 0x07, 0x00, 0x06, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((
- HalCallback::UciNtf(
- uci_hrcv::UciNotification::SessionUpdateControllerMulticastListNtf(_)
- ),
- _
- ))
- ));
- }
-
- #[tokio::test]
- async fn test_short_mac_two_way_range_data_ntf() {
- let data = [
- 0x62, 0x00, 0x00, 0x19, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x0a,
- 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00,
- ];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((
- HalCallback::UciNtf(uci_hrcv::UciNotification::ShortMacTwoWayRangeDataNtf(_)),
- _
- ))
- ));
- }
-
- #[tokio::test]
- async fn test_extended_mac_two_way_range_data_ntf() {
- let data = [
- 0x62, 0x00, 0x00, 0x19, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x0a,
- 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00,
- ];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((
- HalCallback::UciNtf(uci_hrcv::UciNotification::ExtendedMacTwoWayRangeDataNtf(_)),
- _
- ))
- ));
- }
-
- #[tokio::test]
- async fn test_raw_vendor_ntf_fragmented_packet() {
- let fragment_1 = [
- 0x79, 0x01, 0x00, 0xff, 0x81, 0x93, 0xf8, 0x56, 0x53, 0x74, 0x5d, 0xcf, 0x45, 0xfa,
- 0x34, 0xbd, 0xf1, 0x56, 0x53, 0x8f, 0x13, 0xff, 0x9b, 0xdd, 0xee, 0xaf, 0x0e, 0xff,
- 0x1e, 0x63, 0xb6, 0xd7, 0xd4, 0x7b, 0xb7, 0x78, 0x30, 0xc7, 0x92, 0xd0, 0x8a, 0x5e,
- 0xf0, 0x00, 0x1d, 0x05, 0xea, 0xf9, 0x56, 0xce, 0x8b, 0xbc, 0x8b, 0x1b, 0xc2, 0xd4,
- 0x2a, 0xb8, 0x14, 0x82, 0x8b, 0xed, 0x12, 0xe5, 0x83, 0xe6, 0xb0, 0xb8, 0xa0, 0xb9,
- 0xd0, 0x90, 0x6e, 0x09, 0x4e, 0x2e, 0x22, 0x38, 0x39, 0x03, 0x66, 0xf5, 0x95, 0x14,
- 0x1c, 0xd7, 0x60, 0xbf, 0x28, 0x58, 0x9d, 0x47, 0x18, 0x1a, 0x93, 0x59, 0xbb, 0x0d,
- 0x88, 0xf7, 0x7c, 0xce, 0x13, 0xa8, 0x2f, 0x3d, 0x0e, 0xd9, 0x5c, 0x19, 0x45, 0x5d,
- 0xe8, 0xc3, 0xe0, 0x3a, 0xf3, 0x71, 0x09, 0x6e, 0x73, 0x07, 0x96, 0xa9, 0x1f, 0xf4,
- 0x57, 0x84, 0x2e, 0x59, 0x6a, 0xf6, 0x90, 0x28, 0x47, 0xc1, 0x51, 0x7c, 0x59, 0x7e,
- 0x95, 0xfc, 0xa6, 0x4d, 0x1b, 0xe6, 0xfe, 0x97, 0xa0, 0x39, 0x91, 0xa8, 0x28, 0xc9,
- 0x1d, 0x7e, 0xfc, 0xec, 0x71, 0x1d, 0x43, 0x38, 0xcb, 0xbd, 0x50, 0xea, 0x02, 0xfd,
- 0x2c, 0x7a, 0xde, 0x06, 0xdd, 0x77, 0x69, 0x4d, 0x2f, 0x57, 0xf5, 0x4b, 0x97, 0x51,
- 0x58, 0x66, 0x7a, 0x8a, 0xcb, 0x7b, 0x91, 0x18, 0xbe, 0x4e, 0x94, 0xe4, 0xf1, 0xed,
- 0x52, 0x06, 0xa7, 0xe8, 0x6b, 0xe1, 0x8f, 0x4a, 0x06, 0xe8, 0x2c, 0x9f, 0xc7, 0xcb,
- 0xd2, 0x10, 0xb0, 0x0b, 0x71, 0x80, 0x2c, 0xd1, 0xf1, 0x03, 0xc2, 0x79, 0x7e, 0x7f,
- 0x70, 0xf4, 0x8c, 0xc9, 0xcf, 0x9f, 0xcf, 0xa2, 0x8e, 0x6a, 0xe4, 0x1a, 0x28, 0x05,
- 0xa8, 0xfe, 0x7d, 0xec, 0xd9, 0x5f, 0xa7, 0xd0, 0x29, 0x63, 0x1a, 0xba, 0x39, 0xf7,
- 0xfa, 0x5e, 0xff, 0xb8, 0x5a, 0xbd, 0x35,
- ];
- let fragment_2 = [
- 0x69, 0x01, 0x00, 0x91, 0xe7, 0x26, 0xfb, 0xc4, 0x48, 0x68, 0x42, 0x93, 0x23, 0x1f,
- 0x87, 0xf6, 0x12, 0x5e, 0x60, 0xc8, 0x6a, 0x9d, 0x98, 0xbb, 0xb2, 0xb0, 0x47, 0x2f,
- 0xaa, 0xa5, 0xce, 0xdb, 0x32, 0x88, 0x86, 0x0d, 0x6a, 0x5a, 0xfe, 0xc8, 0xda, 0xa1,
- 0xc0, 0x06, 0x37, 0x08, 0xda, 0x67, 0x49, 0x6a, 0xa7, 0x04, 0x62, 0x95, 0xf3, 0x1e,
- 0xcd, 0x71, 0x00, 0x99, 0x68, 0xb4, 0x03, 0xb3, 0x15, 0x64, 0x8b, 0xde, 0xbc, 0x8f,
- 0x41, 0x64, 0xdf, 0x34, 0x6e, 0xff, 0x48, 0xc8, 0xe2, 0xbf, 0x02, 0x15, 0xc5, 0xbc,
- 0x0f, 0xf8, 0xa1, 0x49, 0x91, 0x71, 0xdd, 0xb4, 0x37, 0x1c, 0xfa, 0x60, 0xcb, 0x0f,
- 0xce, 0x6a, 0x0e, 0x90, 0xaf, 0x14, 0x30, 0xf2, 0x5b, 0x21, 0x6f, 0x85, 0xd3, 0x1b,
- 0x89, 0xc9, 0xba, 0x3f, 0x07, 0x11, 0xbd, 0x56, 0xda, 0xdc, 0x88, 0xb4, 0xb0, 0x57,
- 0x0b, 0x0c, 0x44, 0xd9, 0xb9, 0xd2, 0x38, 0x4c, 0xb6, 0xff, 0x83, 0xfe, 0xc8, 0x65,
- 0xbc, 0x2a, 0x10, 0xed, 0x18, 0x62, 0xd2, 0x1b, 0x87,
- ];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result1 = uwb_client_callback.onUciMessage(&fragment_1).await;
- assert_eq!(result1, Ok(()));
- let result2 = uwb_client_callback.onUciMessage(&fragment_2).await;
- assert_eq!(result2, Ok(()));
- // One defragmented packet sent as response
- let response = rsp_receiver.recv().await;
- assert!(matches!(
- response,
- Some((HalCallback::UciNtf(uci_hrcv::UciNotification::RawVendorNtf(_)), _))
- ));
- }
-
- #[tokio::test]
- async fn test_on_uci_message_bad() {
- let data = [
- 0x42, 0x02, 0x00, 0x0b, 0x01, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01,
- 0x0a,
- ];
- let (mut rsp_receiver, uwb_client_callback) = setup_client_callback();
- let result = uwb_client_callback.onUciMessage(&data).await;
- assert_eq!(result, Ok(()));
- let response = rsp_receiver.try_recv();
- assert!(response.is_err());
- }
-
- async fn setup_adaptation_impl(config_fn: impl Fn(&MockHal)) -> Result<UwbAdaptationImpl> {
- // TODO: Remove this once we call it somewhere real.
- logger::init(
- logger::Config::default()
- .with_tag_on_device("uwb_test")
- .with_min_level(log::Level::Debug),
- );
- let (rsp_sender, _) = mpsc::unbounded_channel::<(HalCallback, _)>();
- let mock_hal = MockHal::new(None);
- config_fn(&mock_hal);
-
- UwbAdaptationImpl::new_with_args(
- rsp_sender,
- HashMap::from([(
- String::from("default"),
- binder::Strong::new(Box::new(mock_hal) as Box<dyn IUwbChipAsync<_> + 'static>),
- )]),
- Arc::new(Mutex::new(Vec::from([DeathRecipient::new(|| {})]))),
- )
- .await
- }
-
- #[tokio::test]
- async fn test_send_uci_message() {
- let cmd: UciCommandPacket = GetDeviceInfoCmdBuilder {}.build().into();
- let adaptation_impl = setup_adaptation_impl(|mock_hal| {
- let cmd_packet: UciPacketPacket = cmd.clone().into();
- let mut cmd_frag_packets: Vec<UciPacketHalPacket> = cmd_packet.into();
- let cmd_frag_data = cmd_frag_packets.pop().unwrap().to_vec();
- let cmd_frag_data_len = cmd_frag_data.len();
- mock_hal.expect_send_uci_message(
- cmd_frag_data,
- None,
- Ok(cmd_frag_data_len.try_into().unwrap()),
- );
- })
- .await
- .unwrap();
- adaptation_impl.send_uci_message(cmd, "default").await.unwrap();
- }
-
- #[tokio::test]
- async fn test_send_uci_message_fragmented_packet() {
- let (rsp_sender, _) = mpsc::unbounded_channel::<(HalCallback, _)>();
- let mock_hal = MockHal::new(None);
-
- let cmd_payload: [u8; 400] = [
- 0x81, 0x93, 0xf8, 0x56, 0x53, 0x74, 0x5d, 0xcf, 0x45, 0xfa, 0x34, 0xbd, 0xf1, 0x56,
- 0x53, 0x8f, 0x13, 0xff, 0x9b, 0xdd, 0xee, 0xaf, 0x0e, 0xff, 0x1e, 0x63, 0xb6, 0xd7,
- 0xd4, 0x7b, 0xb7, 0x78, 0x30, 0xc7, 0x92, 0xd0, 0x8a, 0x5e, 0xf0, 0x00, 0x1d, 0x05,
- 0xea, 0xf9, 0x56, 0xce, 0x8b, 0xbc, 0x8b, 0x1b, 0xc2, 0xd4, 0x2a, 0xb8, 0x14, 0x82,
- 0x8b, 0xed, 0x12, 0xe5, 0x83, 0xe6, 0xb0, 0xb8, 0xa0, 0xb9, 0xd0, 0x90, 0x6e, 0x09,
- 0x4e, 0x2e, 0x22, 0x38, 0x39, 0x03, 0x66, 0xf5, 0x95, 0x14, 0x1c, 0xd7, 0x60, 0xbf,
- 0x28, 0x58, 0x9d, 0x47, 0x18, 0x1a, 0x93, 0x59, 0xbb, 0x0d, 0x88, 0xf7, 0x7c, 0xce,
- 0x13, 0xa8, 0x2f, 0x3d, 0x0e, 0xd9, 0x5c, 0x19, 0x45, 0x5d, 0xe8, 0xc3, 0xe0, 0x3a,
- 0xf3, 0x71, 0x09, 0x6e, 0x73, 0x07, 0x96, 0xa9, 0x1f, 0xf4, 0x57, 0x84, 0x2e, 0x59,
- 0x6a, 0xf6, 0x90, 0x28, 0x47, 0xc1, 0x51, 0x7c, 0x59, 0x7e, 0x95, 0xfc, 0xa6, 0x4d,
- 0x1b, 0xe6, 0xfe, 0x97, 0xa0, 0x39, 0x91, 0xa8, 0x28, 0xc9, 0x1d, 0x7e, 0xfc, 0xec,
- 0x71, 0x1d, 0x43, 0x38, 0xcb, 0xbd, 0x50, 0xea, 0x02, 0xfd, 0x2c, 0x7a, 0xde, 0x06,
- 0xdd, 0x77, 0x69, 0x4d, 0x2f, 0x57, 0xf5, 0x4b, 0x97, 0x51, 0x58, 0x66, 0x7a, 0x8a,
- 0xcb, 0x7b, 0x91, 0x18, 0xbe, 0x4e, 0x94, 0xe4, 0xf1, 0xed, 0x52, 0x06, 0xa7, 0xe8,
- 0x6b, 0xe1, 0x8f, 0x4a, 0x06, 0xe8, 0x2c, 0x9f, 0xc7, 0xcb, 0xd2, 0x10, 0xb0, 0x0b,
- 0x71, 0x80, 0x2c, 0xd1, 0xf1, 0x03, 0xc2, 0x79, 0x7e, 0x7f, 0x70, 0xf4, 0x8c, 0xc9,
- 0xcf, 0x9f, 0xcf, 0xa2, 0x8e, 0x6a, 0xe4, 0x1a, 0x28, 0x05, 0xa8, 0xfe, 0x7d, 0xec,
- 0xd9, 0x5f, 0xa7, 0xd0, 0x29, 0x63, 0x1a, 0xba, 0x39, 0xf7, 0xfa, 0x5e, 0xff, 0xb8,
- 0x5a, 0xbd, 0x35, 0xe7, 0x26, 0xfb, 0xc4, 0x48, 0x68, 0x42, 0x93, 0x23, 0x1f, 0x87,
- 0xf6, 0x12, 0x5e, 0x60, 0xc8, 0x6a, 0x9d, 0x98, 0xbb, 0xb2, 0xb0, 0x47, 0x2f, 0xaa,
- 0xa5, 0xce, 0xdb, 0x32, 0x88, 0x86, 0x0d, 0x6a, 0x5a, 0xfe, 0xc8, 0xda, 0xa1, 0xc0,
- 0x06, 0x37, 0x08, 0xda, 0x67, 0x49, 0x6a, 0xa7, 0x04, 0x62, 0x95, 0xf3, 0x1e, 0xcd,
- 0x71, 0x00, 0x99, 0x68, 0xb4, 0x03, 0xb3, 0x15, 0x64, 0x8b, 0xde, 0xbc, 0x8f, 0x41,
- 0x64, 0xdf, 0x34, 0x6e, 0xff, 0x48, 0xc8, 0xe2, 0xbf, 0x02, 0x15, 0xc5, 0xbc, 0x0f,
- 0xf8, 0xa1, 0x49, 0x91, 0x71, 0xdd, 0xb4, 0x37, 0x1c, 0xfa, 0x60, 0xcb, 0x0f, 0xce,
- 0x6a, 0x0e, 0x90, 0xaf, 0x14, 0x30, 0xf2, 0x5b, 0x21, 0x6f, 0x85, 0xd3, 0x1b, 0x89,
- 0xc9, 0xba, 0x3f, 0x07, 0x11, 0xbd, 0x56, 0xda, 0xdc, 0x88, 0xb4, 0xb0, 0x57, 0x0b,
- 0x0c, 0x44, 0xd9, 0xb9, 0xd2, 0x38, 0x4c, 0xb6, 0xff, 0x83, 0xfe, 0xc8, 0x65, 0xbc,
- 0x2a, 0x10, 0xed, 0x18, 0x62, 0xd2, 0x1b, 0x87,
- ];
- let cmd: UciCommandPacket = UciVendor_9_CommandBuilder {
- opcode: 1,
- payload: Some(Bytes::from(cmd_payload.to_vec())),
- }
- .build()
- .into();
-
- let cmd_frag_data_1 = [
- 0x39, 0x01, 0x00, 0xff, 0x81, 0x93, 0xf8, 0x56, 0x53, 0x74, 0x5d, 0xcf, 0x45, 0xfa,
- 0x34, 0xbd, 0xf1, 0x56, 0x53, 0x8f, 0x13, 0xff, 0x9b, 0xdd, 0xee, 0xaf, 0x0e, 0xff,
- 0x1e, 0x63, 0xb6, 0xd7, 0xd4, 0x7b, 0xb7, 0x78, 0x30, 0xc7, 0x92, 0xd0, 0x8a, 0x5e,
- 0xf0, 0x00, 0x1d, 0x05, 0xea, 0xf9, 0x56, 0xce, 0x8b, 0xbc, 0x8b, 0x1b, 0xc2, 0xd4,
- 0x2a, 0xb8, 0x14, 0x82, 0x8b, 0xed, 0x12, 0xe5, 0x83, 0xe6, 0xb0, 0xb8, 0xa0, 0xb9,
- 0xd0, 0x90, 0x6e, 0x09, 0x4e, 0x2e, 0x22, 0x38, 0x39, 0x03, 0x66, 0xf5, 0x95, 0x14,
- 0x1c, 0xd7, 0x60, 0xbf, 0x28, 0x58, 0x9d, 0x47, 0x18, 0x1a, 0x93, 0x59, 0xbb, 0x0d,
- 0x88, 0xf7, 0x7c, 0xce, 0x13, 0xa8, 0x2f, 0x3d, 0x0e, 0xd9, 0x5c, 0x19, 0x45, 0x5d,
- 0xe8, 0xc3, 0xe0, 0x3a, 0xf3, 0x71, 0x09, 0x6e, 0x73, 0x07, 0x96, 0xa9, 0x1f, 0xf4,
- 0x57, 0x84, 0x2e, 0x59, 0x6a, 0xf6, 0x90, 0x28, 0x47, 0xc1, 0x51, 0x7c, 0x59, 0x7e,
- 0x95, 0xfc, 0xa6, 0x4d, 0x1b, 0xe6, 0xfe, 0x97, 0xa0, 0x39, 0x91, 0xa8, 0x28, 0xc9,
- 0x1d, 0x7e, 0xfc, 0xec, 0x71, 0x1d, 0x43, 0x38, 0xcb, 0xbd, 0x50, 0xea, 0x02, 0xfd,
- 0x2c, 0x7a, 0xde, 0x06, 0xdd, 0x77, 0x69, 0x4d, 0x2f, 0x57, 0xf5, 0x4b, 0x97, 0x51,
- 0x58, 0x66, 0x7a, 0x8a, 0xcb, 0x7b, 0x91, 0x18, 0xbe, 0x4e, 0x94, 0xe4, 0xf1, 0xed,
- 0x52, 0x06, 0xa7, 0xe8, 0x6b, 0xe1, 0x8f, 0x4a, 0x06, 0xe8, 0x2c, 0x9f, 0xc7, 0xcb,
- 0xd2, 0x10, 0xb0, 0x0b, 0x71, 0x80, 0x2c, 0xd1, 0xf1, 0x03, 0xc2, 0x79, 0x7e, 0x7f,
- 0x70, 0xf4, 0x8c, 0xc9, 0xcf, 0x9f, 0xcf, 0xa2, 0x8e, 0x6a, 0xe4, 0x1a, 0x28, 0x05,
- 0xa8, 0xfe, 0x7d, 0xec, 0xd9, 0x5f, 0xa7, 0xd0, 0x29, 0x63, 0x1a, 0xba, 0x39, 0xf7,
- 0xfa, 0x5e, 0xff, 0xb8, 0x5a, 0xbd, 0x35,
- ];
- let cmd_frag_data_len_1 = cmd_frag_data_1.len();
-
- let cmd_frag_data_2 = [
- 0x29, 0x01, 0x00, 0x91, 0xe7, 0x26, 0xfb, 0xc4, 0x48, 0x68, 0x42, 0x93, 0x23, 0x1f,
- 0x87, 0xf6, 0x12, 0x5e, 0x60, 0xc8, 0x6a, 0x9d, 0x98, 0xbb, 0xb2, 0xb0, 0x47, 0x2f,
- 0xaa, 0xa5, 0xce, 0xdb, 0x32, 0x88, 0x86, 0x0d, 0x6a, 0x5a, 0xfe, 0xc8, 0xda, 0xa1,
- 0xc0, 0x06, 0x37, 0x08, 0xda, 0x67, 0x49, 0x6a, 0xa7, 0x04, 0x62, 0x95, 0xf3, 0x1e,
- 0xcd, 0x71, 0x00, 0x99, 0x68, 0xb4, 0x03, 0xb3, 0x15, 0x64, 0x8b, 0xde, 0xbc, 0x8f,
- 0x41, 0x64, 0xdf, 0x34, 0x6e, 0xff, 0x48, 0xc8, 0xe2, 0xbf, 0x02, 0x15, 0xc5, 0xbc,
- 0x0f, 0xf8, 0xa1, 0x49, 0x91, 0x71, 0xdd, 0xb4, 0x37, 0x1c, 0xfa, 0x60, 0xcb, 0x0f,
- 0xce, 0x6a, 0x0e, 0x90, 0xaf, 0x14, 0x30, 0xf2, 0x5b, 0x21, 0x6f, 0x85, 0xd3, 0x1b,
- 0x89, 0xc9, 0xba, 0x3f, 0x07, 0x11, 0xbd, 0x56, 0xda, 0xdc, 0x88, 0xb4, 0xb0, 0x57,
- 0x0b, 0x0c, 0x44, 0xd9, 0xb9, 0xd2, 0x38, 0x4c, 0xb6, 0xff, 0x83, 0xfe, 0xc8, 0x65,
- 0xbc, 0x2a, 0x10, 0xed, 0x18, 0x62, 0xd2, 0x1b, 0x87,
- ];
- let cmd_frag_data_len_2 = cmd_frag_data_2.len();
-
- mock_hal.expect_send_uci_message(
- cmd_frag_data_1.to_vec(),
- None,
- Ok(cmd_frag_data_len_1.try_into().unwrap()),
- );
- mock_hal.expect_send_uci_message(
- cmd_frag_data_2.to_vec(),
- None,
- Ok(cmd_frag_data_len_2.try_into().unwrap()),
- );
- let adaptation_impl = UwbAdaptationImpl::new_with_args(
- rsp_sender,
- HashMap::from([(
- String::from("default"),
- binder::Strong::new(Box::new(mock_hal) as Box<dyn IUwbChipAsync<_> + 'static>),
- )]),
- Arc::new(Mutex::new(Vec::from([DeathRecipient::new(|| {})]))),
- )
- .await
- .unwrap();
- adaptation_impl.send_uci_message(cmd, "default").await.unwrap();
- }
-}
diff --git a/src/rust/error.rs b/src/rust/error.rs
deleted file mode 100644
index cc031f9..0000000
--- a/src/rust/error.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-use crate::uci::uci_hrcv::UciResponse;
-use crate::uci::{HalCallback, JNICommand};
-use android_hardware_uwb::aidl::android::hardware::uwb::UwbStatus::UwbStatus;
-use std::array::TryFromSliceError;
-use std::option::Option;
-use tokio::sync::{mpsc, oneshot};
-use uwb_uci_packets::StatusCode;
-
-#[derive(Debug, thiserror::Error)]
-pub enum UwbErr {
- #[error("StatusCoode error: {0:?}")]
- StatusCode(StatusCode),
- #[error("UWBStatus error: {0:?}")]
- UwbStatus(UwbStatus),
- #[error("Binder error: {0}")]
- Binder(#[from] binder::Status),
- #[error("JNI error: {0}")]
- Jni(#[from] jni::errors::Error),
- #[error("IO error: {0}")]
- Io(#[from] std::io::Error),
- #[error("SendError for JNICommand: {0}")]
- SendJNICommand(
- #[from] mpsc::error::SendError<(JNICommand, Option<oneshot::Sender<UciResponse>>, String)>,
- ),
- #[error("SendError for HalCallback: {0}")]
- SendHalCallback(#[from] mpsc::error::SendError<HalCallback>),
- #[error("RecvError: {0}")]
- RecvError(#[from] oneshot::error::RecvError),
- #[error("Could not parse: {0}")]
- Parse(#[from] uwb_uci_packets::Error),
- #[error("Could not specialize: {0:?}")]
- Specialize(Vec<u8>),
- #[error("Could not convert: {0:?}")]
- ConvertToArray(#[from] TryFromSliceError),
- #[error("The dispatcher does not exist")]
- NoneDispatcher,
- #[error("Invalid args")]
- InvalidArgs,
- #[error("Exit")]
- Exit,
- #[error("Could not connect to HAL")]
- HalUnavailable(#[from] binder::StatusCode),
- #[error("Could not convert")]
- ConvertToEnum(#[from] std::num::TryFromIntError),
- #[error("Unknown error")]
- Undefined,
-}
-
-impl UwbErr {
- pub fn failed() -> Self {
- UwbErr::UwbStatus(UwbStatus::FAILED)
- }
-
- pub fn refused() -> Self {
- UwbErr::UwbStatus(UwbStatus::REFUSED)
- }
-}
diff --git a/src/rust/event_manager/mock_event_manager.rs b/src/rust/event_manager/mock_event_manager.rs
deleted file mode 100644
index 03d940a..0000000
--- a/src/rust/event_manager/mock_event_manager.rs
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//! MockEventManager
-
-use crate::event_manager::EventManager;
-use jni::errors::{Error, JniError, Result};
-use log::warn;
-use std::collections::VecDeque;
-use std::sync::Mutex;
-use uwb_uci_packets::{
- DeviceStatusNtfPacket, ExtendedMacTwoWayRangeDataNtfPacket, GenericErrorPacket,
- SessionStatusNtfPacket, SessionUpdateControllerMulticastListNtfPacket,
- ShortMacTwoWayRangeDataNtfPacket, UciNotificationPacket,
-};
-
-#[cfg(any(test, fuzzing))]
-enum ExpectedCall {
- DeviceStatus { out: Result<()> },
- CoreGenericError { out: Result<()> },
- SessionStatus { out: Result<()> },
- ShortRangeData { out: Result<()> },
- ExtendedRangeData { out: Result<()> },
- SessionUpdateControllerMulticastList { out: Result<()> },
- VendorUci { out: Result<()> },
-}
-
-#[cfg(any(test, fuzzing))]
-#[derive(Default)]
-pub struct MockEventManager {
- expected_calls: Mutex<VecDeque<ExpectedCall>>,
-}
-
-#[cfg(any(test, fuzzing))]
-impl MockEventManager {
- pub fn new() -> Self {
- Default::default()
- }
-
- pub fn expect_device_status_notification_received(&mut self, out: Result<()>) {
- self.add_expected_call(ExpectedCall::DeviceStatus { out });
- }
-
- pub fn expect_core_generic_error_notification_received(&mut self, out: Result<()>) {
- self.add_expected_call(ExpectedCall::CoreGenericError { out });
- }
-
- pub fn expect_session_status_notification_received(&mut self, out: Result<()>) {
- self.add_expected_call(ExpectedCall::SessionStatus { out });
- }
-
- pub fn expect_short_range_data_notification_received(&mut self, out: Result<()>) {
- self.add_expected_call(ExpectedCall::ShortRangeData { out });
- }
-
- pub fn expect_extended_range_data_notification_received(&mut self, out: Result<()>) {
- self.add_expected_call(ExpectedCall::ExtendedRangeData { out });
- }
-
- pub fn expect_session_update_controller_multicast_list_notification_received(
- &mut self,
- out: Result<()>,
- ) {
- self.add_expected_call(ExpectedCall::SessionUpdateControllerMulticastList { out });
- }
-
- pub fn expect_vendor_uci_notification_received(&mut self, out: Result<()>) {
- self.add_expected_call(ExpectedCall::VendorUci { out });
- }
-
- fn add_expected_call(&mut self, call: ExpectedCall) {
- self.expected_calls.lock().unwrap().push_back(call);
- }
-
- fn unwrap_out(&self, out: Option<Result<()>>, method_name: &str) -> Result<()> {
- out.unwrap_or_else(move || {
- warn!("unpected {:?}() called", method_name);
- Err(Error::JniCall(JniError::Unknown))
- })
- }
-
- pub fn clear_expected_calls(&self) {
- self.expected_calls.lock().unwrap().clear();
- }
-}
-
-#[cfg(any(test, fuzzing))]
-impl Drop for MockEventManager {
- fn drop(&mut self) {
- assert!(self.expected_calls.lock().unwrap().is_empty());
- }
-}
-#[cfg(any(test, fuzzing))]
-impl EventManager for MockEventManager {
- fn device_status_notification_received(
- &self,
- _data: DeviceStatusNtfPacket,
- _chip_id: &str,
- ) -> Result<()> {
- let out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::DeviceStatus { out }) => Some(out),
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- self.unwrap_out(out, "device_status_notification_received")
- }
-
- fn core_generic_error_notification_received(
- &self,
- _data: GenericErrorPacket,
- _chip_id: &str,
- ) -> Result<()> {
- let out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::CoreGenericError { out }) => Some(out),
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- self.unwrap_out(out, "core_generic_error_notification_received")
- }
-
- fn session_status_notification_received(&self, _data: SessionStatusNtfPacket) -> Result<()> {
- let out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::SessionStatus { out }) => Some(out),
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- self.unwrap_out(out, "session_status_notification_received")
- }
-
- fn short_range_data_notification_received(
- &self,
- _data: ShortMacTwoWayRangeDataNtfPacket,
- ) -> Result<()> {
- let out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::ShortRangeData { out }) => Some(out),
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- self.unwrap_out(out, "short_range_data_notification_received")
- }
- fn extended_range_data_notification_received(
- &self,
- _data: ExtendedMacTwoWayRangeDataNtfPacket,
- ) -> Result<()> {
- let out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::ExtendedRangeData { out }) => Some(out),
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- self.unwrap_out(out, "extended_range_data_notification_received")
- }
-
- fn session_update_controller_multicast_list_notification_received(
- &self,
- _data: SessionUpdateControllerMulticastListNtfPacket,
- ) -> Result<()> {
- let out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::SessionUpdateControllerMulticastList { out }) => Some(out),
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- self.unwrap_out(out, "session_update_controller_multicast_list_notification_received")
- }
-
- fn vendor_uci_notification_received(
- &self,
- _data: UciNotificationPacket,
- _chip_id: &str,
- ) -> Result<()> {
- let out = {
- let mut expected_calls = self.expected_calls.lock().unwrap();
- match expected_calls.pop_front() {
- Some(ExpectedCall::VendorUci { out }) => Some(out),
- Some(call) => {
- expected_calls.push_front(call);
- None
- }
- None => None,
- }
- };
-
- self.unwrap_out(out, "vendor_uci_notification_received")
- }
-}
diff --git a/src/rust/event_manager/mod.rs b/src/rust/event_manager/mod.rs
deleted file mode 100644
index 226083a..0000000
--- a/src/rust/event_manager/mod.rs
+++ /dev/null
@@ -1,756 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-use jni::errors::{Error, JniError, Result};
-use jni::objects::{GlobalRef, JClass, JObject, JValue, JValue::Void};
-use jni::signature::JavaType;
-use jni::sys::jobjectArray;
-use jni::{AttachGuard, JNIEnv, JavaVM};
-use log::error;
-use num_traits::ToPrimitive;
-use std::convert::TryInto;
-use std::vec::Vec;
-use uwb_uci_packets::{
- DeviceStatusNtfPacket, ExtendedAddressTwoWayRangingMeasurement,
- ExtendedMacTwoWayRangeDataNtfPacket, GenericErrorPacket, Packet, RangeDataNtfPacket,
- SessionStatusNtfPacket, SessionUpdateControllerMulticastListNtfPacket,
- ShortAddressTwoWayRangingMeasurement, ShortMacTwoWayRangeDataNtfPacket, UciNotificationChild,
- UciNotificationPacket, UciVendor_9_NotificationChild, UciVendor_A_NotificationChild,
- UciVendor_B_NotificationChild, UciVendor_E_NotificationChild, UciVendor_F_NotificationChild,
-};
-
-const UWB_RANGING_DATA_CLASS: &str = "com/android/server/uwb/data/UwbRangingData";
-const UWB_TWO_WAY_MEASUREMENT_CLASS: &str = "com/android/server/uwb/data/UwbTwoWayMeasurement";
-const MULTICAST_LIST_UPDATE_STATUS_CLASS: &str =
- "com/android/server/uwb/data/UwbMulticastListUpdateStatus";
-const SHORT_MAC_ADDRESS_LEN: usize = 2;
-const EXTENDED_MAC_ADDRESS_LEN: usize = 8;
-
-// TODO: Reconsider the best way to cache the JNIEnv. We currently attach and detach for every
-// call, which the documentation warns could be expensive. We could attach the thread permanently,
-// but that would not allow us to detach when we drop this structure. We could cache the
-// AttachGuard in the EventManager, but it is not Send, so we should wait to see how this is used
-// and how expensive the current approach is. We can call JavaVM's get_env method if we're already
-// attached.
-
-// TODO: We could consider caching the method ids rather than recomputing them each time at the cost
-// of less safety.
-
-pub trait EventManager {
- fn device_status_notification_received(
- &self,
- data: DeviceStatusNtfPacket,
- chip_id: &str,
- ) -> Result<()>;
- fn core_generic_error_notification_received(
- &self,
- data: GenericErrorPacket,
- chip_id: &str,
- ) -> Result<()>;
- fn session_status_notification_received(&self, data: SessionStatusNtfPacket) -> Result<()>;
- fn short_range_data_notification_received(
- &self,
- data: ShortMacTwoWayRangeDataNtfPacket,
- ) -> Result<()>;
- fn extended_range_data_notification_received(
- &self,
- data: ExtendedMacTwoWayRangeDataNtfPacket,
- ) -> Result<()>;
- fn session_update_controller_multicast_list_notification_received(
- &self,
- data: SessionUpdateControllerMulticastListNtfPacket,
- ) -> Result<()>;
- fn vendor_uci_notification_received(
- &self,
- data: UciNotificationPacket,
- chip_id: &str,
- ) -> Result<()>;
-}
-
-// Manages calling Java callbacks through the JNI.
-pub struct EventManagerImpl {
- jvm: JavaVM,
- obj: GlobalRef,
- // cache used to lookup uwb classes in callback.
- class_loader_obj: GlobalRef,
-}
-
-impl EventManager for EventManagerImpl {
- fn device_status_notification_received(
- &self,
- data: DeviceStatusNtfPacket,
- chip_id: &str,
- ) -> Result<()> {
- let env = self.jvm.attach_current_thread()?;
- let result = self.handle_device_status_notification_received(&env, data, chip_id);
- self.clear_exception(env);
- result
- }
-
- fn core_generic_error_notification_received(
- &self,
- data: GenericErrorPacket,
- chip_id: &str,
- ) -> Result<()> {
- let env = self.jvm.attach_current_thread()?;
- let result = self.handle_core_generic_error_notification_received(&env, data, chip_id);
- self.clear_exception(env);
- result
- }
-
- fn session_status_notification_received(&self, data: SessionStatusNtfPacket) -> Result<()> {
- let env = self.jvm.attach_current_thread()?;
- let result = self.handle_session_status_notification_received(&env, data);
- self.clear_exception(env);
- result
- }
-
- fn short_range_data_notification_received(
- &self,
- data: ShortMacTwoWayRangeDataNtfPacket,
- ) -> Result<()> {
- let env = self.jvm.attach_current_thread()?;
- let result = self.handle_short_range_data_notification_received(&env, data);
- self.clear_exception(env);
- result
- }
-
- fn extended_range_data_notification_received(
- &self,
- data: ExtendedMacTwoWayRangeDataNtfPacket,
- ) -> Result<()> {
- let env = self.jvm.attach_current_thread()?;
- let result = self.handle_extended_range_data_notification_received(&env, data);
- self.clear_exception(env);
- result
- }
-
- fn session_update_controller_multicast_list_notification_received(
- &self,
- data: SessionUpdateControllerMulticastListNtfPacket,
- ) -> Result<()> {
- let env = self.jvm.attach_current_thread()?;
- let result =
- self.handle_session_update_controller_multicast_list_notification_received(&env, data);
- self.clear_exception(env);
- result
- }
- fn vendor_uci_notification_received(
- &self,
- data: UciNotificationPacket,
- chip_id: &str,
- ) -> Result<()> {
- let env = self.jvm.attach_current_thread()?;
- let result = self.handle_vendor_uci_notification_received(&env, data, chip_id);
- self.clear_exception(env);
- result
- }
-}
-
-impl EventManagerImpl {
- /// Creates a new EventManagerImpl.
- pub fn new(env: JNIEnv, obj: JObject) -> Result<Self> {
- let jvm = env.get_java_vm()?;
- let obj = env.new_global_ref(obj)?;
- let class_loader_obj = EventManagerImpl::get_classloader_obj(&env)?;
- let class_loader_obj = env.new_global_ref(class_loader_obj)?;
- Ok(EventManagerImpl { jvm, obj, class_loader_obj })
- }
-
- fn get_classloader_obj<'a>(env: &'a JNIEnv) -> Result<JObject<'a>> {
- // Use UwbRangingData class to find the classloader used by the java service.
- let ranging_data_class = env.find_class(&UWB_RANGING_DATA_CLASS)?;
- let ranging_data_class_class = env.get_object_class(ranging_data_class)?;
- let get_class_loader_method = env.get_method_id(
- ranging_data_class_class,
- "getClassLoader",
- "()Ljava/lang/ClassLoader;",
- )?;
- let class_loader = env.call_method_unchecked(
- ranging_data_class,
- get_class_loader_method,
- JavaType::Object("java/lang/ClassLoader".into()),
- &[Void],
- )?;
- class_loader.l()
- }
-
- fn find_class<'a>(&'a self, env: &'a JNIEnv, class_name: &'a str) -> Result<JClass<'a>> {
- let class_value = env.call_method(
- self.class_loader_obj.as_obj(),
- "findClass",
- "(Ljava/lang/String;)Ljava/lang/Class;",
- &[JValue::Object(JObject::from(env.new_string(class_name)?))],
- )?;
- class_value.l().map(JClass::from)
- }
-
- fn handle_device_status_notification_received(
- &self,
- env: &JNIEnv,
- data: DeviceStatusNtfPacket,
- chip_id: &str,
- ) -> Result<()> {
- let state = data.get_device_state().to_i32().ok_or_else(|| {
- error!("Failed converting device_state to i32");
- Error::JniCall(JniError::Unknown)
- })?;
- env.call_method(
- self.obj.as_obj(),
- "onDeviceStatusNotificationReceived",
- "(ILjava/lang/String;)V",
- &[JValue::Int(state), JValue::Object(JObject::from(env.new_string(chip_id)?))],
- )
- .map(|_| ()) // drop void method return
- }
-
- fn handle_session_status_notification_received(
- &self,
- env: &JNIEnv,
- data: SessionStatusNtfPacket,
- ) -> Result<()> {
- let session_id = data.get_session_id().to_i64().ok_or_else(|| {
- error!("Failed converting session_id to i64");
- Error::JniCall(JniError::Unknown)
- })?;
- let state = data.get_session_state().to_i32().ok_or_else(|| {
- error!("Failed converting session_state to i32");
- Error::JniCall(JniError::Unknown)
- })?;
- let reason_code = data.get_reason_code().to_i32().ok_or_else(|| {
- error!("Failed converting reason_code to i32");
- Error::JniCall(JniError::Unknown)
- })?;
- env.call_method(
- self.obj.as_obj(),
- "onSessionStatusNotificationReceived",
- "(JII)V",
- &[JValue::Long(session_id), JValue::Int(state), JValue::Int(reason_code)],
- )
- .map(|_| ()) // drop void method return
- }
-
- fn handle_core_generic_error_notification_received(
- &self,
- env: &JNIEnv,
- data: GenericErrorPacket,
- chip_id: &str,
- ) -> Result<()> {
- let status = data.get_status().to_i32().ok_or_else(|| {
- error!("Failed converting status to i32");
- Error::JniCall(JniError::Unknown)
- })?;
- env.call_method(
- self.obj.as_obj(),
- "onCoreGenericErrorNotificationReceived",
- "(ILjava/lang/String;)V",
- &[JValue::Int(status), JValue::Object(JObject::from(env.new_string(chip_id)?))],
- )
- .map(|_| ()) // drop void method return
- }
-
- fn create_zeroed_two_way_measurement_java<'a>(
- env: &'a JNIEnv,
- two_way_measurement_class: JClass,
- mac_address_java: jobjectArray,
- ) -> Result<JObject<'a>> {
- env.new_object(
- two_way_measurement_class,
- "([BIIIIIIIIIIIII)V",
- &[
- JValue::Object(JObject::from(mac_address_java)),
- JValue::Int(0),
- JValue::Int(0),
- JValue::Int(0),
- JValue::Int(0),
- JValue::Int(0),
- JValue::Int(0),
- JValue::Int(0),
- JValue::Int(0),
- JValue::Int(0),
- JValue::Int(0),
- JValue::Int(0),
- JValue::Int(0),
- JValue::Int(0),
- ],
- )
- }
-
- fn create_short_mac_two_way_measurement_java<'a>(
- env: &'a JNIEnv,
- two_way_measurement_class: JClass,
- two_way_measurement: &'a ShortAddressTwoWayRangingMeasurement,
- ) -> Result<JObject<'a>> {
- let mac_address_arr = two_way_measurement.mac_address.to_ne_bytes();
- let mac_address_java =
- env.new_byte_array(SHORT_MAC_ADDRESS_LEN.to_i32().ok_or_else(|| {
- error!("Failed converting mac address len to i32");
- Error::JniCall(JniError::Unknown)
- })?)?;
- // Convert from [u8] to [i8] since java does not support unsigned byte.
- let mac_address_arr_i8 = mac_address_arr.map(|x| x as i8);
- env.set_byte_array_region(mac_address_java, 0, &mac_address_arr_i8)?;
- env.new_object(
- two_way_measurement_class,
- "([BIIIIIIIIIIIII)V",
- &[
- JValue::Object(JObject::from(mac_address_java)),
- JValue::Int(two_way_measurement.status.to_i32().ok_or_else(|| {
- error!("Failed converting status to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.nlos.to_i32().ok_or_else(|| {
- error!("Failed converting nlos to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.distance.to_i32().ok_or_else(|| {
- error!("Failed converting distance to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.aoa_azimuth.to_i32().ok_or_else(|| {
- error!("Failed converting aoa azimuth to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.aoa_azimuth_fom.to_i32().ok_or_else(|| {
- error!("Failed converting aoa azimuth fom to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.aoa_elevation.to_i32().ok_or_else(|| {
- error!("Failed converting aoa elevation to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.aoa_elevation_fom.to_i32().ok_or_else(|| {
- error!("Failed converting aoa elevation fom to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.aoa_destination_azimuth.to_i32().ok_or_else(
- || {
- error!("Failed converting dest aoa azimuth to i32");
- Error::JniCall(JniError::Unknown)
- },
- )?),
- JValue::Int(two_way_measurement.aoa_destination_azimuth_fom.to_i32().ok_or_else(
- || {
- error!("Failed converting dest aoa azimuth fom to i32");
- Error::JniCall(JniError::Unknown)
- },
- )?),
- JValue::Int(two_way_measurement.aoa_destination_elevation.to_i32().ok_or_else(
- || {
- error!("Failed converting dest aoa elevation to i32");
- Error::JniCall(JniError::Unknown)
- },
- )?),
- JValue::Int(
- two_way_measurement.aoa_destination_elevation_fom.to_i32().ok_or_else(
- || {
- error!("Failed converting dest aoa elevation azimuth to i32");
- Error::JniCall(JniError::Unknown)
- },
- )?,
- ),
- JValue::Int(two_way_measurement.slot_index.to_i32().ok_or_else(|| {
- error!("Failed converting slot index to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.rssi.to_i32().ok_or_else(|| {
- error!("Failed converting rssi to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- ],
- )
- }
-
- fn create_extended_mac_two_way_measurement_java<'a>(
- env: &'a JNIEnv,
- two_way_measurement_class: JClass,
- two_way_measurement: &'a ExtendedAddressTwoWayRangingMeasurement,
- ) -> Result<JObject<'a>> {
- let mac_address_arr = two_way_measurement.mac_address.to_ne_bytes();
- let mac_address_java =
- env.new_byte_array(EXTENDED_MAC_ADDRESS_LEN.to_i32().ok_or_else(|| {
- error!("Failed converting mac address len to i32");
- Error::JniCall(JniError::Unknown)
- })?)?;
- // Convert from [u8] to [i8] since java does not support unsigned byte.
- let mac_address_arr_i8 = mac_address_arr.map(|x| x as i8);
- env.set_byte_array_region(mac_address_java, 0, &mac_address_arr_i8)?;
- env.new_object(
- two_way_measurement_class,
- "([BIIIIIIIIIIIII)V",
- &[
- JValue::Object(JObject::from(mac_address_java)),
- JValue::Int(two_way_measurement.status.to_i32().ok_or_else(|| {
- error!("Failed converting status to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.nlos.to_i32().ok_or_else(|| {
- error!("Failed converting nlos to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.distance.to_i32().ok_or_else(|| {
- error!("Failed converting distance to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.aoa_azimuth.to_i32().ok_or_else(|| {
- error!("Failed converting aoa azimuth to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.aoa_azimuth_fom.to_i32().ok_or_else(|| {
- error!("Failed converting aoa azimuth fom to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.aoa_elevation.to_i32().ok_or_else(|| {
- error!("Failed converting aoa elevation to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.aoa_elevation_fom.to_i32().ok_or_else(|| {
- error!("Failed converting aoa elevation fom to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.aoa_destination_azimuth.to_i32().ok_or_else(
- || {
- error!("Failed converting dest aoa azimuth to i32");
- Error::JniCall(JniError::Unknown)
- },
- )?),
- JValue::Int(two_way_measurement.aoa_destination_azimuth_fom.to_i32().ok_or_else(
- || {
- error!("Failed converting dest aoa azimuth fom to i32");
- Error::JniCall(JniError::Unknown)
- },
- )?),
- JValue::Int(two_way_measurement.aoa_destination_elevation.to_i32().ok_or_else(
- || {
- error!("Failed converting dest aoa elevation to i32");
- Error::JniCall(JniError::Unknown)
- },
- )?),
- JValue::Int(
- two_way_measurement.aoa_destination_elevation_fom.to_i32().ok_or_else(
- || {
- error!("Failed converting dest aoa elevation azimuth to i32");
- Error::JniCall(JniError::Unknown)
- },
- )?,
- ),
- JValue::Int(two_way_measurement.slot_index.to_i32().ok_or_else(|| {
- error!("Failed converting slot index to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(two_way_measurement.rssi.to_i32().ok_or_else(|| {
- error!("Failed converting rssi to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- ],
- )
- }
-
- fn create_range_data_java<'a>(
- &'a self,
- env: &'a JNIEnv,
- data: RangeDataNtfPacket,
- two_way_measurements_java: jobjectArray,
- num_two_way_measurements: i32,
- ) -> Result<JObject<'a>> {
- let ranging_data_class = self.find_class(env, UWB_RANGING_DATA_CLASS)?;
- let raw_ntf: Vec<u8> = data.clone().to_vec();
- let raw_ntf_jbytearray = env.byte_array_from_slice(raw_ntf.as_ref())?;
- env.new_object(
- ranging_data_class,
- "(JJIJIII[Lcom/android/server/uwb/data/UwbTwoWayMeasurement;[B)V",
- &[
- JValue::Long(data.get_sequence_number().to_i64().ok_or_else(|| {
- error!("Failed converting seq num to i64");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Long(data.get_session_id().to_i64().ok_or_else(|| {
- error!("Failed converting session id to i64");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(data.get_rcr_indicator().to_i32().ok_or_else(|| {
- error!("Failed converting rcr indicator to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Long(data.get_current_ranging_interval().to_i64().ok_or_else(|| {
- error!("Failed converting current ranging interval to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(data.get_ranging_measurement_type().to_i32().ok_or_else(|| {
- error!("Failed converting ranging measurement type to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(data.get_mac_address_indicator().to_i32().ok_or_else(|| {
- error!("Failed converting mac address indicator to i32");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(num_two_way_measurements),
- JValue::Object(JObject::from(two_way_measurements_java)),
- JValue::Object(JObject::from(raw_ntf_jbytearray)),
- ],
- )
- }
-
- fn handle_short_range_data_notification_received(
- &self,
- env: &JNIEnv,
- data: ShortMacTwoWayRangeDataNtfPacket,
- ) -> Result<()> {
- let two_way_measurement_class = self.find_class(env, UWB_TWO_WAY_MEASUREMENT_CLASS)?;
- let two_way_measurement_initial_java =
- EventManagerImpl::create_zeroed_two_way_measurement_java(
- env,
- two_way_measurement_class,
- env.new_byte_array(SHORT_MAC_ADDRESS_LEN.to_i32().ok_or_else(|| {
- error!("Failed converting mac address len to i32");
- Error::JniCall(JniError::Unknown)
- })?)?,
- )?;
- let num_two_way_measurements: i32 =
- data.get_two_way_ranging_measurements().len().to_i32().ok_or_else(|| {
- error!("Failed converting len to i32");
- Error::JniCall(JniError::Unknown)
- })?;
- let two_way_measurements_java = env.new_object_array(
- num_two_way_measurements,
- two_way_measurement_class,
- two_way_measurement_initial_java,
- )?;
- for (i, two_way_measurement) in data.get_two_way_ranging_measurements().iter().enumerate() {
- let two_way_measurement_java =
- EventManagerImpl::create_short_mac_two_way_measurement_java(
- env,
- two_way_measurement_class,
- two_way_measurement,
- )?;
- env.set_object_array_element(
- two_way_measurements_java,
- i.to_i32().ok_or_else(|| {
- error!("Failed converting idx to i32");
- Error::JniCall(JniError::Unknown)
- })?,
- two_way_measurement_java,
- )?
- }
- let ranging_data_java = self.create_range_data_java(
- env,
- data.into(),
- two_way_measurements_java,
- num_two_way_measurements,
- )?;
- env.call_method(
- self.obj.as_obj(),
- "onRangeDataNotificationReceived",
- "(Lcom/android/server/uwb/data/UwbRangingData;)V",
- &[JValue::Object(ranging_data_java)],
- )
- .map(|_| ()) // drop void method return
- }
-
- fn handle_extended_range_data_notification_received(
- &self,
- env: &JNIEnv,
- data: ExtendedMacTwoWayRangeDataNtfPacket,
- ) -> Result<()> {
- let two_way_measurement_class = self.find_class(env, UWB_TWO_WAY_MEASUREMENT_CLASS)?;
- let two_way_measurement_initial_java =
- EventManagerImpl::create_zeroed_two_way_measurement_java(
- env,
- two_way_measurement_class,
- env.new_byte_array(EXTENDED_MAC_ADDRESS_LEN.to_i32().ok_or_else(|| {
- error!("Failed converting mac address len to i32");
- Error::JniCall(JniError::Unknown)
- })?)?,
- )?;
- let num_two_way_measurements: i32 =
- data.get_two_way_ranging_measurements().len().to_i32().ok_or_else(|| {
- error!("Failed converting len to i32");
- Error::JniCall(JniError::Unknown)
- })?;
- let two_way_measurements_java = env.new_object_array(
- num_two_way_measurements,
- two_way_measurement_class,
- two_way_measurement_initial_java,
- )?;
- for (i, two_way_measurement) in data.get_two_way_ranging_measurements().iter().enumerate() {
- let two_way_measurement_java =
- EventManagerImpl::create_extended_mac_two_way_measurement_java(
- env,
- two_way_measurement_class,
- two_way_measurement,
- )?;
- env.set_object_array_element(
- two_way_measurements_java,
- i.to_i32().ok_or_else(|| {
- error!("Failed converting idx to i32");
- Error::JniCall(JniError::Unknown)
- })?,
- two_way_measurement_java,
- )?;
- }
- let ranging_data_java = self.create_range_data_java(
- env,
- data.into(),
- two_way_measurements_java,
- num_two_way_measurements,
- )?;
- env.call_method(
- self.obj.as_obj(),
- "onRangeDataNotificationReceived",
- "(Lcom/android/server/uwb/data/UwbRangingData;)V",
- &[JValue::Object(ranging_data_java)],
- )
- .map(|_| ()) // drop void method return
- }
-
- pub fn handle_session_update_controller_multicast_list_notification_received(
- &self,
- env: &JNIEnv,
- data: SessionUpdateControllerMulticastListNtfPacket,
- ) -> Result<()> {
- let uwb_multicast_update_class =
- self.find_class(env, MULTICAST_LIST_UPDATE_STATUS_CLASS)?;
-
- let controlee_status = data.get_controlee_status();
- let count: i32 = controlee_status.len().try_into().map_err(|_| {
- error!("Failed to convert controlee status length");
- Error::JniCall(JniError::Unknown)
- })?;
- let mut mac_address_list: Vec<i32> = Vec::new();
- let mut subsession_id_list: Vec<i64> = Vec::new();
- let mut status_list: Vec<i32> = Vec::new();
-
- for iter in controlee_status {
- mac_address_list.push(iter.mac_address.into());
- subsession_id_list.push(iter.subsession_id.into());
- status_list.push(iter.status.to_i32().ok_or_else(|| {
- error!("Failed to convert controlee_status's status field: {:?}", iter.status);
- Error::JniCall(JniError::Unknown)
- })?);
- }
-
- let mac_address_jintarray = env.new_int_array(count)?;
- env.set_int_array_region(mac_address_jintarray, 0, mac_address_list.as_ref())?;
- let subsession_id_jlongarray = env.new_long_array(count)?;
- env.set_long_array_region(subsession_id_jlongarray, 0, subsession_id_list.as_ref())?;
- let status_jintarray = env.new_int_array(count)?;
- env.set_int_array_region(status_jintarray, 0, status_list.as_ref())?;
-
- let uwb_multicast_update_object = env.new_object(
- uwb_multicast_update_class,
- "(JII[I[J[I)V",
- &[
- JValue::Long(data.get_session_id().try_into().map_err(|_| {
- error!("Could not convert session_id");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(data.get_remaining_multicast_list_size().try_into().map_err(|_| {
- error!("Could not convert remaining multicast list size");
- Error::JniCall(JniError::Unknown)
- })?),
- JValue::Int(count),
- JValue::Object(JObject::from(mac_address_jintarray)),
- JValue::Object(JObject::from(subsession_id_jlongarray)),
- JValue::Object(JObject::from(status_jintarray)),
- ],
- )?;
-
- env.call_method(
- self.obj.as_obj(),
- "onMulticastListUpdateNotificationReceived",
- "(Lcom/android/server/uwb/data/UwbMulticastListUpdateStatus;)V",
- &[JValue::Object(uwb_multicast_update_object)],
- )
- .map(|_| ()) // drop void method return
- }
-
- fn get_vendor_uci_payload(data: UciNotificationPacket) -> Result<Vec<u8>> {
- match data.specialize() {
- UciNotificationChild::UciVendor_9_Notification(evt) => match evt.specialize() {
- UciVendor_9_NotificationChild::Payload(payload) => Ok(payload.to_vec()),
- UciVendor_9_NotificationChild::None => Ok(Vec::new()),
- },
- UciNotificationChild::UciVendor_A_Notification(evt) => match evt.specialize() {
- UciVendor_A_NotificationChild::Payload(payload) => Ok(payload.to_vec()),
- UciVendor_A_NotificationChild::None => Ok(Vec::new()),
- },
- UciNotificationChild::UciVendor_B_Notification(evt) => match evt.specialize() {
- UciVendor_B_NotificationChild::Payload(payload) => Ok(payload.to_vec()),
- UciVendor_B_NotificationChild::None => Ok(Vec::new()),
- },
- UciNotificationChild::UciVendor_E_Notification(evt) => match evt.specialize() {
- UciVendor_E_NotificationChild::Payload(payload) => Ok(payload.to_vec()),
- UciVendor_E_NotificationChild::None => Ok(Vec::new()),
- },
- UciNotificationChild::UciVendor_F_Notification(evt) => match evt.specialize() {
- UciVendor_F_NotificationChild::Payload(payload) => Ok(payload.to_vec()),
- UciVendor_F_NotificationChild::None => Ok(Vec::new()),
- },
- _ => {
- error!("Invalid vendor notification with gid {:?}", data.to_vec());
- Err(Error::JniCall(JniError::Unknown))
- }
- }
- }
-
- pub fn handle_vendor_uci_notification_received(
- &self,
- env: &JNIEnv,
- data: UciNotificationPacket,
- _chip_id: &str,
- ) -> Result<()> {
- let gid: i32 = data.get_group_id().to_i32().ok_or_else(|| {
- error!("Failed to convert gid");
- Error::JniCall(JniError::Unknown)
- })?;
- let oid: i32 = data.get_opcode().to_i32().ok_or_else(|| {
- error!("Failed to convert gid");
- Error::JniCall(JniError::Unknown)
- })?;
- let payload: Vec<u8> = EventManagerImpl::get_vendor_uci_payload(data)?;
- let payload_jbytearray = env.byte_array_from_slice(payload.as_ref())?;
-
- // TODO(b/237533396): Add chip_id parameter to onVendorUciNotificationReceived
- env.call_method(
- self.obj.as_obj(),
- "onVendorUciNotificationReceived",
- "(II[B)V",
- &[
- JValue::Int(gid),
- JValue::Int(oid),
- JValue::Object(JObject::from(payload_jbytearray)),
- ],
- )
- .map(|_| ()) // drop void method return
- }
-
- // Attempts to clear an exception. If we do not do this, the exception continues being thrown
- // when the control flow returns to Java. We discard errors here (after logging them) rather
- // than propagating them to the caller since there's nothing they can do with that information.
- fn clear_exception(&self, env: AttachGuard) {
- match env.exception_check() {
- Ok(true) => match env.exception_clear() {
- Ok(()) => {} // We successfully cleared the exception.
- Err(e) => error!("Error clearing JNI exception: {:?}", e),
- },
- Ok(false) => {} // No exception found.
- Err(e) => error!("Error checking JNI exception: {:?}", e),
- }
- }
-}
-
-#[cfg(any(test, fuzzing))]
-pub mod mock_event_manager;
diff --git a/src/rust/lib.rs b/src/rust/lib.rs
deleted file mode 100644
index e9f3dbe..0000000
--- a/src/rust/lib.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// TODO remove this and add appropriate documentation once it is decided whether this stays here or
-// moves into packages/modules/Uwb
-#![allow(missing_docs)]
-#![feature(rustc_private)]
-
-pub mod adaptation;
-pub mod error;
-pub mod event_manager;
-pub mod uci;
diff --git a/src/rust/uci/mock_uci_logger.rs b/src/rust/uci/mock_uci_logger.rs
deleted file mode 100644
index ebf53c7..0000000
--- a/src/rust/uci/mock_uci_logger.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-extern crate libc;
-
-use crate::uci::uci_logger::UciLogger;
-use crate::uci::UwbErr;
-use async_trait::async_trait;
-use std::path::Path;
-use std::time::Duration;
-use uwb_uci_packets::{UciCommandPacket, UciNotificationPacket, UciResponsePacket};
-
-#[cfg(test)]
-pub struct MockUciLogger {}
-
-#[cfg(test)]
-impl MockUciLogger {
- pub fn new() -> Self {
- MockUciLogger {}
- }
-}
-
-#[cfg(test)]
-impl Default for MockUciLogger {
- fn default() -> Self {
- Self::new()
- }
-}
-
-#[cfg(test)]
-#[async_trait]
-impl UciLogger for MockUciLogger {
- async fn log_uci_command(&self, _cmd: UciCommandPacket) {}
- async fn log_uci_response(&self, _rsp: UciResponsePacket) {}
- async fn log_uci_notification(&self, _ntf: UciNotificationPacket) {}
- async fn close_file(&self) {}
-}
-
-#[cfg(test)]
-pub async fn create_dir(_path: impl AsRef<Path>) -> Result<(), UwbErr> {
- Ok(())
-}
-
-#[cfg(test)]
-pub async fn remove_file(_path: impl AsRef<Path>) -> Result<(), UwbErr> {
- Ok(())
-}
-
-#[cfg(test)]
-pub async fn rename(_from: impl AsRef<Path>, _to: impl AsRef<Path>) -> Result<(), UwbErr> {
- Ok(())
-}
-
-#[cfg(test)]
-pub struct Instant {}
-impl Instant {
- pub fn now() -> Instant {
- Instant {}
- }
- pub fn elapsed(&self) -> Duration {
- Duration::from_micros(0)
- }
-}
diff --git a/src/rust/uci/mod.rs b/src/rust/uci/mod.rs
deleted file mode 100644
index 7cd7da1..0000000
--- a/src/rust/uci/mod.rs
+++ /dev/null
@@ -1,1129 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-pub mod uci_hmsgs;
-pub mod uci_hrcv;
-pub mod uci_logger;
-
-use crate::adaptation::{UwbAdaptation, UwbAdaptationImpl};
-use crate::error::UwbErr;
-use crate::event_manager::EventManager;
-use crate::uci::uci_hrcv::UciResponse;
-use android_hardware_uwb::aidl::android::hardware::uwb::{
- UwbEvent::UwbEvent, UwbStatus::UwbStatus,
-};
-use arbitrary::Arbitrary;
-use log::{debug, error, info, warn};
-use num_traits::FromPrimitive;
-use std::future::Future;
-use std::option::Option;
-use std::sync::Arc;
-use tokio::runtime::{Builder, Runtime};
-use tokio::sync::{mpsc, oneshot, Notify};
-use tokio::{select, task};
-use uwb_uci_packets::{
- AndroidGetPowerStatsCmdBuilder, DeviceState, DeviceStatusNtfBuilder, GetCapsInfoCmdBuilder,
- GetDeviceInfoCmdBuilder, GetDeviceInfoRspPacket, MessageControl, RangeStartCmdBuilder,
- RangeStopCmdBuilder, SessionDeinitCmdBuilder, SessionGetAppConfigCmdBuilder,
- SessionGetCountCmdBuilder, SessionGetStateCmdBuilder, SessionState, SessionStatusNtfPacket,
- StatusCode, UciCommandPacket,
-};
-
-pub type Result<T> = std::result::Result<T, UwbErr>;
-pub type UciResponseHandle = oneshot::Sender<UciResponse>;
-pub type SyncUwbAdaptation = Arc<dyn UwbAdaptation + Send + Sync>;
-
-// Commands sent from JNI.
-#[derive(Arbitrary, Clone, Debug, PartialEq, Eq)]
-pub enum JNICommand {
- // Blocking UCI commands
- Enable,
- UciGetCapsInfo,
- UciGetDeviceInfo,
- UciSessionInit(u32, u8),
- UciSessionDeinit(u32),
- UciSessionGetCount,
- UciStartRange(u32),
- UciStopRange(u32),
- UciGetSessionState(u32),
- UciSessionUpdateMulticastList {
- session_id: u32,
- action: u8,
- no_of_controlee: u8,
- address_list: Vec<i16>,
- sub_session_id_list: Vec<i32>,
- message_control: i32,
- sub_session_key_list: Vec<Vec<u8>>,
- },
- UciSetCountryCode {
- code: Vec<u8>,
- },
- UciSetAppConfig {
- session_id: u32,
- no_of_params: u32,
- // TODO this field should be removed, in tandem with a change to the Uwb APEX
- app_config_param_len: u32,
- app_configs: Vec<u8>,
- },
- UciGetAppConfig {
- session_id: u32,
- no_of_params: u32,
- app_config_param_len: u32,
- app_configs: Vec<u8>,
- },
- UciRawVendorCmd {
- gid: u32,
- oid: u32,
- payload: Vec<u8>,
- },
- UciDeviceReset {
- reset_config: u8,
- },
- UciGetPowerStats,
-
- // Non blocking commands
- Disable(bool),
-}
-
-// Responses from the HAL.
-#[derive(Debug)]
-pub enum HalCallback {
- Event { event: UwbEvent, event_status: UwbStatus },
- UciRsp(uci_hrcv::UciResponse),
- UciNtf(uci_hrcv::UciNotification),
-}
-
-#[derive(Debug, PartialEq)]
-pub enum UwbState {
- None,
- W4HalOpen,
- Ready,
- W4UciResp,
- W4HalClose,
-}
-
-#[derive(Clone)]
-struct Retryer {
- received: Arc<Notify>,
- failed: Arc<Notify>,
- retry: Arc<Notify>,
-}
-
-impl Retryer {
- fn new() -> Self {
- Self {
- received: Arc::new(Notify::new()),
- failed: Arc::new(Notify::new()),
- retry: Arc::new(Notify::new()),
- }
- }
-
- async fn command_failed(&self) {
- self.failed.notified().await
- }
-
- async fn immediate_retry(&self) {
- self.retry.notified().await
- }
-
- async fn command_serviced(&self) {
- self.received.notified().await
- }
-
- fn received(&self) {
- self.received.notify_one()
- }
-
- fn retry(&self) {
- self.retry.notify_one()
- }
-
- fn failed(&self) {
- self.failed.notify_one()
- }
-
- fn send_with_retry(
- self,
- adaptation: SyncUwbAdaptation,
- cmd: UciCommandPacket,
- chip_id: String,
- ) {
- tokio::task::spawn(async move {
- let mut received_response = false;
- for retry in 0..MAX_RETRIES {
- adaptation.send_uci_message(cmd.clone(), &chip_id).await.unwrap_or_else(|e| {
- error!("Sending UCI message to chip {} failed: {:?}", chip_id, e);
- });
- select! {
- _ = tokio::time::sleep(tokio::time::Duration::from_millis(RETRY_DELAY_MS)) => warn!("UWB chip did not respond within {}ms deadline. Retrying (#{})...", RETRY_DELAY_MS, retry + 1),
- _ = self.command_serviced() => {
- received_response = true;
- break;
- }
- _ = self.immediate_retry() => debug!("UWB chip requested immediate retry. Retrying (#{})...", retry + 1),
- }
- }
- if !received_response {
- error!("After {} retries, no response from UWB chip {}", MAX_RETRIES, chip_id);
- adaptation.core_initialization(&chip_id).await.unwrap_or_else(|e| {
- error!("Resetting chip {} due to no responses failed: {:?}", chip_id, e);
- });
- self.failed();
- }
- });
- }
-}
-
-//TODO pull in libfutures instead of open-coding this
-async fn option_future<R, T: Future<Output = R>>(mf: Option<T>) -> Option<R> {
- if let Some(f) = mf {
- Some(f.await)
- } else {
- None
- }
-}
-
-struct Driver<T: EventManager> {
- adaptation: SyncUwbAdaptation,
- event_manager: T,
- cmd_receiver: mpsc::UnboundedReceiver<(JNICommand, Option<UciResponseHandle>, String)>,
- rsp_receiver: mpsc::UnboundedReceiver<(HalCallback, String)>,
- response_channel: Option<(UciResponseHandle, Retryer)>,
- state: UwbState,
-}
-
-// Creates a future that handles messages from JNI and the HAL.
-async fn drive<T: EventManager + Send + Sync>(
- adaptation: SyncUwbAdaptation,
- event_manager: T,
- cmd_receiver: mpsc::UnboundedReceiver<(JNICommand, Option<UciResponseHandle>, String)>,
- rsp_receiver: mpsc::UnboundedReceiver<(HalCallback, String)>,
-) -> Result<()> {
- Driver::new(adaptation, event_manager, cmd_receiver, rsp_receiver).await.drive().await
-}
-
-const MAX_RETRIES: usize = 5;
-const RETRY_DELAY_MS: u64 = 800;
-
-impl<T: EventManager> Driver<T> {
- async fn new(
- adaptation: SyncUwbAdaptation,
- event_manager: T,
- cmd_receiver: mpsc::UnboundedReceiver<(JNICommand, Option<UciResponseHandle>, String)>,
- rsp_receiver: mpsc::UnboundedReceiver<(HalCallback, String)>,
- ) -> Self {
- Self {
- adaptation,
- event_manager,
- cmd_receiver,
- rsp_receiver,
- response_channel: None,
- state: UwbState::None,
- }
- }
-
- // Continually handles messages.
- async fn drive(mut self) -> Result<()> {
- loop {
- match self.drive_once().await {
- Err(UwbErr::Exit) => return Ok(()),
- Err(e) => error!("drive_once: {:?}", e),
- Ok(()) => (),
- }
- }
- }
-
- async fn handle_blocking_jni_cmd(
- &mut self,
- tx: oneshot::Sender<UciResponse>,
- cmd: JNICommand,
- chip_id: String,
- ) -> Result<()> {
- log::debug!("Received blocking cmd {:?}", cmd);
- let command: UciCommandPacket = match cmd {
- JNICommand::Enable => {
- match (
- self.adaptation.hal_open(&chip_id).await,
- self.adaptation.core_initialization(&chip_id).await,
- ) {
- (Ok(()), Ok(())) => {
- tx.send(UciResponse::EnableRsp(true))
- .unwrap_or_else(|e| error!("Error sending Enable response: {:?}", e));
- self.set_state(UwbState::W4HalOpen);
- }
- (Err(e), _) | (_, Err(e)) => {
- error!("Enable UWB failed with: {:?}", e);
- tx.send(UciResponse::EnableRsp(false))
- .unwrap_or_else(|e| error!("Error sending Enable response: {:?}", e));
- }
- }
- return Ok(());
- }
- JNICommand::UciGetDeviceInfo => GetDeviceInfoCmdBuilder {}.build().into(),
- JNICommand::UciGetCapsInfo => GetCapsInfoCmdBuilder {}.build().into(),
- JNICommand::UciSessionInit(session_id, session_type) => {
- uci_hmsgs::build_session_init_cmd(session_id, session_type)?.build().into()
- }
- JNICommand::UciSessionDeinit(session_id) => {
- SessionDeinitCmdBuilder { session_id }.build().into()
- }
- JNICommand::UciSessionGetCount => SessionGetCountCmdBuilder {}.build().into(),
- JNICommand::UciGetPowerStats => AndroidGetPowerStatsCmdBuilder {}.build().into(),
- JNICommand::UciStartRange(session_id) => {
- RangeStartCmdBuilder { session_id }.build().into()
- }
- JNICommand::UciStopRange(session_id) => {
- RangeStopCmdBuilder { session_id }.build().into()
- }
- JNICommand::UciGetSessionState(session_id) => {
- SessionGetStateCmdBuilder { session_id }.build().into()
- }
- JNICommand::UciSessionUpdateMulticastList {
- session_id,
- action,
- no_of_controlee,
- ref address_list,
- ref sub_session_id_list,
- message_control,
- ref sub_session_key_list,
- } => uci_hmsgs::build_multicast_list_update_cmd(
- session_id,
- action,
- no_of_controlee,
- address_list,
- sub_session_id_list,
- match message_control {
- -1 => None,
- _ => {
- Some(MessageControl::from_i32(message_control).ok_or(UwbErr::InvalidArgs)?)
- }
- },
- sub_session_key_list,
- )?
- .build()
- .into(),
- JNICommand::UciSetCountryCode { ref code } => {
- uci_hmsgs::build_set_country_code_cmd(code)?.build().into()
- }
- JNICommand::UciSetAppConfig { session_id, no_of_params, ref app_configs, .. } => {
- uci_hmsgs::build_set_app_config_cmd(session_id, no_of_params, app_configs)?
- .build()
- .into()
- }
- JNICommand::UciGetAppConfig { session_id, ref app_configs, .. } => {
- SessionGetAppConfigCmdBuilder { session_id, app_cfg: app_configs.to_vec() }
- .build()
- .into()
- }
- JNICommand::UciRawVendorCmd { gid, oid, payload } => {
- uci_hmsgs::build_uci_vendor_cmd_packet(gid, oid, payload)?
- }
- JNICommand::UciDeviceReset { reset_config } => {
- uci_hmsgs::build_device_reset_cmd(reset_config)?.build().into()
- }
- _ => {
- error!("Unexpected blocking cmd received {:?}", cmd);
- return Ok(());
- }
- };
-
- log::debug!("Sending HAL UCI message {:?}", command);
-
- let retryer = Retryer::new();
- self.response_channel = Some((tx, retryer.clone()));
- retryer.send_with_retry(self.adaptation.clone(), command, chip_id);
- self.set_state(UwbState::W4UciResp);
- Ok(())
- }
-
- async fn handle_non_blocking_jni_cmd(
- &mut self,
- cmd: JNICommand,
- chip_id: String,
- ) -> Result<()> {
- log::debug!("Received non blocking cmd {:?}", cmd);
- match cmd {
- JNICommand::Disable(_graceful) => match self.adaptation.hal_close(&chip_id).await {
- Ok(()) => self.set_state(UwbState::W4HalClose),
- Err(e) => {
- error!("Recevied HAL close failure: {:?}", e);
- self.set_state(UwbState::None); // TODO(b/239965873): state should be per-chip
- return Err(UwbErr::Exit);
- }
- },
- _ => error!("Unexpected non blocking cmd received {:?}", cmd),
- }
- Ok(())
- }
-
- async fn handle_hal_notification(
- &self,
- response: uci_hrcv::UciNotification,
- chip_id: String,
- ) -> Result<()> {
- log::debug!("Received hal notification {:?}", response);
- match response {
- uci_hrcv::UciNotification::DeviceStatusNtf(response) => {
- self.event_manager.device_status_notification_received(response, &chip_id)?;
- }
- uci_hrcv::UciNotification::GenericError(response) => {
- if let (StatusCode::UciStatusCommandRetry, Some((_, retryer))) =
- (response.get_status(), self.response_channel.as_ref())
- {
- retryer.retry();
- }
- self.event_manager.core_generic_error_notification_received(response, &chip_id)?;
- }
- uci_hrcv::UciNotification::SessionStatusNtf(response) => {
- self.invoke_hal_session_init_if_necessary(&response, chip_id).await;
- self.event_manager.session_status_notification_received(response)?;
- }
- uci_hrcv::UciNotification::ShortMacTwoWayRangeDataNtf(response) => {
- self.event_manager.short_range_data_notification_received(response)?;
- }
- uci_hrcv::UciNotification::ExtendedMacTwoWayRangeDataNtf(response) => {
- self.event_manager.extended_range_data_notification_received(response)?;
- }
- uci_hrcv::UciNotification::SessionUpdateControllerMulticastListNtf(response) => {
- self.event_manager
- .session_update_controller_multicast_list_notification_received(response)?;
- }
- uci_hrcv::UciNotification::AndroidRangeDiagnosticsNtf(_response) => {}
- uci_hrcv::UciNotification::RawVendorNtf(response) => {
- self.event_manager.vendor_uci_notification_received(response, &chip_id)?;
- }
- }
- Ok(())
- }
-
- // Handles a single message from JNI or the HAL.
- async fn drive_once(&mut self) -> Result<()> {
- select! {
- Some(()) = option_future(self.response_channel.as_ref()
- .map(|(_, retryer)| retryer.command_failed())) => {
- // TODO: Do we want to flush the incoming queue of commands when this happens?
- self.set_state(UwbState::W4HalOpen);
- self.response_channel = None
- }
- // Note: If a blocking command is awaiting a response, any non-blocking commands are not
- // dequeued until the blocking cmd's response is received.
- Some((cmd, tx, chip_id)) = self.cmd_receiver.recv(), if self.can_process_cmd() => {
- match tx {
- Some(tx) => { // Blocking JNI commands processing.
- self.handle_blocking_jni_cmd(tx, cmd, chip_id).await?;
- },
- None => { // Non Blocking JNI commands processing.
- self.handle_non_blocking_jni_cmd(cmd, chip_id).await?;
- }
- }
- }
- Some((rsp, chip_id)) = self.rsp_receiver.recv() => {
- match rsp {
- HalCallback::Event{event, event_status} => {
- log::info!("Received HAL event: {:?} with status: {:?}", event, event_status);
- match event {
- UwbEvent::POST_INIT_CPLT => {
- self.set_state(UwbState::Ready);
- }
- UwbEvent::CLOSE_CPLT => {
- self.set_state(UwbState::None);
- return Err(UwbErr::Exit);
- }
- UwbEvent::ERROR => {
- // Send device status notification with error state.
- let device_status_ntf = DeviceStatusNtfBuilder { device_state: DeviceState::DeviceStateError}.build();
- self.event_manager.device_status_notification_received(device_status_ntf, &chip_id)?;
- self.set_state(UwbState::None);
- }
- _ => ()
- }
- },
- HalCallback::UciRsp(response) => {
- log::debug!("Received HAL UCI message {:?}", response);
- self.set_state(UwbState::Ready);
- if let Some((channel, retryer)) = self.response_channel.take() {
- retryer.received();
- channel.send(response).unwrap_or_else(|_| {
- error!("Unable to send response, receiver gone");
- });
- } else {
- error!("Received response packet, but no response channel available");
- }
- },
- HalCallback::UciNtf(response) => {
- self.handle_hal_notification(response, chip_id).await?;
- }
- }
- }
- }
- Ok(())
- }
-
- // Triggers the session init HAL API, if a new session is initialized.
- async fn invoke_hal_session_init_if_necessary(
- &self,
- response: &SessionStatusNtfPacket,
- chip_id: String,
- ) {
- if let SessionState::SessionStateInit = response.get_session_state() {
- info!(
- "Session {:?} initialized, invoking session init HAL API",
- response.get_session_id()
- );
- self.adaptation
- // HAL API accepts signed int, so cast received session_id as i32.
- .session_initialization(response.get_session_id() as i32, &chip_id)
- .await
- .unwrap_or_else(|e| error!("Error invoking session init HAL API : {:?}", e));
- }
- }
-
- fn set_state(&mut self, state: UwbState) {
- info!("UWB state change from {:?} to {:?}", self.state, state);
- self.state = state;
- }
-
- fn can_process_cmd(&mut self) -> bool {
- self.state == UwbState::None || self.state == UwbState::Ready
- }
-}
-
-pub trait Dispatcher {
- fn send_jni_command(&self, cmd: JNICommand, chip_id: String) -> Result<()>;
- fn block_on_jni_command(&self, cmd: JNICommand, chip_id: String) -> Result<UciResponse>;
- fn wait_for_exit(&mut self) -> Result<()>;
- fn get_device_info(&self) -> &Option<GetDeviceInfoRspPacket>;
- fn set_device_info(&mut self, device_info: Option<GetDeviceInfoRspPacket>);
-}
-
-// Controller for sending tasks for the native thread to handle.
-pub struct DispatcherImpl {
- cmd_sender: mpsc::UnboundedSender<(JNICommand, Option<UciResponseHandle>, String)>,
- join_handle: task::JoinHandle<Result<()>>,
- runtime: Runtime,
- device_info: Option<GetDeviceInfoRspPacket>,
-}
-
-impl DispatcherImpl {
- pub fn new<T: 'static + EventManager + Send + Sync>(
- event_manager: T,
- chip_ids: Vec<String>,
- ) -> Result<Self> {
- let (rsp_sender, rsp_receiver) = mpsc::unbounded_channel::<(HalCallback, String)>();
- // TODO when simplifying constructors, avoid spare runtime
- let adaptation: SyncUwbAdaptation = Arc::new(
- Builder::new_current_thread()
- .build()?
- .block_on(UwbAdaptationImpl::new(rsp_sender, &chip_ids))?,
- );
-
- Self::new_with_args(event_manager, adaptation, rsp_receiver)
- }
-
- pub fn new_for_testing<T: 'static + EventManager + Send + Sync>(
- event_manager: T,
- adaptation: SyncUwbAdaptation,
- rsp_receiver: mpsc::UnboundedReceiver<(HalCallback, String)>,
- ) -> Result<Self> {
- Self::new_with_args(event_manager, adaptation, rsp_receiver)
- }
-
- fn new_with_args<T: 'static + EventManager + Send + Sync>(
- event_manager: T,
- adaptation: SyncUwbAdaptation,
- rsp_receiver: mpsc::UnboundedReceiver<(HalCallback, String)>,
- ) -> Result<Self> {
- info!("initializing dispatcher");
- let (cmd_sender, cmd_receiver) =
- mpsc::unbounded_channel::<(JNICommand, Option<UciResponseHandle>, String)>();
-
- // We create a new thread here both to avoid reusing the Java service thread and because
- // binder threads will call into this.
- let runtime = Builder::new_multi_thread()
- .worker_threads(1)
- .thread_name("uwb-uci-handler")
- .enable_all()
- .build()?;
-
- let join_handle =
- runtime.spawn(drive(adaptation, event_manager, cmd_receiver, rsp_receiver));
- Ok(DispatcherImpl { cmd_sender, join_handle, runtime, device_info: None })
- }
-}
-
-impl Dispatcher for DispatcherImpl {
- fn send_jni_command(&self, cmd: JNICommand, chip_id: String) -> Result<()> {
- self.cmd_sender.send((cmd, None, chip_id))?;
- Ok(())
- }
-
- // TODO: Consider implementing these separate for different commands so we can have more
- // specific return types.
- fn block_on_jni_command(&self, cmd: JNICommand, chip_id: String) -> Result<UciResponse> {
- let (tx, rx) = oneshot::channel();
- self.cmd_sender.send((cmd, Some(tx), chip_id))?;
- let ret = self.runtime.block_on(rx)?;
- log::trace!("{:?}", ret);
- Ok(ret)
- }
-
- fn wait_for_exit(&mut self) -> Result<()> {
- match self.runtime.block_on(&mut self.join_handle) {
- Err(err) if err.is_panic() => {
- error!("Driver thread is panic!");
- Err(UwbErr::Undefined)
- }
- _ => Ok(()),
- }
- }
-
- fn get_device_info(&self) -> &Option<GetDeviceInfoRspPacket> {
- &self.device_info
- }
- fn set_device_info(&mut self, device_info: Option<GetDeviceInfoRspPacket>) {
- self.device_info = device_info;
- }
-}
-
-#[cfg(test)]
-pub mod mock_uci_logger;
-
-#[cfg(test)]
-mod tests {
- use self::uci_hrcv::UciNotification;
- use self::uci_hrcv::UciResponse;
-
- use super::*;
- use crate::adaptation::mock_adaptation::MockUwbAdaptation;
- use crate::event_manager::mock_event_manager::MockEventManager;
- use android_hardware_uwb::aidl::android::hardware::uwb::{
- UwbEvent::UwbEvent, UwbStatus::UwbStatus,
- };
- use bytes::Bytes;
- use num_traits::ToPrimitive;
- use uwb_uci_packets::*;
-
- fn setup_dispatcher_and_return_hal_cb_sender(
- config_fn: fn(&mut Arc<MockUwbAdaptation>, &mut MockEventManager),
- ) -> (DispatcherImpl, mpsc::UnboundedSender<(HalCallback, String)>) {
- // TODO: Remove this once we call it somewhere real.
- logger::init(
- logger::Config::default().with_tag_on_device("uwb").with_min_level(log::Level::Debug),
- );
-
- let (rsp_sender, rsp_receiver) = mpsc::unbounded_channel::<(HalCallback, String)>();
- let mut mock_adaptation = Arc::new(MockUwbAdaptation::new(rsp_sender.clone()));
- let mut mock_event_manager = MockEventManager::new();
-
- config_fn(&mut mock_adaptation, &mut mock_event_manager);
- let dispatcher = DispatcherImpl::new_for_testing(
- mock_event_manager,
- mock_adaptation as SyncUwbAdaptation,
- rsp_receiver,
- )
- .unwrap();
- (dispatcher, rsp_sender)
- }
-
- fn generate_fake_get_device_cmd_rsp() -> (GetDeviceInfoCmdPacket, GetDeviceInfoRspPacket) {
- let cmd = GetDeviceInfoCmdBuilder {}.build();
- let rsp = GetDeviceInfoRspBuilder {
- status: StatusCode::UciStatusOk,
- uci_version: 0,
- mac_version: 0,
- phy_version: 0,
- uci_test_version: 0,
- vendor_spec_info: vec![],
- }
- .build();
- (cmd, rsp)
- }
-
- fn generate_fake_device_status_ntf() -> DeviceStatusNtfPacket {
- DeviceStatusNtfBuilder { device_state: DeviceState::DeviceStateReady }.build()
- }
-
- #[test]
- fn test_initialize() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- mock_adaptation.expect_hal_open(Ok(()));
- mock_adaptation.expect_core_initialization(Ok(()));
- });
-
- dispatcher.block_on_jni_command(JNICommand::Enable, String::from("chip_id")).unwrap();
- }
-
- #[test]
- fn test_hal_error_event() {
- let (mut dispatcher, hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, mock_event_manager| {
- mock_adaptation.expect_hal_open(Ok(()));
- mock_adaptation.expect_core_initialization(Ok(()));
- mock_event_manager.expect_device_status_notification_received(Ok(()));
- });
- let chip_id = String::from("chip_id");
-
- dispatcher.block_on_jni_command(JNICommand::Enable, chip_id.clone()).unwrap();
- hal_sender
- .send((
- HalCallback::Event { event: UwbEvent::ERROR, event_status: UwbStatus::FAILED },
- chip_id.clone(),
- ))
- .unwrap();
- hal_sender
- .send((
- HalCallback::Event { event: UwbEvent::CLOSE_CPLT, event_status: UwbStatus::OK },
- chip_id,
- ))
- .unwrap();
- dispatcher.wait_for_exit().unwrap();
- }
-
- #[test]
- fn test_deinitialize() {
- let (mut dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- mock_adaptation.expect_hal_close(Ok(()));
- });
- let chip_id = String::from("chip_id");
-
- dispatcher.send_jni_command(JNICommand::Disable(true), chip_id).unwrap();
- dispatcher.wait_for_exit().unwrap();
- }
-
- #[test]
- fn test_get_device_info() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let (cmd, rsp) = generate_fake_get_device_cmd_rsp();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::GetDeviceInfoRsp(rsp)),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(JNICommand::UciGetDeviceInfo, String::from("chip_id"))
- .unwrap();
- }
-
- #[test]
- fn test_get_device_info_with_uci_retry() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let (cmd, rsp) = generate_fake_get_device_cmd_rsp();
-
- // Let the first 2 tries not response data, then the 3rd tries response successfully.
- mock_adaptation.expect_send_uci_message(cmd.clone().into(), None, None, Ok(()));
- mock_adaptation.expect_send_uci_message(cmd.clone().into(), None, None, Ok(()));
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::GetDeviceInfoRsp(rsp)),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(JNICommand::UciGetDeviceInfo, String::from("chip_id"))
- .unwrap();
- }
-
- #[test]
- fn test_get_device_info_send_uci_message_failed() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let (cmd, _rsp) = generate_fake_get_device_cmd_rsp();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- None,
- None,
- Err(UwbErr::failed()),
- );
- });
-
- dispatcher
- .block_on_jni_command(JNICommand::UciGetDeviceInfo, String::from("chip_id"))
- .expect_err("This method should fail.");
- }
-
- #[test]
- fn test_device_status_notification() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, mock_event_manager| {
- let (cmd, rsp) = generate_fake_get_device_cmd_rsp();
- let ntf = generate_fake_device_status_ntf();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::GetDeviceInfoRsp(rsp)),
- Some(UciNotification::DeviceStatusNtf(ntf)),
- Ok(()),
- );
- mock_event_manager.expect_device_status_notification_received(Ok(()));
- });
-
- dispatcher
- .block_on_jni_command(JNICommand::UciGetDeviceInfo, String::from("chip_id"))
- .unwrap();
- }
-
- #[test]
- fn test_get_caps_info() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let cmd = GetCapsInfoCmdBuilder {}.build();
- let rsp =
- GetCapsInfoRspBuilder { status: StatusCode::UciStatusOk, tlvs: Vec::new() }
- .build();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::GetCapsInfoRsp(rsp)),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(JNICommand::UciGetCapsInfo, String::from("chip_id"))
- .unwrap();
- }
-
- #[test]
- fn test_session_init() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let cmd = SessionInitCmdBuilder {
- session_id: 1,
- session_type: SessionType::FiraRangingSession,
- }
- .build();
- let rsp = SessionInitRspBuilder { status: StatusCode::UciStatusOk }.build();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::SessionInitRsp(rsp)),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(
- JNICommand::UciSessionInit(1, SessionType::FiraRangingSession.to_u8().unwrap()),
- String::from("chip_id"),
- )
- .unwrap();
- }
-
- #[test]
- fn test_session_deinit() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let cmd = SessionDeinitCmdBuilder { session_id: 1 }.build();
- let rsp = SessionDeinitRspBuilder { status: StatusCode::UciStatusOk }.build();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::SessionDeinitRsp(rsp)),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(JNICommand::UciSessionDeinit(1), String::from("chip_id"))
- .unwrap();
- }
-
- #[test]
- fn test_session_get_count() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let cmd = SessionGetCountCmdBuilder {}.build();
- let rsp =
- SessionGetCountRspBuilder { status: StatusCode::UciStatusOk, session_count: 5 }
- .build();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::SessionGetCountRsp(rsp)),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(JNICommand::UciSessionGetCount, String::from("chip_id"))
- .unwrap();
- }
-
- #[test]
- fn test_start_range() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let cmd = RangeStartCmdBuilder { session_id: 5 }.build();
- let rsp = RangeStartRspBuilder { status: StatusCode::UciStatusOk }.build();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::RangeStartRsp(rsp)),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(JNICommand::UciStartRange(5), String::from("chip_id"))
- .unwrap();
- }
-
- #[test]
- fn test_stop_range() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let cmd = RangeStopCmdBuilder { session_id: 5 }.build();
- let rsp = RangeStopRspBuilder { status: StatusCode::UciStatusOk }.build();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::RangeStopRsp(rsp)),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(JNICommand::UciStopRange(5), String::from("chip_id"))
- .unwrap();
- }
-
- #[test]
- fn test_get_session_state() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let cmd = SessionGetStateCmdBuilder { session_id: 5 }.build();
- let rsp = SessionGetStateRspBuilder {
- status: StatusCode::UciStatusOk,
- session_state: SessionState::SessionStateActive,
- }
- .build();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::SessionGetStateRsp(rsp)),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(JNICommand::UciGetSessionState(5), String::from("chip_id"))
- .unwrap();
- }
-
- #[test]
- fn test_session_update_multicast_list() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let cmd = SessionUpdateControllerMulticastListCmdBuilder {
- session_id: 5,
- action: UpdateMulticastListAction::AddControlee,
- payload: Some(Bytes::from(vec![0])),
- }
- .build();
- let rsp = SessionUpdateControllerMulticastListRspBuilder {
- status: StatusCode::UciStatusOk,
- }
- .build();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::SessionUpdateControllerMulticastListRsp(rsp)),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(
- JNICommand::UciSessionUpdateMulticastList {
- session_id: 5,
- action: UpdateMulticastListAction::AddControlee.to_u8().unwrap(),
- no_of_controlee: 0,
- address_list: Vec::new(),
- sub_session_id_list: Vec::new(),
- message_control: 8,
- sub_session_key_list: Vec::new(),
- },
- String::from("chip_id"),
- )
- .unwrap();
- }
-
- #[test]
- fn test_set_country_code() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let cmd = AndroidSetCountryCodeCmdBuilder { country_code: [45, 34] }.build();
- let rsp =
- AndroidSetCountryCodeRspBuilder { status: StatusCode::UciStatusOk }.build();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::AndroidSetCountryCodeRsp(rsp)),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(
- JNICommand::UciSetCountryCode { code: vec![45, 34] },
- String::from("chip_id"),
- )
- .unwrap();
- }
-
- #[test]
- fn test_set_app_config() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let cmd = SessionSetAppConfigCmdBuilder { session_id: 5, tlvs: Vec::new() }.build();
- let rsp = SessionSetAppConfigRspBuilder {
- status: StatusCode::UciStatusOk,
- cfg_status: Vec::new(),
- }
- .build();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::SessionSetAppConfigRsp(rsp)),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(
- JNICommand::UciSetAppConfig {
- session_id: 5,
- no_of_params: 0,
- app_config_param_len: 0,
- app_configs: Vec::new(),
- },
- String::from("chip_id"),
- )
- .unwrap();
- }
-
- #[test]
- fn test_get_app_config() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let cmd =
- SessionGetAppConfigCmdBuilder { session_id: 5, app_cfg: Vec::new() }.build();
- let rsp = SessionGetAppConfigRspBuilder {
- status: StatusCode::UciStatusOk,
- tlvs: Vec::new(),
- }
- .build();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::SessionGetAppConfigRsp(rsp)),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(
- JNICommand::UciGetAppConfig {
- session_id: 5,
- no_of_params: 0,
- app_config_param_len: 0,
- app_configs: Vec::new(),
- },
- String::from("chip_id"),
- )
- .unwrap();
- }
-
- #[test]
- fn test_raw_vendor_cmd() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let cmd = UciVendor_9_CommandBuilder { opcode: 5, payload: None }.build();
- let rsp = UciVendor_9_ResponseBuilder { opcode: 5, payload: None }.build();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::RawVendorRsp(rsp.into())),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(
- JNICommand::UciRawVendorCmd { gid: 9, oid: 5, payload: Vec::new() },
- String::from("chip_id"),
- )
- .unwrap();
- }
-
- #[test]
- fn test_device_reset() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let cmd = DeviceResetCmdBuilder { reset_config: ResetConfig::UwbsReset }.build();
- let rsp = DeviceResetRspBuilder { status: StatusCode::UciStatusOk }.build();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::DeviceResetRsp(rsp)),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(
- JNICommand::UciDeviceReset { reset_config: 0 },
- String::from("chip_id"),
- )
- .unwrap();
- }
-
- #[test]
- fn test_get_power_stats() {
- let (dispatcher, _hal_sender) =
- setup_dispatcher_and_return_hal_cb_sender(|mock_adaptation, _mock_event_manager| {
- let cmd = AndroidGetPowerStatsCmdBuilder {}.build();
- let rsp = AndroidGetPowerStatsRspBuilder {
- stats: PowerStats {
- status: StatusCode::UciStatusOk,
- idle_time_ms: 0,
- tx_time_ms: 0,
- rx_time_ms: 0,
- total_wake_count: 0,
- },
- }
- .build();
- mock_adaptation.expect_send_uci_message(
- cmd.into(),
- Some(UciResponse::AndroidGetPowerStatsRsp(rsp)),
- None,
- Ok(()),
- );
- });
-
- dispatcher
- .block_on_jni_command(JNICommand::UciGetPowerStats, String::from("chip_id"))
- .unwrap();
- }
-}
diff --git a/src/rust/uci/uci_hmsgs.rs b/src/rust/uci/uci_hmsgs.rs
deleted file mode 100644
index 3f6e2ab..0000000
--- a/src/rust/uci/uci_hmsgs.rs
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-use crate::uci::UwbErr;
-use bytes::{BufMut, Bytes, BytesMut};
-use log::error;
-use num_traits::FromPrimitive;
-use uwb_uci_packets::{
- write_controlee, write_controlee_2_0_0byte, write_controlee_2_0_16byte,
- write_controlee_2_0_32byte, AndroidSetCountryCodeCmdBuilder, AppConfigTlv, Controlee,
- Controlee_V2_0_0_Byte_Version, Controlee_V2_0_16_Byte_Version, Controlee_V2_0_32_Byte_Version,
- DeviceResetCmdBuilder, GroupId, MessageControl, ResetConfig, SessionInitCmdBuilder,
- SessionSetAppConfigCmdBuilder, SessionType, SessionUpdateControllerMulticastListCmdBuilder,
- UciCommandPacket, UciVendor_9_CommandBuilder, UciVendor_A_CommandBuilder,
- UciVendor_B_CommandBuilder, UciVendor_E_CommandBuilder, UciVendor_F_CommandBuilder,
- UpdateMulticastListAction,
-};
-
-pub fn build_session_init_cmd(
- session_id: u32,
- session_type: u8,
-) -> Result<SessionInitCmdBuilder, UwbErr> {
- Ok(SessionInitCmdBuilder {
- session_id,
- session_type: SessionType::from_u8(session_type).ok_or(UwbErr::InvalidArgs)?,
- })
-}
-
-pub fn build_set_country_code_cmd(code: &[u8]) -> Result<AndroidSetCountryCodeCmdBuilder, UwbErr> {
- Ok(AndroidSetCountryCodeCmdBuilder { country_code: code.try_into()? })
-}
-
-pub fn build_multicast_list_update_cmd(
- session_id: u32,
- action: u8,
- no_of_controlee: u8,
- address_list: &[i16],
- sub_session_id_list: &[i32],
- message_control: Option<MessageControl>,
- sub_session_key_list: &[Vec<u8>],
-) -> Result<SessionUpdateControllerMulticastListCmdBuilder, UwbErr> {
- if usize::from(no_of_controlee) != address_list.len()
- || usize::from(no_of_controlee) != sub_session_id_list.len()
- {
- return Err(UwbErr::InvalidArgs);
- }
- let mut controlees_buf = BytesMut::new();
- controlees_buf.put_u8(no_of_controlee);
- match message_control {
- None => {
- for i in 0..no_of_controlee {
- controlees_buf.extend_from_slice(&write_controlee(&Controlee {
- short_address: address_list[i as usize] as u16,
- subsession_id: sub_session_id_list[i as usize] as u32,
- }));
- }
- }
- Some(MessageControl::SubSessionKeyNotConfigured) => {
- for i in 0..no_of_controlee {
- controlees_buf.extend_from_slice(&write_controlee_2_0_0byte(
- &Controlee_V2_0_0_Byte_Version {
- short_address: address_list[i as usize] as u16,
- subsession_id: sub_session_id_list[i as usize] as u32,
- message_control: MessageControl::SubSessionKeyNotConfigured,
- },
- ));
- }
- }
- Some(MessageControl::ShortSubSessionKeyConfigured) => {
- for i in 0..no_of_controlee {
- controlees_buf.extend_from_slice(&write_controlee_2_0_16byte(
- &Controlee_V2_0_16_Byte_Version {
- short_address: address_list[i as usize] as u16,
- subsession_id: sub_session_id_list[i as usize] as u32,
- message_control: MessageControl::ShortSubSessionKeyConfigured,
- subsession_key: sub_session_key_list[i as usize]
- .clone()
- .try_into()
- .map_err(|_| UwbErr::InvalidArgs)?,
- },
- ));
- }
- }
- Some(MessageControl::LongSubSessionKeyConfigured) => {
- for i in 0..no_of_controlee {
- controlees_buf.extend_from_slice(&write_controlee_2_0_32byte(
- &Controlee_V2_0_32_Byte_Version {
- short_address: address_list[i as usize] as u16,
- subsession_id: sub_session_id_list[i as usize] as u32,
- message_control: MessageControl::LongSubSessionKeyConfigured,
- subsession_key: sub_session_key_list[i as usize]
- .clone()
- .try_into()
- .map_err(|_| UwbErr::InvalidArgs)?,
- },
- ));
- }
- }
- }
- Ok(SessionUpdateControllerMulticastListCmdBuilder {
- session_id,
- action: UpdateMulticastListAction::from_u8(action).ok_or(UwbErr::InvalidArgs)?,
- payload: Some(controlees_buf.freeze()),
- })
-}
-
-pub fn build_set_app_config_cmd(
- session_id: u32,
- no_of_params: u32,
- mut app_configs: &[u8],
-) -> Result<SessionSetAppConfigCmdBuilder, UwbErr> {
- let mut tlvs = Vec::new();
- let received_tlvs_len = app_configs.len();
- let mut parsed_tlvs_len = 0;
- for _ in 0..no_of_params {
- let tlv = AppConfigTlv::parse(app_configs)?;
- app_configs = app_configs.get(tlv.v.len() + 2..).ok_or(UwbErr::InvalidArgs)?;
- parsed_tlvs_len += tlv.v.len() + 2;
- tlvs.push(tlv);
- }
- if parsed_tlvs_len != received_tlvs_len {
- error!("Parsed TLV len: {:?}, received len: {:?}", parsed_tlvs_len, received_tlvs_len);
- return Err(UwbErr::InvalidArgs);
- }
- Ok(SessionSetAppConfigCmdBuilder { session_id, tlvs })
-}
-
-pub fn build_uci_vendor_cmd_packet(
- gid: u32,
- oid: u32,
- payload: Vec<u8>,
-) -> Result<UciCommandPacket, UwbErr> {
- use GroupId::*;
- let group_id: GroupId = GroupId::from_u32(gid).ok_or(UwbErr::InvalidArgs)?;
- let payload = if payload.is_empty() { None } else { Some(Bytes::from(payload)) };
- let opcode: u8 = oid.try_into()?;
- let packet: UciCommandPacket = match group_id {
- VendorReserved9 => UciVendor_9_CommandBuilder { opcode, payload }.build().into(),
- VendorReservedA => UciVendor_A_CommandBuilder { opcode, payload }.build().into(),
- VendorReservedB => UciVendor_B_CommandBuilder { opcode, payload }.build().into(),
- VendorReservedE => UciVendor_E_CommandBuilder { opcode, payload }.build().into(),
- VendorReservedF => UciVendor_F_CommandBuilder { opcode, payload }.build().into(),
- _ => {
- error!("Invalid vendor gid {:?}", gid);
- return Err(UwbErr::InvalidArgs);
- }
- };
- Ok(packet)
-}
-
-pub fn build_device_reset_cmd(reset_config: u8) -> Result<DeviceResetCmdBuilder, UwbErr> {
- Ok(DeviceResetCmdBuilder {
- reset_config: ResetConfig::from_u8(reset_config).ok_or(UwbErr::InvalidArgs)?,
- })
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use num_traits::ToPrimitive;
- use uwb_uci_packets::*;
-
- #[test]
- fn test_build_uci_vendor_cmd_packet() {
- let oid: u8 = 6;
- let gid = GroupId::VendorReserved9;
- let payload = vec![0x5, 0x5, 0x5, 0x5];
- assert_eq!(
- build_uci_vendor_cmd_packet(gid.to_u32().unwrap(), oid.into(), payload.clone())
- .unwrap()
- .to_bytes(),
- UciVendor_9_CommandBuilder { opcode: oid, payload: Some(Bytes::from(payload)) }
- .build()
- .to_bytes()
- );
- }
-}
diff --git a/src/rust/uci/uci_hrcv.rs b/src/rust/uci/uci_hrcv.rs
deleted file mode 100644
index c79b7c6..0000000
--- a/src/rust/uci/uci_hrcv.rs
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-use crate::error::UwbErr;
-use uwb_uci_packets::*;
-
-#[derive(Debug)]
-pub enum UciMessage {
- Response(UciResponse),
- Notification(UciNotification),
-}
-
-#[derive(Debug, Clone)]
-pub enum UciResponse {
- GetDeviceInfoRsp(GetDeviceInfoRspPacket),
- GetCapsInfoRsp(GetCapsInfoRspPacket),
- SetConfigRsp(SetConfigRspPacket),
- GetConfigRsp(GetConfigRspPacket),
- DeviceResetRsp(DeviceResetRspPacket),
- SessionInitRsp(SessionInitRspPacket),
- SessionDeinitRsp(SessionDeinitRspPacket),
- SessionGetAppConfigRsp(SessionGetAppConfigRspPacket),
- SessionSetAppConfigRsp(SessionSetAppConfigRspPacket),
- SessionGetStateRsp(SessionGetStateRspPacket),
- SessionGetCountRsp(SessionGetCountRspPacket),
- SessionUpdateControllerMulticastListRsp(SessionUpdateControllerMulticastListRspPacket),
- RangeStartRsp(RangeStartRspPacket),
- RangeStopRsp(RangeStopRspPacket),
- RangeGetRangingCountRsp(RangeGetRangingCountRspPacket),
- AndroidSetCountryCodeRsp(AndroidSetCountryCodeRspPacket),
- AndroidGetPowerStatsRsp(AndroidGetPowerStatsRspPacket),
- RawVendorRsp(UciResponsePacket),
- EnableRsp(bool),
- DisableRsp,
-}
-
-#[derive(Debug, Clone)]
-pub enum UciNotification {
- GenericError(GenericErrorPacket),
- DeviceStatusNtf(DeviceStatusNtfPacket),
- SessionStatusNtf(SessionStatusNtfPacket),
- SessionUpdateControllerMulticastListNtf(SessionUpdateControllerMulticastListNtfPacket),
- ShortMacTwoWayRangeDataNtf(ShortMacTwoWayRangeDataNtfPacket),
- ExtendedMacTwoWayRangeDataNtf(ExtendedMacTwoWayRangeDataNtfPacket),
- AndroidRangeDiagnosticsNtf(ParsedDiagnosticNtfPacket),
- RawVendorNtf(UciNotificationPacket),
-}
-
-pub fn uci_message(evt: UciPacketPacket) -> Result<UciMessage, UwbErr> {
- match evt.specialize() {
- UciPacketChild::UciResponse(evt) => Ok(UciMessage::Response(uci_response(evt).unwrap())),
- UciPacketChild::UciNotification(evt) => {
- Ok(UciMessage::Notification(uci_notification(evt).unwrap()))
- }
- _ => Err(UwbErr::Specialize(evt.to_vec())),
- }
-}
-
-pub fn uci_response(evt: UciResponsePacket) -> Result<UciResponse, UwbErr> {
- match evt.specialize() {
- UciResponseChild::CoreResponse(evt) => core_response(evt),
- UciResponseChild::SessionResponse(evt) => session_response(evt),
- UciResponseChild::RangingResponse(evt) => ranging_response(evt),
- UciResponseChild::AndroidResponse(evt) => android_response(evt),
- UciResponseChild::UciVendor_9_Response(evt) => vendor_response(evt.into()),
- UciResponseChild::UciVendor_A_Response(evt) => vendor_response(evt.into()),
- UciResponseChild::UciVendor_B_Response(evt) => vendor_response(evt.into()),
- UciResponseChild::UciVendor_E_Response(evt) => vendor_response(evt.into()),
- UciResponseChild::UciVendor_F_Response(evt) => vendor_response(evt.into()),
- _ => Err(UwbErr::Specialize(evt.to_vec())),
- }
-}
-
-pub fn uci_notification(evt: UciNotificationPacket) -> Result<UciNotification, UwbErr> {
- match evt.specialize() {
- UciNotificationChild::CoreNotification(evt) => core_notification(evt),
- UciNotificationChild::SessionNotification(evt) => session_notification(evt),
- UciNotificationChild::RangingNotification(evt) => ranging_notification(evt),
- UciNotificationChild::AndroidNotification(evt) => android_notification(evt),
- UciNotificationChild::UciVendor_9_Notification(evt) => vendor_notification(evt.into()),
- UciNotificationChild::UciVendor_A_Notification(evt) => vendor_notification(evt.into()),
- UciNotificationChild::UciVendor_B_Notification(evt) => vendor_notification(evt.into()),
- UciNotificationChild::UciVendor_E_Notification(evt) => vendor_notification(evt.into()),
- UciNotificationChild::UciVendor_F_Notification(evt) => vendor_notification(evt.into()),
- _ => Err(UwbErr::Specialize(evt.to_vec())),
- }
-}
-
-fn core_response(evt: CoreResponsePacket) -> Result<UciResponse, UwbErr> {
- match evt.specialize() {
- CoreResponseChild::GetDeviceInfoRsp(evt) => Ok(UciResponse::GetDeviceInfoRsp(evt)),
- CoreResponseChild::GetCapsInfoRsp(evt) => Ok(UciResponse::GetCapsInfoRsp(evt)),
- CoreResponseChild::SetConfigRsp(evt) => Ok(UciResponse::SetConfigRsp(evt)),
- CoreResponseChild::GetConfigRsp(evt) => Ok(UciResponse::GetConfigRsp(evt)),
- CoreResponseChild::DeviceResetRsp(evt) => Ok(UciResponse::DeviceResetRsp(evt)),
- _ => Err(UwbErr::Specialize(evt.to_vec())),
- }
-}
-
-fn session_response(evt: SessionResponsePacket) -> Result<UciResponse, UwbErr> {
- match evt.specialize() {
- SessionResponseChild::SessionInitRsp(evt) => Ok(UciResponse::SessionInitRsp(evt)),
- SessionResponseChild::SessionDeinitRsp(evt) => Ok(UciResponse::SessionDeinitRsp(evt)),
- SessionResponseChild::SessionSetAppConfigRsp(evt) => {
- Ok(UciResponse::SessionSetAppConfigRsp(evt))
- }
- SessionResponseChild::SessionGetAppConfigRsp(evt) => {
- Ok(UciResponse::SessionGetAppConfigRsp(evt))
- }
- SessionResponseChild::SessionGetStateRsp(evt) => Ok(UciResponse::SessionGetStateRsp(evt)),
- SessionResponseChild::SessionGetCountRsp(evt) => Ok(UciResponse::SessionGetCountRsp(evt)),
- SessionResponseChild::SessionUpdateControllerMulticastListRsp(evt) => {
- Ok(UciResponse::SessionUpdateControllerMulticastListRsp(evt))
- }
- _ => Err(UwbErr::Specialize(evt.to_vec())),
- }
-}
-
-fn ranging_response(evt: RangingResponsePacket) -> Result<UciResponse, UwbErr> {
- match evt.specialize() {
- RangingResponseChild::RangeStartRsp(evt) => Ok(UciResponse::RangeStartRsp(evt)),
- RangingResponseChild::RangeStopRsp(evt) => Ok(UciResponse::RangeStopRsp(evt)),
- RangingResponseChild::RangeGetRangingCountRsp(evt) => {
- Ok(UciResponse::RangeGetRangingCountRsp(evt))
- }
- _ => Err(UwbErr::Specialize(evt.to_vec())),
- }
-}
-
-fn android_response(evt: AndroidResponsePacket) -> Result<UciResponse, UwbErr> {
- match evt.specialize() {
- AndroidResponseChild::AndroidSetCountryCodeRsp(evt) => {
- Ok(UciResponse::AndroidSetCountryCodeRsp(evt))
- }
- AndroidResponseChild::AndroidGetPowerStatsRsp(evt) => {
- Ok(UciResponse::AndroidGetPowerStatsRsp(evt))
- }
- _ => Err(UwbErr::Specialize(evt.to_vec())),
- }
-}
-
-fn vendor_response(evt: UciResponsePacket) -> Result<UciResponse, UwbErr> {
- Ok(UciResponse::RawVendorRsp(evt))
-}
-
-fn core_notification(evt: CoreNotificationPacket) -> Result<UciNotification, UwbErr> {
- match evt.specialize() {
- CoreNotificationChild::DeviceStatusNtf(evt) => Ok(UciNotification::DeviceStatusNtf(evt)),
- CoreNotificationChild::GenericError(evt) => Ok(UciNotification::GenericError(evt)),
- _ => Err(UwbErr::Specialize(evt.to_vec())),
- }
-}
-
-fn session_notification(evt: SessionNotificationPacket) -> Result<UciNotification, UwbErr> {
- match evt.specialize() {
- SessionNotificationChild::SessionStatusNtf(evt) => {
- Ok(UciNotification::SessionStatusNtf(evt))
- }
- SessionNotificationChild::SessionUpdateControllerMulticastListNtf(evt) => {
- Ok(UciNotification::SessionUpdateControllerMulticastListNtf(evt))
- }
- _ => Err(UwbErr::Specialize(evt.to_vec())),
- }
-}
-
-fn ranging_notification(evt: RangingNotificationPacket) -> Result<UciNotification, UwbErr> {
- match evt.specialize() {
- RangingNotificationChild::RangeDataNtf(evt) => range_data_notification(evt),
- _ => Err(UwbErr::Specialize(evt.to_vec())),
- }
-}
-
-fn range_data_notification(evt: RangeDataNtfPacket) -> Result<UciNotification, UwbErr> {
- match evt.specialize() {
- RangeDataNtfChild::ShortMacTwoWayRangeDataNtf(evt) => {
- Ok(UciNotification::ShortMacTwoWayRangeDataNtf(evt))
- }
- RangeDataNtfChild::ExtendedMacTwoWayRangeDataNtf(evt) => {
- Ok(UciNotification::ExtendedMacTwoWayRangeDataNtf(evt))
- }
- _ => Err(UwbErr::Specialize(evt.to_vec())),
- }
-}
-
-fn android_notification(evt: AndroidNotificationPacket) -> Result<UciNotification, UwbErr> {
- match evt.specialize() {
- AndroidNotificationChild::AndroidRangeDiagnosticsNtf(evt) => {
- Ok(UciNotification::AndroidRangeDiagnosticsNtf(parse_diagnostics_ntf(evt)?))
- }
- _ => Err(UwbErr::Specialize(evt.to_vec())),
- }
-}
-
-fn vendor_notification(evt: UciNotificationPacket) -> Result<UciNotification, UwbErr> {
- Ok(UciNotification::RawVendorNtf(evt))
-}
diff --git a/src/rust/uci/uci_logger.rs b/src/rust/uci/uci_logger.rs
deleted file mode 100644
index dce8789..0000000
--- a/src/rust/uci/uci_logger.rs
+++ /dev/null
@@ -1,693 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-extern crate libc;
-
-#[cfg(test)]
-use crate::uci::mock_uci_logger::{create_dir, remove_file, rename, Instant};
-use crate::uci::UwbErr;
-use async_trait::async_trait;
-use log::{error, info};
-use std::marker::Unpin;
-use std::sync::Arc;
-#[cfg(not(test))]
-use std::time::Instant;
-use std::time::SystemTime;
-use tokio::fs::OpenOptions;
-#[cfg(not(test))]
-use tokio::fs::{create_dir, remove_file, rename};
-use tokio::io::{AsyncWrite, AsyncWriteExt};
-use tokio::sync::Mutex;
-use tokio::{task, time};
-use uwb_uci_packets::{
- AppConfigTlv, AppConfigTlvType, Packet, SessionCommandChild, SessionGetAppConfigRspBuilder,
- SessionResponseChild, SessionSetAppConfigCmdBuilder, UciCommandChild, UciCommandPacket,
- UciNotificationPacket, UciPacketPacket, UciResponseChild, UciResponsePacket,
-};
-
-// micros since 0000-01-01
-const UCI_LOG_LAST_FILE_STORE_TIME_SEC: u64 = 86400; // 24 hours
-const MAX_FILE_SIZE: usize = 102400; // 100 KB
-const MAX_BUFFER_SIZE: usize = 10240; // 10 KB
-const VENDOR_ID: u64 = AppConfigTlvType::VendorId as u64;
-const STATIC_STS_IV: u64 = AppConfigTlvType::StaticStsIv as u64;
-const LOG_DIR: &str = "/data/misc/apexdata/com.android.uwb/log";
-const FILE_NAME: &str = "uwb_uci.pcapng";
-
-type SyncFile = Arc<Mutex<dyn AsyncWrite + Send + Sync + Unpin>>;
-type SyncFactory = Arc<Mutex<dyn FileFactory + Send + Sync>>;
-
-#[derive(Clone, PartialEq, Eq)]
-pub enum UciLogMode {
- Disabled,
- Filtered,
- Enabled,
-}
-
-#[derive(Clone)]
-pub struct UciLogConfig {
- path: String,
- mode: UciLogMode,
-}
-
-impl UciLogConfig {
- pub fn new(mode: UciLogMode) -> Self {
- Self { path: format!("{}/{}", LOG_DIR, FILE_NAME), mode }
- }
-}
-
-#[async_trait]
-pub trait UciLogger {
- async fn log_uci_command(&self, cmd: UciCommandPacket);
- async fn log_uci_response(&self, rsp: UciResponsePacket);
- async fn log_uci_notification(&self, ntf: UciNotificationPacket);
- async fn close_file(&self);
-}
-
-struct BufferedFile {
- file: Option<SyncFile>,
- written_size: usize,
- buffer: Vec<u8>,
- deleter_handle: Option<task::JoinHandle<()>>,
-}
-
-impl BufferedFile {
- async fn open_next_file(&mut self, factory: SyncFactory, path: &str) -> Result<(), UwbErr> {
- info!("Open next file");
- self.close_file().await;
- if create_dir(LOG_DIR).await.is_err() {
- error!("Failed to create dir");
- }
- if rename(path, path.to_owned() + ".last").await.is_err() {
- error!("Failed to rename the file");
- }
- if let Some(deleter_handle) = self.deleter_handle.take() {
- deleter_handle.abort();
- }
- let last_file_path = path.to_owned() + ".last";
- self.deleter_handle = Some(task::spawn(async {
- time::sleep(time::Duration::from_secs(UCI_LOG_LAST_FILE_STORE_TIME_SEC)).await;
- if remove_file(last_file_path).await.is_err() {
- error!("Failed to remove file!");
- };
- }));
- let file = factory.lock().await.create_file_using_open_options(path).await?;
- self.file = Some(file);
- let header = get_pcapng_header();
- self.buffered_write(header).await;
- Ok(())
- }
-
- fn file_size(&self) -> usize {
- self.written_size + self.buffer.len()
- }
-
- async fn buffered_write(&mut self, mut data: Vec<u8>) {
- if self.buffer.len() + data.len() >= MAX_BUFFER_SIZE {
- self.flush_buffer().await;
- }
- self.buffer.append(&mut data);
- }
-
- async fn close_file(&mut self) {
- if self.file.is_some() {
- info!("UCI log file closing");
- self.flush_buffer().await;
- self.file = None;
- }
- self.written_size = 0;
- }
-
- async fn flush_buffer(&mut self) {
- let mut locked_file = match &self.file {
- Some(file) => file.lock().await,
- None => {
- return;
- }
- };
- if locked_file.write_all(&self.buffer).await.is_err() {
- error!("Failed to write");
- return;
- }
- if let Err(e) = locked_file.flush().await {
- error!("Failed to flush: {:?}", e);
- return;
- }
- self.written_size += self.buffer.len();
- self.buffer.clear();
- }
-}
-
-pub struct UciLoggerImpl {
- config: UciLogConfig,
- buf_file: Mutex<BufferedFile>,
- file_factory: SyncFactory,
- start_time: Instant,
-}
-
-impl UciLoggerImpl {
- pub async fn new(mode: UciLogMode, file_factory: SyncFactory) -> Self {
- let config = UciLogConfig::new(mode);
- let mut factory = file_factory.lock().await;
- factory.set_config(config.clone()).await;
- let (file, size) = factory.new_file().await;
- let buf_file = BufferedFile {
- written_size: size,
- file,
- buffer: Vec::with_capacity(MAX_BUFFER_SIZE),
- deleter_handle: None,
- };
- let ret = Self {
- config,
- buf_file: Mutex::new(buf_file),
- file_factory: file_factory.clone(),
- start_time: Instant::now(),
- };
- info!("UCI logger created");
- ret
- }
-
- async fn log_uci_packet(&self, packet: UciPacketPacket) {
- const HEADER_SIZE: usize = 48;
- let bytes = packet.to_vec();
- let timestamp = self.start_time.elapsed().as_micros() as u64;
- let enhanced_block = EnhancedBlockBuilder::new()
- .interface_id(0)
- .timestamp(timestamp)
- .packet(bytes)
- .max_block_size(MAX_FILE_SIZE - HEADER_SIZE)
- .build();
- // Checks whether the enhanced_block fits inside the file:
- let mut buf_file = self.buf_file.lock().await;
- if buf_file.file_size() + enhanced_block.len() > MAX_FILE_SIZE {
- match buf_file.open_next_file(self.file_factory.clone(), &self.config.path).await {
- Ok(()) => info!("Created new pcagng log file"),
- Err(e) => {
- error!("Failed to open new pcapng log file: {:?}", e);
- return;
- }
- }
- }
- buf_file.buffered_write(enhanced_block).await;
- }
-}
-
-/// Constructs Enhanced Packet Block from raw packet and additional fields.
-struct EnhancedBlockBuilder {
- interface_id: u32,
- timestamp: u64,
- packet: Vec<u8>,
- max_block_size: Option<usize>,
-}
-impl EnhancedBlockBuilder {
- /// Constructor.
- fn new() -> Self {
- Self { interface_id: 0, timestamp: 0, packet: vec![], max_block_size: None }
- }
-
- /// Sets interface_id.
- fn interface_id(mut self, interface_id: u32) -> Self {
- self.interface_id = interface_id;
- self
- }
-
- /// Sets timestamp.
- fn timestamp(mut self, timestamp: u64) -> Self {
- self.timestamp = timestamp;
- self
- }
-
- /// Sets packet.
- fn packet(mut self, packet: Vec<u8>) -> Self {
- self.packet = packet;
- self
- }
-
- /// Sets maximum block size permitted (optional). Truncated down to nearest multiple of 4.
- fn max_block_size(mut self, max_size: usize) -> Self {
- self.max_block_size = Some(max_size / 4 * 4);
- self
- }
-
- /// Builds the packet.
- fn build(mut self) -> Vec<u8> {
- const ENHANCED_BLOCK_SIZE: usize = 32;
- let packet_length = self.packet.len() as u32;
- let padded_data_length = (self.packet.len() + 3) / 4 * 4; // padded to multiple of 4.
- let mut pad_length = padded_data_length - self.packet.len();
- let mut block_total_length = padded_data_length + ENHANCED_BLOCK_SIZE;
- if let Some(max_block_size) = self.max_block_size {
- if block_total_length > max_block_size {
- self.packet.truncate(max_block_size - ENHANCED_BLOCK_SIZE);
- pad_length = 0;
- block_total_length = max_block_size;
- }
- }
- let mut block_data = Vec::<u8>::new();
- block_data.extend_from_slice(&u32::to_le_bytes(0x00000006)); // Block Type
- block_data.extend_from_slice(&u32::to_le_bytes(block_total_length.try_into().unwrap()));
- block_data.extend_from_slice(&u32::to_le_bytes(self.interface_id)); // Interface ID
- // High timestamp
- block_data.extend_from_slice(&u32::to_le_bytes((self.timestamp >> 32) as u32));
- // Low timestamp
- block_data.extend_from_slice(&u32::to_le_bytes(self.timestamp as u32));
- // Captured Packet Length
- block_data.extend_from_slice(&u32::to_le_bytes(self.packet.len() as u32));
- block_data.extend_from_slice(&u32::to_le_bytes(packet_length)); // Original Packet Length
- block_data.append(&mut self.packet);
- block_data.extend_from_slice(&vec![0; pad_length]);
- block_data.extend_from_slice(&u32::to_le_bytes(block_total_length.try_into().unwrap()));
- block_data
- }
-}
-
-fn get_pcapng_header() -> Vec<u8> {
- let mut bytes = vec![];
- // PCAPng files must start with a Section Header Block.
- bytes.extend_from_slice(&u32::to_le_bytes(0x0A0D0D0A)); // Block Type
- bytes.extend_from_slice(&u32::to_le_bytes(28)); // Block Total Length
- bytes.extend_from_slice(&u32::to_le_bytes(0x1A2B3C4D)); // Byte-Order Magic
- bytes.extend_from_slice(&u16::to_le_bytes(1)); // Major Version
- bytes.extend_from_slice(&u16::to_le_bytes(0)); // Minor Version
- bytes.extend_from_slice(&u64::to_le_bytes(0xFFFFFFFFFFFFFFFF)); // Section Length (not specified)
- bytes.extend_from_slice(&u32::to_le_bytes(28)); // Block Total Length
-
- // Write the Interface Description Block used for all
- // UCI records.
- bytes.extend_from_slice(&u32::to_le_bytes(0x00000001)); // Block Type
- bytes.extend_from_slice(&u32::to_le_bytes(20)); // Block Total Length
- bytes.extend_from_slice(&u16::to_le_bytes(293)); // LinkType
- bytes.extend_from_slice(&u16::to_le_bytes(0)); // Reserved
- bytes.extend_from_slice(&u32::to_le_bytes(0)); // SnapLen (no limit)
- bytes.extend_from_slice(&u32::to_le_bytes(20)); // Block Total Length
- bytes
-}
-
-#[async_trait]
-impl UciLogger for UciLoggerImpl {
- async fn log_uci_command(&self, cmd: UciCommandPacket) {
- match self.config.mode {
- UciLogMode::Disabled => return,
- UciLogMode::Enabled => self.log_uci_packet(cmd.into()).await,
- UciLogMode::Filtered => {
- let filtered_cmd: UciCommandPacket = match cmd.specialize() {
- UciCommandChild::SessionCommand(session_cmd) => {
- match session_cmd.specialize() {
- SessionCommandChild::SessionSetAppConfigCmd(set_config_cmd) => {
- let session_id = set_config_cmd.get_session_id();
- let tlvs = set_config_cmd.get_tlvs();
- let mut filtered_tlvs = Vec::new();
- for tlv in tlvs {
- if VENDOR_ID == tlv.cfg_id as u64
- || STATIC_STS_IV == tlv.cfg_id as u64
- {
- filtered_tlvs.push(AppConfigTlv {
- cfg_id: tlv.cfg_id,
- v: vec![0; tlv.v.len()],
- });
- } else {
- filtered_tlvs.push(tlv.clone());
- }
- }
- SessionSetAppConfigCmdBuilder { session_id, tlvs: filtered_tlvs }
- .build()
- .into()
- }
- _ => session_cmd.into(),
- }
- }
- _ => cmd,
- };
- self.log_uci_packet(filtered_cmd.into()).await;
- }
- }
- }
-
- async fn log_uci_response(&self, rsp: UciResponsePacket) {
- match self.config.mode {
- UciLogMode::Disabled => return,
- UciLogMode::Enabled => self.log_uci_packet(rsp.into()).await,
- UciLogMode::Filtered => {
- let filtered_rsp: UciResponsePacket = match rsp.specialize() {
- UciResponseChild::SessionResponse(session_rsp) => {
- match session_rsp.specialize() {
- SessionResponseChild::SessionGetAppConfigRsp(rsp) => {
- let status = rsp.get_status();
- let tlvs = rsp.get_tlvs();
- let mut filtered_tlvs = Vec::new();
- for tlv in tlvs {
- if VENDOR_ID == tlv.cfg_id as u64
- || STATIC_STS_IV == tlv.cfg_id as u64
- {
- filtered_tlvs.push(AppConfigTlv {
- cfg_id: tlv.cfg_id,
- v: vec![0; tlv.v.len()],
- });
- } else {
- filtered_tlvs.push(tlv.clone());
- }
- }
- SessionGetAppConfigRspBuilder { status, tlvs: filtered_tlvs }
- .build()
- .into()
- }
- _ => session_rsp.into(),
- }
- }
- _ => rsp,
- };
- self.log_uci_packet(filtered_rsp.into()).await;
- }
- }
- }
-
- async fn log_uci_notification(&self, ntf: UciNotificationPacket) {
- if self.config.mode == UciLogMode::Disabled {
- return;
- }
- // No notifications to be filtered.
- self.log_uci_packet(ntf.into()).await;
- }
-
- async fn close_file(&self) {
- if self.config.mode == UciLogMode::Disabled {
- return;
- }
- self.buf_file.lock().await.close_file().await;
- }
-}
-
-#[async_trait]
-pub trait FileFactory {
- async fn new_file(&self) -> (Option<SyncFile>, usize);
- async fn create_file_using_open_options(&self, path: &str) -> Result<SyncFile, UwbErr>;
- async fn create_file_at_path(&self, path: &str) -> Option<SyncFile>;
- async fn set_config(&mut self, config: UciLogConfig);
-}
-
-#[derive(Default)]
-pub struct RealFileFactory {
- config: Option<UciLogConfig>,
-}
-
-#[async_trait]
-impl FileFactory for RealFileFactory {
- async fn new_file(&self) -> (Option<SyncFile>, usize) {
- match OpenOptions::new()
- .append(true)
- .custom_flags(libc::O_NOFOLLOW)
- .open(&self.config.as_ref().unwrap().path)
- .await
- .ok()
- {
- Some(f) => {
- let size = match f.metadata().await {
- Ok(md) => {
- let duration = match md.modified() {
- Ok(modified_date) => {
- match SystemTime::now().duration_since(modified_date) {
- Ok(duration) => duration.as_secs(),
- Err(e) => {
- error!("Failed to convert to duration {:?}", e);
- 0
- }
- }
- }
- Err(e) => {
- error!("Failed to convert to duration {:?}", e);
- 0
- }
- };
- if duration > UCI_LOG_LAST_FILE_STORE_TIME_SEC {
- 0
- } else {
- md.len().try_into().unwrap()
- }
- }
- Err(e) => {
- error!("Failed to get metadata {:?}", e);
- 0
- }
- };
- match size {
- 0 => {
- (self.create_file_at_path(&self.config.as_ref().unwrap().path).await, size)
- }
- _ => (Some(Arc::new(Mutex::new(f))), size),
- }
- }
- None => (self.create_file_at_path(&self.config.as_ref().unwrap().path).await, 0),
- }
- }
-
- async fn set_config(&mut self, config: UciLogConfig) {
- self.config = Some(config);
- }
-
- async fn create_file_using_open_options(&self, path: &str) -> Result<SyncFile, UwbErr> {
- Ok(Arc::new(Mutex::new(OpenOptions::new().write(true).create_new(true).open(path).await?)))
- }
-
- async fn create_file_at_path(&self, path: &str) -> Option<SyncFile> {
- if create_dir(LOG_DIR).await.is_err() {
- error!("Failed to create dir");
- }
- if remove_file(path).await.is_err() {
- error!("Failed to remove file!");
- }
- match self.create_file_using_open_options(path).await {
- Ok(f) => Some(f),
- Err(e) => {
- error!("Failed to create file {:?}", e);
- None
- }
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use core::pin::Pin;
- use core::task::{Context, Poll};
- use log::debug;
- use std::io::Error;
- use uwb_uci_packets::{
- AppConfigTlvType, DeviceState, DeviceStatusNtfBuilder, GetDeviceInfoCmdBuilder,
- GetDeviceInfoRspBuilder, StatusCode,
- };
-
- struct MockLogFile;
-
- impl MockLogFile {
- #[allow(dead_code)]
- async fn write_all(&mut self, _data: &[u8]) -> Result<(), UwbErr> {
- debug!("Write to fake file");
- Ok(())
- }
- #[allow(dead_code)]
- async fn flush(&self) -> Result<(), UwbErr> {
- debug!("Fake file flush success");
- Ok(())
- }
- }
-
- impl AsyncWrite for MockLogFile {
- fn poll_write(
- self: Pin<&mut Self>,
- _cx: &mut Context<'_>,
- _buf: &[u8],
- ) -> Poll<Result<usize, Error>> {
- Poll::Ready(Ok(0))
- }
-
- fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
- Poll::Ready(Ok(()))
- }
-
- fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
- Poll::Ready(Ok(()))
- }
- }
-
- struct MockFileFactory;
-
- #[async_trait]
- impl FileFactory for MockFileFactory {
- async fn new_file(&self) -> (Option<SyncFile>, usize) {
- (Some(Arc::new(Mutex::new(MockLogFile {}))), 0)
- }
- async fn set_config(&mut self, _config: UciLogConfig) {}
- async fn create_file_using_open_options(&self, _path: &str) -> Result<SyncFile, UwbErr> {
- Ok(Arc::new(Mutex::new(MockLogFile {})))
- }
- async fn create_file_at_path(&self, _path: &str) -> Option<SyncFile> {
- Some(Arc::new(Mutex::new(MockLogFile {})))
- }
- }
-
- #[test]
- fn test_enhanced_packet_build() {
- let uci_packet: Vec<u8> = vec![0x41, 0x03, 0x00, 0x02, 0x00, 0x00];
- let timestamp: u64 = 0x0102_0304_0506_0708;
- let interface_id: u32 = 0;
- let enhanced_block = EnhancedBlockBuilder::new()
- .timestamp(timestamp)
- .interface_id(interface_id)
- .packet(uci_packet)
- .build();
-
- let expected_block: Vec<u8> = vec![
- 0x06, 0x00, 0x00, 0x00, // block type
- // packet is of length 6, padded to 8, with total length 40=0x28
- 0x28, 0x00, 0x00, 0x00, // block length
- 0x00, 0x00, 0x00, 0x00, // interface id
- 0x04, 0x03, 0x02, 0x01, // timestamp high
- 0x08, 0x07, 0x06, 0x05, // timestemp low
- 0x06, 0x00, 0x00, 0x00, // captured length
- 0x06, 0x00, 0x00, 0x00, // original length
- 0x41, 0x03, 0x00, 0x02, // packet (padded)
- 0x00, 0x00, 0x00, 0x00, // packet (padded)
- 0x28, 0x00, 0x00, 0x00, // block length
- ];
- assert_eq!(&enhanced_block, &expected_block);
- }
-
- #[test]
- fn test_enhanced_packet_truncate_build() {
- let uci_packet: Vec<u8> = vec![0x41, 0x03, 0x00, 0x02, 0x00, 0x00];
- let timestamp: u64 = 0x0102_0304_0506_0708;
- let interface_id: u32 = 0;
- let enhanced_block = EnhancedBlockBuilder::new()
- .timestamp(timestamp)
- .interface_id(interface_id)
- .packet(uci_packet)
- .max_block_size(0x24) // packet need truncation
- .build();
-
- let expected_block: Vec<u8> = vec![
- 0x06, 0x00, 0x00, 0x00, // block type
- 0x24, 0x00, 0x00, 0x00, // block length
- 0x00, 0x00, 0x00, 0x00, // interface id
- 0x04, 0x03, 0x02, 0x01, // timestamp high
- 0x08, 0x07, 0x06, 0x05, // timestemp low
- 0x04, 0x00, 0x00, 0x00, // captured length
- 0x06, 0x00, 0x00, 0x00, // original length
- 0x41, 0x03, 0x00, 0x02, // packet (truncated)
- 0x24, 0x00, 0x00, 0x00, // block length
- ];
- assert_eq!(&enhanced_block, &expected_block);
- }
-
- #[tokio::test]
- async fn test_log_command() -> Result<(), UwbErr> {
- let logger =
- UciLoggerImpl::new(UciLogMode::Filtered, Arc::new(Mutex::new(MockFileFactory {})))
- .await;
- let cmd: UciCommandPacket = GetDeviceInfoCmdBuilder {}.build().into();
- logger.log_uci_command(cmd).await;
- let expected_buffer = [
- 6, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0,
- 32, 2, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0,
- ];
- let buf_file = logger.buf_file.lock().await;
- assert_eq!(&buf_file.buffer, &expected_buffer);
- Ok(())
- }
-
- #[tokio::test]
- async fn test_log_response() -> Result<(), UwbErr> {
- let logger =
- UciLoggerImpl::new(UciLogMode::Filtered, Arc::new(Mutex::new(MockFileFactory {})))
- .await;
- let rsp = GetDeviceInfoRspBuilder {
- status: StatusCode::UciStatusOk,
- uci_version: 0,
- mac_version: 0,
- phy_version: 0,
- uci_test_version: 0,
- vendor_spec_info: vec![],
- }
- .build()
- .into();
- logger.log_uci_response(rsp).await;
- let expected_buffer = [
- 6, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0,
- 64, 2, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0,
- ];
- let buf_file = logger.buf_file.lock().await;
- assert_eq!(&buf_file.buffer, &expected_buffer);
- Ok(())
- }
-
- #[tokio::test]
- async fn test_log_notification() -> Result<(), UwbErr> {
- let logger =
- UciLoggerImpl::new(UciLogMode::Filtered, Arc::new(Mutex::new(MockFileFactory {})))
- .await;
- let ntf =
- DeviceStatusNtfBuilder { device_state: DeviceState::DeviceStateReady }.build().into();
- logger.log_uci_notification(ntf).await;
- let expected_buffer = [
- 6, 0, 0, 0, // block type
- 40, 0, 0, 0, // block length
- 0, 0, 0, 0, // interface id
- 0, 0, 0, 0, // timestamp high
- 0, 0, 0, 0, // timestamp low
- 8, 0, 0, 0, // captured length
- 8, 0, 0, 0, // original length
- 96, 1, 0, 1, // packet
- 0, 0, 0, 1, // packet
- 40, 0, 0, 0, // block length
- ];
- let buf_file = logger.buf_file.lock().await;
- assert_eq!(&buf_file.buffer, &expected_buffer);
- Ok(())
- }
-
- #[tokio::test]
- async fn test_disabled_log() -> Result<(), UwbErr> {
- let logger =
- UciLoggerImpl::new(UciLogMode::Disabled, Arc::new(Mutex::new(MockFileFactory {})))
- .await;
- let cmd: UciCommandPacket = GetDeviceInfoCmdBuilder {}.build().into();
- logger.log_uci_command(cmd).await;
- let buf_file = logger.buf_file.lock().await;
- assert!(buf_file.buffer.is_empty());
- Ok(())
- }
-
- #[tokio::test]
- async fn test_filter_log() -> Result<(), UwbErr> {
- let logger =
- UciLoggerImpl::new(UciLogMode::Filtered, Arc::new(Mutex::new(MockFileFactory {})))
- .await;
- let rsp = SessionGetAppConfigRspBuilder {
- status: StatusCode::UciStatusOk,
- tlvs: vec![AppConfigTlv { cfg_id: AppConfigTlvType::VendorId, v: vec![0x02, 0x02] }],
- }
- .build()
- .into();
- logger.log_uci_response(rsp).await;
- let expected_buffer = [
- 6, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0,
- 65, 4, 0, 6, 0, 0, 0, 0, 1, 39, 2, 0, 0, 0, 0, 0, 48, 0, 0, 0,
- ];
- let buf_file = logger.buf_file.lock().await;
- assert_eq!(&buf_file.buffer, &expected_buffer);
- Ok(())
- }
-}
diff --git a/src/rust/uci_hal_android/error.rs b/src/rust/uci_hal_android/error.rs
index ede1b99..60fa755 100644
--- a/src/rust/uci_hal_android/error.rs
+++ b/src/rust/uci_hal_android/error.rs
@@ -126,3 +126,146 @@ fn exception_code_to_uwb_error(exception_code: ExceptionCode) -> UwbCoreError {
}
/// Result type associated with Error:
pub type Result<T> = std::result::Result<T, Error>;
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use android_hardware_uwb::binder::ExceptionCode;
+ use uwb_core::error::Error as UwbCoreError;
+
+ #[test]
+ fn test_uwb_core_error_to_exception_code() {
+ let mut exception = uwb_core_error_to_exception_code(UwbCoreError::BadParameters);
+ assert_eq!(exception, ExceptionCode::ILLEGAL_ARGUMENT);
+
+ exception = uwb_core_error_to_exception_code(UwbCoreError::ForeignFunctionInterface);
+ assert_eq!(exception, ExceptionCode::TRANSACTION_FAILED);
+ }
+
+ #[test]
+ fn test_exception_code_to_uwb_error() {
+ let mut error = exception_code_to_uwb_error(ExceptionCode::ILLEGAL_ARGUMENT);
+ assert_eq!(error, UwbCoreError::BadParameters);
+
+ error = exception_code_to_uwb_error(ExceptionCode::ILLEGAL_STATE);
+ assert_eq!(error, UwbCoreError::BadParameters);
+
+ error = exception_code_to_uwb_error(ExceptionCode::UNSUPPORTED_OPERATION);
+ assert_eq!(error, UwbCoreError::BadParameters);
+
+ error = exception_code_to_uwb_error(ExceptionCode::NULL_POINTER);
+ assert_eq!(error, UwbCoreError::BadParameters);
+ }
+
+ #[test]
+ fn test_status_code_to_exception_code() {
+ let mut exception = status_code_to_exception_code(StatusCode::OK);
+ assert_eq!(exception, ExceptionCode::NONE);
+
+ exception = status_code_to_exception_code(StatusCode::NO_MEMORY);
+ assert_eq!(exception, ExceptionCode::TRANSACTION_FAILED);
+
+ exception = status_code_to_exception_code(StatusCode::INVALID_OPERATION);
+ assert_eq!(exception, ExceptionCode::ILLEGAL_ARGUMENT);
+
+ exception = status_code_to_exception_code(StatusCode::BAD_VALUE);
+ assert_eq!(exception, ExceptionCode::ILLEGAL_ARGUMENT);
+
+ exception = status_code_to_exception_code(StatusCode::BAD_TYPE);
+ assert_eq!(exception, ExceptionCode::ILLEGAL_ARGUMENT);
+
+ exception = status_code_to_exception_code(StatusCode::NAME_NOT_FOUND);
+ assert_eq!(exception, ExceptionCode::ILLEGAL_ARGUMENT);
+
+ exception = status_code_to_exception_code(StatusCode::PERMISSION_DENIED);
+ assert_eq!(exception, ExceptionCode::SECURITY);
+
+ exception = status_code_to_exception_code(StatusCode::NO_INIT);
+ assert_eq!(exception, ExceptionCode::ILLEGAL_ARGUMENT);
+
+ exception = status_code_to_exception_code(StatusCode::ALREADY_EXISTS);
+ assert_eq!(exception, ExceptionCode::ILLEGAL_ARGUMENT);
+
+ exception = status_code_to_exception_code(StatusCode::DEAD_OBJECT);
+ assert_eq!(exception, ExceptionCode::ILLEGAL_ARGUMENT);
+
+ exception = status_code_to_exception_code(StatusCode::FAILED_TRANSACTION);
+ assert_eq!(exception, ExceptionCode::TRANSACTION_FAILED);
+
+ exception = status_code_to_exception_code(StatusCode::BAD_INDEX);
+ assert_eq!(exception, ExceptionCode::ILLEGAL_ARGUMENT);
+
+ exception = status_code_to_exception_code(StatusCode::NOT_ENOUGH_DATA);
+ assert_eq!(exception, ExceptionCode::ILLEGAL_ARGUMENT);
+
+ exception = status_code_to_exception_code(StatusCode::WOULD_BLOCK);
+ assert_eq!(exception, ExceptionCode::TRANSACTION_FAILED);
+
+ exception = status_code_to_exception_code(StatusCode::TIMED_OUT);
+ assert_eq!(exception, ExceptionCode::TRANSACTION_FAILED);
+
+ exception = status_code_to_exception_code(StatusCode::UNKNOWN_TRANSACTION);
+ assert_eq!(exception, ExceptionCode::ILLEGAL_ARGUMENT);
+
+ exception = status_code_to_exception_code(StatusCode::FDS_NOT_ALLOWED);
+ assert_eq!(exception, ExceptionCode::ILLEGAL_ARGUMENT);
+
+ exception = status_code_to_exception_code(StatusCode::UNEXPECTED_NULL);
+ assert_eq!(exception, ExceptionCode::ILLEGAL_ARGUMENT);
+ }
+
+ #[test]
+ fn test_status_code_to_uwb_core_error() {
+ let mut error = status_code_to_uwb_core_error(StatusCode::OK);
+ assert_eq!(error, UwbCoreError::Unknown);
+
+ error = status_code_to_uwb_core_error(StatusCode::NO_MEMORY);
+ assert_eq!(error, UwbCoreError::Unknown);
+
+ error = status_code_to_uwb_core_error(StatusCode::BAD_VALUE);
+ assert_eq!(error, UwbCoreError::BadParameters);
+
+ error = status_code_to_uwb_core_error(StatusCode::BAD_TYPE);
+ assert_eq!(error, UwbCoreError::BadParameters);
+
+ error = status_code_to_uwb_core_error(StatusCode::NAME_NOT_FOUND);
+ assert_eq!(error, UwbCoreError::BadParameters);
+
+ error = status_code_to_uwb_core_error(StatusCode::PERMISSION_DENIED);
+ assert_eq!(error, UwbCoreError::BadParameters);
+
+ error = status_code_to_uwb_core_error(StatusCode::NO_INIT);
+ assert_eq!(error, UwbCoreError::BadParameters);
+
+ error = status_code_to_uwb_core_error(StatusCode::ALREADY_EXISTS);
+ assert_eq!(error, UwbCoreError::Unknown);
+
+ error = status_code_to_uwb_core_error(StatusCode::DEAD_OBJECT);
+ assert_eq!(error, UwbCoreError::Unknown);
+
+ error = status_code_to_uwb_core_error(StatusCode::FAILED_TRANSACTION);
+ assert_eq!(error, UwbCoreError::Unknown);
+
+ error = status_code_to_uwb_core_error(StatusCode::BAD_INDEX);
+ assert_eq!(error, UwbCoreError::BadParameters);
+
+ error = status_code_to_uwb_core_error(StatusCode::NOT_ENOUGH_DATA);
+ assert_eq!(error, UwbCoreError::BadParameters);
+
+ error = status_code_to_uwb_core_error(StatusCode::WOULD_BLOCK);
+ assert_eq!(error, UwbCoreError::Unknown);
+
+ error = status_code_to_uwb_core_error(StatusCode::TIMED_OUT);
+ assert_eq!(error, UwbCoreError::Timeout);
+
+ error = status_code_to_uwb_core_error(StatusCode::UNKNOWN_TRANSACTION);
+ assert_eq!(error, UwbCoreError::BadParameters);
+
+ error = status_code_to_uwb_core_error(StatusCode::FDS_NOT_ALLOWED);
+ assert_eq!(error, UwbCoreError::Unknown);
+
+ error = status_code_to_uwb_core_error(StatusCode::UNEXPECTED_NULL);
+ assert_eq!(error, UwbCoreError::Unknown);
+ }
+}
diff --git a/src/rust/uci_hal_android/uci_hal_android.rs b/src/rust/uci_hal_android/uci_hal_android.rs
index a9b3048..0dd4c0b 100644
--- a/src/rust/uci_hal_android/uci_hal_android.rs
+++ b/src/rust/uci_hal_android/uci_hal_android.rs
@@ -39,10 +39,10 @@ use uwb_uci_packets::{DeviceState, DeviceStatusNtfBuilder};
use crate::error::{Error, Result};
-fn input_uci_hal_packet<T: Into<uwb_uci_packets::UciPacketPacket>>(
+fn input_uci_hal_packet<T: Into<uwb_uci_packets::UciControlPacket>>(
builder: T,
) -> Vec<UciHalPacket> {
- let packets: Vec<uwb_uci_packets::UciPacketHalPacket> = builder.into().into();
+ let packets: Vec<uwb_uci_packets::UciControlPacketHal> = builder.into().into();
packets.into_iter().map(|packet| packet.into()).collect()
}
@@ -286,3 +286,49 @@ impl UciHal for UciHalAndroid {
}
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_send_device_state_error_notification() {
+ let (uci_sender, _) = mpsc::unbounded_channel();
+ let res = send_device_state_error_notification(&uci_sender);
+ assert_eq!(res, Err(UwbCoreError::BadParameters));
+ }
+
+ #[tokio::test]
+ async fn test_new() {
+ let chip_id = "test_chip_id";
+ let hal = UciHalAndroid::new(chip_id);
+ assert_eq!(hal.chip_id, chip_id);
+ assert!(hal.hal_close_result_receiver.is_none());
+ assert!(hal.hal_death_recipient.is_none());
+ assert!(hal.hal_uci_recipient.is_none());
+ }
+
+ #[tokio::test]
+ async fn test_open_error() {
+ let chip_id = "test_chip_id";
+ let mut hal = UciHalAndroid::new(chip_id);
+ let packet_sender = mpsc::unbounded_channel().0;
+ let res = hal.open(packet_sender).await;
+ assert_eq!(res, Err(UwbCoreError::BadParameters));
+ }
+
+ #[tokio::test]
+ async fn test_close() {
+ let chip_id = "test_chip_id";
+ let mut hal = UciHalAndroid::new(chip_id);
+ let (_, receiver) = mpsc::channel::<Result<()>>(1);
+ let death_recipient = Arc::new(Mutex::new(DeathRecipient::new(|| {})));
+ hal.hal_close_result_receiver = Some(receiver);
+ hal.hal_death_recipient = Some(death_recipient.clone());
+ let res = hal.close().await;
+ assert_eq!(res, Err(UwbCoreError::BadParameters));
+ assert!(hal.hal_close_result_receiver.is_none());
+ assert!(hal.hal_death_recipient.is_none());
+ assert!(hal.hal_uci_recipient.is_none());
+ }
+}
diff --git a/src/rust/uwb_core/Cargo.toml b/src/rust/uwb_core/Cargo.toml
index 8f0e03c..9814721 100644
--- a/src/rust/uwb_core/Cargo.toml
+++ b/src/rust/uwb_core/Cargo.toml
@@ -3,10 +3,14 @@ name = "uwb_core"
version = "0.0.1"
edition = "2021"
+[build-dependencies]
+protoc-rust = "2.24.1"
+
[dependencies]
async-trait = "0.1.32"
bytes = "1.1.0"
log = "0.4.14"
+protobuf = { version = "2.24.1", optional = true }
num-traits = "0.2.12"
num-derive = "0.3.3"
thiserror = "1.0.30"
@@ -17,4 +21,8 @@ uwb_uci_packets = { path = "../uwb_uci_packets" } # provided by ebuild
[dev-dependencies]
env_logger = "0.9.0"
-tempfile = "3" \ No newline at end of file
+tempfile = "3"
+
+[features]
+proto = ["dep:protobuf"]
+mock-util = [] \ No newline at end of file
diff --git a/src/rust/uwb_core/README.md b/src/rust/uwb_core/README.md
index ea22064..0601af1 100644
--- a/src/rust/uwb_core/README.md
+++ b/src/rust/uwb_core/README.md
@@ -5,13 +5,13 @@ build and test the library by cargo.
## Building `uwb_uci_packets` package
-The `uwb_uci_packets` package depends on `bluetooth_packetgen` and thus simply
-using `cargo build` will fail. Follow the steps below before using cargo.
+The `uwb_uci_packets` package depends on `pdl` and thus simply using `cargo
+build` will fail. Follow the steps below before using cargo.
1. Enter Android environment by `source build/make/rbesetup.sh; lunch <target>`
-2. Run `m -j32 bluetooth_packetgen` to compile `bluetooth_packetgen` c++ binary.
+2. Run `m pdl` to compile the `pdl` Rust binary.
-After that, we could build or test the package by cargo.
+After that, we could build or test the package by `cargo test --features proto`.
## Enable logging for a certain test case of uwb\_core library
@@ -23,3 +23,68 @@ single test case.
```
RUST_LOG=debug cargo test -p uwb_core <test_case_name> -- --nocapture
```
+
+# Code Architecture
+
+This section describes the main modules of this library. The modules below are
+listed in reversed topological order.
+
+## The uwb\_uci\_packets crate
+
+The `uwb_uci_packets` crate is aimed for encoding and decoding the UCI packets.
+All the details of the UCI packet format should be encapsulated here. That
+means, the client of this crate should not be aware of how the UCI messages are
+constructed to or parsed from raw byte buffers.
+
+The crate is mainly generated from the PDL file. However, in the case where a
+UCI feature cannot be achieved using PDL alone, a workaround should be created
+inside this crate to complete this feature (i.e. define structs and implement
+the parsing methods manually) to encapsulate the details of UCI packet format.
+
+Note that the interface of the workaround should be as close to PDL-generated
+code as possible.
+
+
+## params
+
+The params modules defines the parameters types, including UCI, FiRa, and CCC
+specification.
+
+This module depends on the `uwb_uci_packets` crate. To prevent the client of
+this module directly depending on the `uwb_uci_packets` crate, we re-expose all
+the needed enums and structs at `params/uci_packets.rs`.
+
+## UCI
+
+The `uci` module is aimed to provide a rust-idiomatic way that implements the
+UCI interface, such as:
+- Declare meaningful arguments types
+- Create a public method for each UCI command, and wait for its corresponding
+ response
+- Create a callback method for each UCI notification
+
+According to the asynchronous nature of the UCI interface, the `UciManager`
+struct provides asynchronous methods using the actor model. For easier usage,
+the `UciManagerSync` struct works as a thin synchronous wrapper.
+
+This module depends on the `params` module.
+
+## Session
+
+The `session` module implements the ranging session-related logic. We support
+the FiRa and CCC specification here.
+
+This module depends on the `params` and `UCI` modules.
+
+## service
+
+The `service` module is aimed to provide a "top-shim", the main entry of this
+library. Similar to the `UciManagerSync`, the `UwbService` struct provides a
+simple synchronous interface to the client of the library. `examples/main.rs` is
+a simple example for using the `UwbService` struct.
+
+If we want to provide the UWB across the process or language boundary, then
+`ProtoUwbService` provices a simple wrapper that converts all the arguments and
+responses to protobuf-encoded byte buffers.
+
+The `service` module depends on `params`, `uci`, and `session` modules.
diff --git a/src/rust/uwb_core/build.rs b/src/rust/uwb_core/build.rs
new file mode 100644
index 0000000..f29a5e1
--- /dev/null
+++ b/src/rust/uwb_core/build.rs
@@ -0,0 +1,59 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use std::fs::File;
+use std::io::Write;
+use std::path::PathBuf;
+
+/// Generate the protobuf bindings inside the uwb_core library.
+///
+/// The protobuf are mainly used to represent the elements of uwb_uci_packets. If we use
+/// Android's rust_protobuf build target to split the protobuf bindings to a dedicated crate, then
+/// we cannot implement the conversion trait (i.e. std::convert::From) between the protobuf
+/// bindings and the uwb_uci_packets's elements due to Rust's orphan rule.
+fn generate_proto_bindings() {
+ let out_dir = std::env::var_os("OUT_DIR").unwrap();
+
+ // Generate the protobuf bindings to "${OUT_DIR}/uwb_service.rs".
+ protoc_rust::Codegen::new()
+ .out_dir(&out_dir)
+ .input("./protos/uwb_service.proto")
+ .run()
+ .expect("Running protoc failed.");
+
+ // Including the protobuf bindings directly hits the issue:
+ // "error: an inner attribute is not permitted in this context".
+ //
+ // To workaround this, first we create the file "${OUT_DIR}/proto_bindings.rs" that contains
+ // ```
+ // #[path = "${OUT_DIR}/uwb_service.rs"]
+ // pub mod bindings;
+ // ```
+ //
+ // Then include the generated file at proto.rs by:
+ // ```
+ // include!(concat!(env!("OUT_DIR"), "/proto_bindings.rs"));
+ // ```
+ let file_path = PathBuf::from(&out_dir).join("proto_bindings.rs");
+ let file = File::create(file_path).expect("Failed to create the generated file");
+ writeln!(&file, "#[path = \"{}/uwb_service.rs\"]", out_dir.to_str().unwrap())
+ .expect("Failed to write to the generated file");
+ writeln!(&file, "pub mod bindings;").expect("Failed to write to the generated file");
+}
+
+fn main() {
+ if std::env::var("CARGO_FEATURE_PROTO") == Ok("1".to_string()) {
+ generate_proto_bindings();
+ }
+}
diff --git a/src/rust/uwb_core/examples/main.rs b/src/rust/uwb_core/examples/main.rs
index 42ad748..63317b1 100644
--- a/src/rust/uwb_core/examples/main.rs
+++ b/src/rust/uwb_core/examples/main.rs
@@ -14,81 +14,25 @@
//! A simple example for the usage of the uwb_core library.
-use async_trait::async_trait;
use log::debug;
-use tokio::sync::mpsc;
use uwb_core::error::{Error as UwbError, Result as UwbResult};
-use uwb_core::params::uci_packets::{DeviceState, ReasonCode, SessionId, SessionState};
use uwb_core::service::{
- default_runtime, UwbServiceBuilder, UwbServiceCallback, UwbServiceCallbackSendBuilder,
+ default_runtime, NopUwbServiceCallback, UwbServiceBuilder, UwbServiceCallbackSendBuilder,
};
-use uwb_core::uci::uci_logger_factory::UciLoggerFactoryNull;
-use uwb_core::uci::{SessionRangeData, UciHal, UciHalPacket};
-
-/// A placeholder implementation for UciHal.
-struct UciHalImpl {}
-#[async_trait]
-impl UciHal for UciHalImpl {
- async fn open(&mut self, _packet_sender: mpsc::UnboundedSender<UciHalPacket>) -> UwbResult<()> {
- debug!("UciHalImpl::open() is called");
- Ok(())
- }
- async fn close(&mut self) -> UwbResult<()> {
- debug!("UciHalImpl::close() is called");
- Ok(())
- }
- async fn send_packet(&mut self, packet: UciHalPacket) -> UwbResult<()> {
- debug!("UciHalImpl::send_packet({:?}) is called", packet);
- Ok(())
- }
-}
-
-/// A placeholder implementation for UwbServiceCallback.
-struct UwbServiceCallbackImpl {}
-impl UwbServiceCallback for UwbServiceCallbackImpl {
- fn on_service_reset(&mut self, success: bool) {
- debug!("UwbService is reset, success: {}", success);
- }
-
- fn on_uci_device_status_changed(&mut self, state: DeviceState) {
- debug!("UCI device status: {:?}", state);
- }
-
- fn on_session_state_changed(
- &mut self,
- session_id: SessionId,
- session_state: SessionState,
- reason_code: ReasonCode,
- ) {
- debug!(
- "Session {:?}'s state is changed to {:?}, reason: {:?}",
- session_id, session_state, reason_code
- );
- }
-
- fn on_range_data_received(&mut self, session_id: SessionId, range_data: SessionRangeData) {
- debug!("Received range data {:?} from Session {:?}", range_data, session_id);
- }
-
- fn on_vendor_notification_received(&mut self, gid: u32, oid: u32, payload: Vec<u8>) {
- debug!("Received vendor notification: gid={}, oid={}, payload={:?}", gid, oid, payload);
- }
-}
+use uwb_core::uci::{NopUciHal, NopUciLoggerFactory};
fn main() {
env_logger::init();
// The UwbService needs an outlived Tokio Runtime.
let runtime = default_runtime().unwrap();
- // Initialize callback object.
- let callback = UwbServiceCallbackImpl {};
// Initialize the UWB service.
- let mut service = UwbServiceBuilder::new()
+ let service = UwbServiceBuilder::new()
.runtime_handle(runtime.handle().to_owned())
- .callback_builder(UwbServiceCallbackSendBuilder::new(callback))
- .uci_hal(UciHalImpl {})
- .uci_logger_factory(UciLoggerFactoryNull::default())
+ .callback_builder(UwbServiceCallbackSendBuilder::new(NopUwbServiceCallback {}))
+ .uci_hal(NopUciHal {})
+ .uci_logger_factory(NopUciLoggerFactory {})
.build()
.unwrap();
diff --git a/src/rust/uwb_core/fuzz/.gitignore b/src/rust/uwb_core/fuzz/.gitignore
new file mode 100644
index 0000000..1a45eee
--- /dev/null
+++ b/src/rust/uwb_core/fuzz/.gitignore
@@ -0,0 +1,4 @@
+target
+corpus
+artifacts
+coverage
diff --git a/src/rust/uwb_core/fuzz/Cargo.toml b/src/rust/uwb_core/fuzz/Cargo.toml
new file mode 100644
index 0000000..e6ea9f4
--- /dev/null
+++ b/src/rust/uwb_core/fuzz/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "uwb_core-fuzz"
+version = "0.0.1"
+publish = false
+edition = "2021"
+
+[package.metadata]
+cargo-fuzz = true
+
+[dependencies]
+arbitrary = {version = "1", features = ["derive"] }
+libfuzzer-sys = "0.4"
+uwb_core = { path = "..", features = ["proto"] }
+
+# Prevent this from interfering with workspaces
+[workspace]
+members = ["."]
+
+[profile.release]
+debug = 1
+
+[[bin]]
+name = "proto_uwb_service_fuzzer"
+path = "proto_uwb_service_fuzzer.rs"
+test = false
+doc = false
diff --git a/src/rust/uwb_core/fuzz/proto_uwb_service_fuzzer.rs b/src/rust/uwb_core/fuzz/proto_uwb_service_fuzzer.rs
new file mode 100644
index 0000000..850d8a1
--- /dev/null
+++ b/src/rust/uwb_core/fuzz/proto_uwb_service_fuzzer.rs
@@ -0,0 +1,87 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#![no_main]
+
+use libfuzzer_sys::{arbitrary::Arbitrary, fuzz_target};
+use uwb_core::service::{
+ default_runtime, NopUwbServiceCallback, ProtoUwbService, UwbServiceBuilder,
+ UwbServiceCallbackSendBuilder,
+};
+use uwb_core::uci::{NopUciHal, NopUciLoggerFactory};
+
+/// The list of the ProtoUwbService's methods that take the argument.
+#[derive(Arbitrary, Debug)]
+enum Command {
+ SetLoggerMode,
+ InitSession,
+ DeinitSession,
+ StartRanging,
+ StopRanging,
+ Reconfigure,
+ UpdateControllerMulticastList,
+ AndroidSetCountryCode,
+ SendVendorCmd,
+ SessionParams,
+}
+
+fuzz_target!(|methods: Vec<(Command, &[u8])>| {
+ // Setup the ProtoUwbService.
+ let runtime = default_runtime().unwrap();
+ let service = UwbServiceBuilder::new()
+ .runtime_handle(runtime.handle().to_owned())
+ .callback_builder(UwbServiceCallbackSendBuilder::new(NopUwbServiceCallback {}))
+ .uci_hal(NopUciHal {})
+ .uci_logger_factory(NopUciLoggerFactory {})
+ .build()
+ .unwrap();
+ let mut proto_service = ProtoUwbService::new(service);
+ let _ = proto_service.enable();
+
+ // Call the methods of ProtoUwbService that takes the argument.
+ for (command, bytes) in methods.into_iter() {
+ match command {
+ Command::SetLoggerMode => {
+ let _ = proto_service.set_logger_mode(bytes);
+ }
+ Command::InitSession => {
+ let _ = proto_service.init_session(bytes);
+ }
+ Command::DeinitSession => {
+ let _ = proto_service.deinit_session(bytes);
+ }
+ Command::StartRanging => {
+ let _ = proto_service.start_ranging(bytes);
+ }
+ Command::StopRanging => {
+ let _ = proto_service.stop_ranging(bytes);
+ }
+ Command::Reconfigure => {
+ let _ = proto_service.reconfigure(bytes);
+ }
+ Command::UpdateControllerMulticastList => {
+ let _ = proto_service.update_controller_multicast_list(bytes);
+ }
+ Command::AndroidSetCountryCode => {
+ let _ = proto_service.android_set_country_code(bytes);
+ }
+ Command::SendVendorCmd => {
+ let _ = proto_service.raw_uci_cmd(bytes);
+ }
+ Command::SessionParams => {
+ let _ = proto_service.session_params(bytes);
+ }
+ }
+ }
+});
diff --git a/src/rust/uwb_core/protos/uwb_service.proto b/src/rust/uwb_core/protos/uwb_service.proto
new file mode 100644
index 0000000..3d51c4d
--- /dev/null
+++ b/src/rust/uwb_core/protos/uwb_service.proto
@@ -0,0 +1,665 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file defines the requests and responses of the UwbService's methods.
+// Most of the elements are referred to the FiRa Consortium UWB Command
+// Interface Generic Techinal Specification Version 1.1.0.
+//
+// Note: Due to the protobuf's restriction: the first field of enum must be
+// zero, the value of some enum fields are not the same as the UCI
+// specification. Also, the default value of some fields defined at UCI
+// specification is not zero. The client should set all the fields when creating
+// protobuf structure, instead of relying the default value of protobuf.
+
+syntax = "proto3";
+package uwb_core;
+
+// The status code of the method response, containing variants of error::Error
+// and OK.
+enum Status {
+ // The method is executed successfully.
+ OK = 0;
+
+ // The provided parameters are invalid, or the method is not allowed to be
+ // called in the current state.
+ BAD_PARAMETERS = 1;
+
+ // The maximum number of sessions has been reached.
+ MAX_SESSIONS_EXCEEDED = 2;
+
+ // Max ranging round retries reached.
+ MAX_RR_RETRY_REACHED = 3;
+
+ // Fails due to a protocol specific reason.
+ PROTOCOL_SPECIFIC = 4;
+
+ // The remote device has requested to change the session.
+ REMOTE_REQUEST = 5;
+
+ // The response or notification is not received in timeout.
+ TIMEOUT = 6;
+
+ // The command should be retried.
+ COMMAND_RETRY = 7;
+
+ // Duplicated SessionId.
+ DUPLICATED_SESSION_ID = 8;
+
+ // The unknown error.
+ UNKNOWN = 9;
+}
+
+// Represent uwb_uci_packets::StatusCode.
+enum StatusCode {
+ UCI_STATUS_OK = 0;
+ UCI_STATUS_REJECTED = 1;
+ UCI_STATUS_FAILED = 2;
+ UCI_STATUS_SYNTAX_ERROR = 3;
+ UCI_STATUS_INVALID_PARAM = 4;
+ UCI_STATUS_INVALID_RANGE = 5;
+ UCI_STATUS_INVALID_MSG_SIZE = 6;
+ UCI_STATUS_UNKNOWN_GID = 7;
+ UCI_STATUS_UNKNOWN_OID = 8;
+ UCI_STATUS_READ_ONLY = 9;
+ UCI_STATUS_COMMAND_RETRY = 10;
+
+ UCI_STATUS_SESSION_NOT_EXIST = 17;
+ UCI_STATUS_SESSION_DUPLICATE = 18;
+ UCI_STATUS_SESSION_ACTIVE = 19;
+ UCI_STATUS_MAX_SESSIONS_EXCEEDED = 20;
+ UCI_STATUS_SESSION_NOT_CONFIGURED = 21;
+ UCI_STATUS_ACTIVE_SESSIONS_ONGOING = 22;
+ UCI_STATUS_MULTICAST_LIST_FULL = 23;
+ UCI_STATUS_ADDRESS_NOT_FOUND = 24;
+ UCI_STATUS_ADDRESS_ALREADY_PRESENT = 25;
+ UCI_STATUS_OK_NEGATIVE_DISTANCE_REPORT = 27;
+
+ UCI_STATUS_RANGING_TX_FAILED = 32;
+ UCI_STATUS_RANGING_RX_TIMEOUT = 33;
+ UCI_STATUS_RANGING_RX_PHY_DEC_FAILED = 34;
+ UCI_STATUS_RANGING_RX_PHY_TOA_FAILED = 35;
+ UCI_STATUS_RANGING_RX_PHY_STS_FAILED = 36;
+ UCI_STATUS_RANGING_RX_MAC_DEC_FAILED = 37;
+ UCI_STATUS_RANGING_RX_MAC_IE_DEC_FAILED = 38;
+ UCI_STATUS_RANGING_RX_MAC_IE_MISSING = 39;
+ UCI_STATUS_ERROR_ROUND_INDEX_NOT_ACTIVATED = 40;
+ UCI_STATUS_ERROR_NUMBER_OF_ACTIVE_RANGING_ROUNDS_EXCEEDED = 41;
+ UCI_STATUS_ERROR_ROUND_INDEX_NOT_SET_AS_INITIATOR = 42;
+ UCI_STATUS_ERROR_DL_TDOA_DEVICE_ADDRESS_NOT_MATCHING_IN_REPLY_TIME_LIST = 43;
+
+ UCI_STATUS_DATA_MAX_TX_PSDU_SIZE_EXCEEDED = 48;
+ UCI_STATUS_DATA_RX_CRC_ERROR = 49;
+
+ UCI_STATUS_ERROR_CCC_SE_BUSY = 80;
+ UCI_STATUS_ERROR_CCC_LIFECYCLE = 81;
+ UCI_STATUS_ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT = 82;
+ // All vendor specific status code will be mapped to UCI_STATUS_VENDOR_SPECIFIC.
+ UCI_STATUS_RFU_OR_VENDOR_SPECIFIC = 255;
+}
+
+// Represents uwb_uci_packets::OwrAoaStatusCode
+enum OwrAoaStatusCode {
+ UCI_STATUS_SUCCESS = 0;
+ UCI_STATUS_INTER_FRAME_INTERVAL_TIMEOUT = 1;
+}
+
+// Represent uwb_uci_packets::DeviceState.
+enum DeviceState {
+ DEVICE_STATE_READY = 0;
+ DEVICE_STATE_ACTIVE = 1;
+ DEVICE_STATE_ERROR = 2;
+}
+
+// Represent uwb_uci_packets::SessionState.
+enum SessionState {
+ INIT = 0;
+ DEINIT = 1;
+ ACTIVE = 2;
+ IDLE = 3;
+}
+
+// Represent uwb_uci_packets::ReasonCode.
+enum ReasonCode {
+ STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS = 0;
+ MAX_RANGING_ROUND_RETRY_COUNT_REACHED = 1;
+ MAX_NUMBER_OF_MEASUREMENTS_REACHED = 2;
+ SESSION_SUSPENDED_DUE_TO_INBAND_SIGNAL = 3;
+ SESSION_RESUMED_DUE_TO_INBAND_SIGNAL = 4;
+ SESSION_STOPPED_DUE_TO_INBAND_SIGNAL = 5;
+ ERROR_INVALID_UL_TDOA_RANDOM_WINDOW = 29;
+ ERROR_MIN_RFRAMES_PER_RR_NOT_SUPPORTED = 30;
+ ERROR_TX_DELAY_NOT_SUPPORTED = 31;
+ ERROR_SLOT_LENGTH_NOT_SUPPORTED = 32;
+ ERROR_INSUFFICIENT_SLOTS_PER_RR = 33;
+ ERROR_MAC_ADDRESS_MODE_NOT_SUPPORTED = 34;
+ ERROR_INVALID_RANGING_DURATION = 35;
+ ERROR_INVALID_STS_CONFIG = 36;
+ ERROR_INVALID_RFRAME_CONFIG = 37;
+ ERROR_HUS_NOT_ENOUGH_SLOTS = 38;
+ ERROR_HUS_CFP_PHASE_TOO_SHORT = 39;
+ ERROR_HUS_CAP_PHASE_TOO_SHORT = 40;
+ ERROR_HUS_OTHERS = 41;
+ ERROR_STATUS_SESSION_KEY_NOT_FOUND = 42;
+ ERROR_STATUS_SUB_SESSION_KEY_NOT_FOUND = 43;
+ ERROR_INVALID_PREAMBLE_CODE_INDEX = 44;
+ ERROR_INVALID_SFD_ID = 45;
+ ERROR_INVALID_PSDU_DATA_RATE = 46;
+ ERROR_INVALID_PHR_DATA_RATE = 47;
+ ERROR_INVALID_PREAMBLE_DURATION = 48;
+ ERROR_INVALID_STS_LENGTH = 49;
+ ERROR_INVALID_NUM_OF_STS_SEGMENTS = 50;
+ ERROR_INVALID_NUM_OF_CONTROLEES = 51;
+ ERROR_MAX_RANGING_REPLY_TIME_EXCEEDED = 52;
+ ERROR_INVALID_DST_ADDRESS_LIST = 53;
+ ERROR_INVALID_OR_NOT_FOUND_SUB_SESSION_ID = 54;
+ ERROR_INVALID_RESULT_REPORT_CONFIG = 55;
+ ERROR_INVALID_RANGING_ROUND_CONTROL_CONFIG = 56;
+ ERROR_INVALID_RANGING_ROUND_USAGE = 57;
+ ERROR_INVALID_MULTI_NODE_MODE = 58;
+ ERROR_RDS_FETCH_FAILURE = 59;
+ ERROR_REF_UWB_SESSION_DOES_NOT_EXIST = 60;
+ ERROR_REF_UWB_SESSION_RANGING_DURATION_MISMATCH = 61;
+ ERROR_REF_UWB_SESSION_INVALID_OFFSET_TIME = 62;
+ ERROR_REF_UWB_SESSION_LOST = 63;
+ ERROR_INVALID_CHANNEL_WITH_AOA = 128;
+ ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT = 129;
+ ERROR_DT_ANCHOR_RANGING_ROUNDS_NOT_CONFIGURED = 130;
+ ERROR_DT_TAG_RANGING_ROUNDS_NOT_CONFIGURED = 131;
+ // All vendor reason code will be mapped to ERROR_VENDOR_SPECIFIC.
+ ERROR_RFU_OR_VENDOR_SPECIFIC = 255;
+}
+
+// Represent uwb_uci_packets::RangingMeasurementType.
+enum RangingMeasurementType {
+ ONE_WAY = 0;
+ TWO_WAY = 1;
+ DL_TDOA = 2;
+ OWR_AOA = 3;
+}
+
+// Represent uwb_uci_packets::SessionType.
+enum SessionType {
+ FIRA_RANGING_SESSION = 0;
+ FIRA_DATA_TRANSFER = 1;
+ CCC = 2;
+}
+
+// Represent uwb_uci_packets::UpdateMulticastListAction.
+enum UpdateMulticastListAction {
+ ADD_CONTROLEE = 0;
+ REMOVE_CONTROLEE = 1;
+ ADD_CONTROLEE_WITH_SHORT_SUB_SESSION_KEY = 2;
+ ADD_CONTROLEE_WITH_LONG_SUB_SESSION_KEY = 3;
+}
+
+// Represent uwb_core::params::fira_app_config_params::DeviceType.
+enum DeviceType {
+ CONTROLEE = 0;
+ CONTROLLER = 1;
+}
+
+// Represent uwb_core::params::fira_app_config_params::RangingRoundUsage.
+enum RangingRoundUsage {
+ SS_TWR = 0;
+ DS_TWR = 1;
+ SS_TWR_NON = 2;
+ DS_TWR_NON = 3;
+}
+
+// Represent uwb_core::params::fira_app_config_params::StsConfig.
+enum StsConfig {
+ STATIC = 0;
+ DYNAMIC = 1;
+ DYNAMIC_FOR_CONTROLEE_INDIVIDUAL_KEY = 2;
+}
+
+// Represent uwb_core::params::fira_app_config_params::MultiNodeMode.
+enum MultiNodeMode {
+ UNICAST = 0;
+ ONE_TO_MANY = 1;
+ MANY_TO_MANY = 2;
+}
+
+// Represent uwb_core::params::fira_app_config_params::UwbChannel.
+enum UwbChannel {
+ CHANNEL_5 = 0;
+ CHANNEL_6 = 1;
+ CHANNEL_8 = 2;
+ CHANNEL_9 = 3;
+ CHANNEL_10 = 4;
+ CHANNEL_12 = 5;
+ CHANNEL_13 = 6;
+ CHANNEL_14 = 7;
+}
+
+// Represent uwb_core::params::fira_app_config_params::MacFcsType.
+enum MacFcsType {
+ CRC_16 = 0;
+ CRC_32 = 1;
+}
+
+// Represent uwb_core::params::fira_app_config_params::AoaResultRequest.
+enum AoaResultRequest {
+ NO_AOA_REPORT = 0;
+ REQ_AOA_RESULTS = 1;
+ REQ_AOA_RESULTS_AZIMUTH_ONLY = 2;
+ REQ_AOA_RESULTS_ELEVATION_ONLY = 3;
+ REQ_AOA_RESULTS_INTERLEAVED = 4;
+}
+
+// Represent uwb_core::params::fira_app_config_params::RangeDataNtfConfig.
+enum RangeDataNtfConfig {
+ RANGE_DATA_NTF_CONFIG_DISABLE = 0;
+ RANGE_DATA_NTF_CONFIG_ENABLE = 1;
+ RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY = 2;
+}
+
+// Represent uwb_core::params::fira_app_config_params::DeviceRole.
+enum DeviceRole {
+ RESPONDER = 0;
+ INITIATOR = 1;
+}
+
+// Represent uwb_core::params::fira_app_config_params::RframeConfig.
+enum RframeConfig {
+ SP0 = 0;
+ SP1 = 1;
+ SP3 = 3;
+}
+
+// Represent uwb_core::params::fira_app_config_params::PsduDataRate.
+enum PsduDataRate {
+ RATE_6M_81 = 0;
+ RATE_7M_80 = 1;
+ RATE_27M_2 = 2;
+ RATE_31M_2 = 3;
+ RATE_850K = 4;
+}
+
+// Represent uwb_core::params::fira_app_config_params::PreambleDuration.
+enum PreambleDuration {
+ T32_SYMBOLS = 0;
+ T64_SYMBOLS = 1;
+}
+
+// Represent uwb_core::params::fira_app_config_params::RangingTimeStruct.
+enum RangingTimeStruct {
+ INTERVAL_BASED_SCHEDULING = 0;
+ BLOCK_BASED_SCHEDULING = 1;
+}
+
+// Represent uwb_core::params::fira_app_config_params::TxAdaptivePayloadPower.
+enum TxAdaptivePayloadPower {
+ TX_ADAPTIVE_PAYLOAD_POWER_DISABLE = 0;
+ TX_ADAPTIVE_PAYLOAD_POWER_ENABLE = 1;
+}
+
+// Represent uwb_core::params::fira_app_config_params::PrfMode.
+enum PrfMode {
+ BPRF = 0;
+ HPRF_WITH_124_8_MHZ = 1;
+ HPRF_WITH_249_6_MHZ = 2;
+}
+
+// Represent uwb_core::params::fira_app_config_params::ScheduledMode.
+enum ScheduledMode {
+ TIME_SCHEDULED_RANGING = 0;
+}
+
+// Represent uwb_core::params::fira_app_config_params::KeyRotation.
+enum KeyRotation {
+ KEY_ROTATION_DISABLE = 0;
+ KEY_ROTATION_ENABLE = 1;
+}
+
+// Represent uwb_core::params::fira_app_config_params::MacAddressMode.
+enum MacAddressMode {
+ MAC_ADDRESS_2_BYTES = 0;
+ MAC_ADDRESS_8_BYTES_2_BYTES_HEADER = 1;
+ MAC_ADDRESS_8_BYTES = 2;
+}
+
+// Represent uwb_core::params::fira_app_config_params::HoppingMode.
+enum HoppingMode {
+ HOPPING_MODE_DISABLE = 0;
+ FIRA_HOPPING_ENABLE = 1;
+}
+
+// Represent uwb_core::params::fira_app_config_params::BprfPhrDataRate.
+enum BprfPhrDataRate {
+ BPRF_PHR_DATA_RATE_850K = 0;
+ BPRF_PHR_DATA_RATE_6M_81 = 1;
+}
+
+// Represent uwb_core::params::fira_app_config_params::StsLength.
+enum StsLength {
+ LENGTH_32 = 0;
+ LENGTH_64 = 1;
+ LENGTH_128 = 2;
+}
+
+// Represent uwb_core::uci::uci_logger::UciLoggerMode.
+enum UciLoggerMode {
+ UCI_LOGGER_MODE_DISABLED = 0;
+ UCI_LOGGER_MODE_UNFILTERED = 1;
+ UCI_LOGGER_MODE_FILTERED = 2;
+}
+
+// Represent uwb_core::params::fira_app_config_params::RangingRoundControl.
+message RangingRoundControl {
+ bool ranging_result_report_message = 1;
+ bool control_message = 2;
+ bool measurement_report_message = 3;
+}
+
+// Represent uwb_core::params::fira_app_config_params::ResultReportConfig.
+message ResultReportConfig {
+ bool tof = 1;
+ bool aoa_azimuth = 2;
+ bool aoa_elevation = 3;
+ bool aoa_fom = 4;
+}
+
+// Represent uwb_core::params::fira_app_config_params::FiraAppConfigParams.
+message FiraAppConfigParams {
+ DeviceType device_type = 1;
+ RangingRoundUsage ranging_round_usage = 2;
+ StsConfig sts_config = 3;
+ MultiNodeMode multi_node_mode = 4;
+ UwbChannel channel_number = 5;
+ bytes device_mac_address = 6;
+ repeated bytes dst_mac_address = 7;
+ uint32 slot_duration_rstu = 8;
+ uint32 ranging_interval_ms = 9;
+ MacFcsType mac_fcs_type = 10;
+ RangingRoundControl ranging_round_control = 11;
+ AoaResultRequest aoa_result_request = 12;
+ RangeDataNtfConfig range_data_ntf_config = 13;
+ uint32 range_data_ntf_proximity_near_cm = 14;
+ uint32 range_data_ntf_proximity_far_cm = 15;
+ DeviceRole device_role = 16;
+ RframeConfig rframe_config = 17;
+ uint32 preamble_code_index = 18;
+ uint32 sfd_id = 19;
+ PsduDataRate psdu_data_rate = 20;
+ PreambleDuration preamble_duration = 21;
+ RangingTimeStruct ranging_time_struct = 22;
+ uint32 slots_per_rr = 23;
+ TxAdaptivePayloadPower tx_adaptive_payload_power = 24;
+ uint32 responder_slot_index = 25;
+ PrfMode prf_mode = 26;
+ ScheduledMode scheduled_mode = 27;
+ KeyRotation key_rotation = 28;
+ uint32 key_rotation_rate = 29;
+ uint32 session_priority = 30;
+ MacAddressMode mac_address_mode = 31;
+ bytes vendor_id = 32;
+ bytes static_sts_iv = 33;
+ uint32 number_of_sts_segments = 34;
+ uint32 max_rr_retry = 35;
+ uint32 uwb_initiation_time_ms = 36;
+ HoppingMode hopping_mode = 37;
+ uint32 block_stride_length = 38;
+ ResultReportConfig result_report_config = 39;
+ uint32 in_band_termination_attempt_count = 40;
+ uint32 sub_session_id = 41;
+ BprfPhrDataRate bprf_phr_data_rate = 42;
+ uint32 max_number_of_measurements = 43;
+ StsLength sts_length = 44;
+ uint32 number_of_range_measurements = 45;
+ uint32 number_of_aoa_azimuth_measurements = 46;
+ uint32 number_of_aoa_elevation_measurements = 47;
+}
+
+// Represent uwb_uci_packets::Controlee.
+message Controlee {
+ uint32 short_address = 1;
+ uint32 subsession_id = 2;
+}
+
+// Represent uwb_uci_packets::ShortAddressTwoWayRangingMeasurement or
+// uwb_uci_packets::ExtendedAddressTwoWayRangingMeasurement.
+message TwoWayRangingMeasurement {
+ uint64 mac_address = 1;
+ StatusCode status = 2;
+ uint32 nlos = 3;
+ uint32 distance = 4;
+ uint32 aoa_azimuth = 5;
+ uint32 aoa_azimuth_fom = 6;
+ uint32 aoa_elevation = 7;
+ uint32 aoa_elevation_fom = 8;
+ uint32 aoa_destination_azimuth = 9;
+ uint32 aoa_destination_azimuth_fom = 10;
+ uint32 aoa_destination_elevation = 11;
+ uint32 aoa_destination_elevation_fom = 12;
+ uint32 slot_index = 13;
+ uint32 rssi = 14;
+}
+
+// Represent uwb_uci_packets::ShortAddressOwrAoaRangingMeasurement or
+// uwb_uci_packets::ExtendedAddressOwrAoaRangingMeasurement.
+message OwrAoaRangingMeasurement {
+ uint64 mac_address = 1;
+ OwrAoaStatusCode owr_aoa_status_code = 2;
+ uint32 nlos = 3;
+ uint32 block_index = 4;
+ uint32 frame_sequence_number = 5;
+ uint32 aoa_azimuth = 6;
+ uint32 aoa_azimuth_fom = 7;
+ uint32 aoa_elevation = 8;
+ uint32 aoa_elevation_fom = 9;
+}
+
+// Represent uwb_uci_packets::ShortAddressDlTdoaRangingMeasurement or
+// uwb_uci_packets::ExtendedAddressDlTdoaRangingMeasurement.
+message DlTDoARangingMeasurement {
+ uint64 mac_address = 1;
+ StatusCode status = 2;
+ uint32 message_control = 3;
+ uint32 block_index = 4;
+ uint32 round_index = 5;
+ uint32 nlos = 6;
+ uint32 aoa_azimuth = 7;
+ uint32 aoa_azimuth_fom = 8;
+ uint32 aoa_elevation = 9;
+ uint32 aoa_elevation_fom = 10;
+ uint32 rssi = 11;
+ uint64 tx_timestamp = 12;
+ uint64 rx_timestamp = 13;
+ uint32 anchor_cfo = 14;
+ uint32 cfo = 15;
+ uint32 initiator_reply_time = 16;
+ uint32 responder_reply_time = 17;
+ uint32 initiator_responder_tof = 18;
+ repeated uint32 dt_anchor_location = 19;
+ repeated uint32 ranging_rounds = 20;
+}
+
+// Represent uwb_core::uci::notification::SessionRangeData;
+message SessionRangeData {
+ uint32 sequence_number = 1;
+ uint32 session_id = 2;
+ uint32 current_ranging_interval_ms = 3;
+ RangingMeasurementType ranging_measurement_type = 4;
+ repeated TwoWayRangingMeasurement twoway_ranging_measurements = 5;
+ repeated DlTDoARangingMeasurement dltdoa_ranging_measurements = 6;
+ OwrAoaRangingMeasurement owraoa_ranging_measurement = 7;
+}
+
+// Represent uwb_uci_packets::PowerStats;
+message PowerStats {
+ StatusCode status = 1;
+ uint32 idle_time_ms = 2;
+ uint32 tx_time_ms = 3;
+ uint32 rx_time_ms = 4;
+ uint32 total_wake_count = 5;
+}
+
+// Response of the UwbService::enable() method.
+message EnableResponse {
+ Status status = 1;
+}
+
+// Response of the UwbService::disable() method.
+message DisableResponse {
+ Status status = 1;
+}
+
+// Argument of the UwbService::SetLoggerMode() method.
+message SetLoggerModeRequest {
+ UciLoggerMode logger_mode = 1;
+}
+
+// Response of the UwbService::SetLoggerMode() method.
+message SetLoggerModeResponse {
+ Status status = 1;
+}
+
+// Argument of the UwbService::InitSession() method.
+message InitSessionRequest {
+ uint32 session_id = 1;
+ SessionType session_type = 2;
+ FiraAppConfigParams params = 3;
+}
+
+// Response of the UwbService::InitSession() method.
+message InitSessionResponse {
+ Status status = 1;
+}
+
+// Argument of the UwbService::DeinitSession() method.
+message DeinitSessionRequest {
+ uint32 session_id = 1;
+}
+
+// Response of the UwbService::DeinitSession() method.
+message DeinitSessionResponse {
+ Status status = 1;
+}
+
+// Argument of the UwbService::StartRanging() method.
+message StartRangingRequest {
+ uint32 session_id = 1;
+}
+
+// Response of the UwbService::StartRanging() method.
+message StartRangingResponse {
+ Status status = 1;
+}
+
+// Argument of the UwbService::StopRanging() method.
+message StopRangingRequest {
+ uint32 session_id = 1;
+}
+
+// Response of the UwbService::StopRanging() method.
+message StopRangingResponse {
+ Status status = 1;
+}
+
+// Argument of the UwbService::SessionParams() method.
+message SessionParamsRequest {
+ uint32 session_id = 1;
+}
+
+// Response of the UwbService::SessionParams() method.
+message SessionParamsResponse {
+ Status status = 1;
+ FiraAppConfigParams params = 2;
+}
+
+// Argument of the UwbService::Reconfigure() method.
+message ReconfigureRequest {
+ uint32 session_id = 1;
+ FiraAppConfigParams params = 2;
+}
+
+// Response of the UwbService::Reconfigure() method.
+message ReconfigureResponse {
+ Status status = 1;
+}
+
+// Argument of the UwbService::UpdateControllerMulticastList() method.
+message UpdateControllerMulticastListRequest {
+ uint32 session_id = 1;
+ UpdateMulticastListAction action = 2;
+ repeated Controlee controlees = 3;
+}
+
+// Response of the UwbService::UpdateControllerMulticastList() method.
+message UpdateControllerMulticastListResponse {
+ Status status = 1;
+}
+
+// Argument of the UwbService::AndroidSetCountryCode() method.
+message AndroidSetCountryCodeRequest {
+ string country_code = 1;
+}
+
+// Response of the UwbService::AndroidSetCountryCode() method.
+message AndroidSetCountryCodeResponse {
+ Status status = 1;
+}
+
+// Response of the UwbService::AndroidGetPowerStats() method.
+message AndroidGetPowerStatsResponse {
+ Status status = 1;
+ PowerStats power_stats = 2;
+}
+
+// Argument of the UwbService::SendVendorCmd() method.
+message SendVendorCmdRequest {
+ uint32 gid = 1;
+ uint32 oid = 2;
+ bytes payload = 3;
+ uint32 mt = 4;
+}
+
+// Response of the UwbService::SendVendorCmd() method.
+message SendVendorCmdResponse {
+ Status status = 1;
+ uint32 gid = 2;
+ uint32 oid = 3;
+ bytes payload = 4;
+}
+
+// Argument of the UwbServiceCallback::onServiceReset() method.
+message ServiceResetSignal {
+ bool success = 1;
+}
+
+// Argument of the UwbServiceCallback::onUciDeviceStatusChanged() method.
+message UciDeviceStatusChangedSignal {
+ DeviceState state = 1;
+}
+
+// Argument of the UwbServiceCallback::onSessionStateChanged() method.
+message SessionStateChangedSignal {
+ uint32 session_id = 1;
+ SessionState session_state = 2;
+ ReasonCode reason_code = 3;
+}
+
+// Argument of the UwbServiceCallback::onRangeDataReceived() method.
+message RangeDataReceivedSignal {
+ uint32 session_id = 1;
+ SessionRangeData range_data = 2;
+}
+
+// Argument of the UwbServiceCallback::onVendorNotificationReceived() method.
+message VendorNotificationReceivedSignal {
+ uint32 gid = 1;
+ uint32 oid = 2;
+ bytes payload = 3;
+}
diff --git a/src/rust/uwb_core/src/error.rs b/src/rust/uwb_core/src/error.rs
index da2be79..0b9c6b3 100644
--- a/src/rust/uwb_core/src/error.rs
+++ b/src/rust/uwb_core/src/error.rs
@@ -22,6 +22,9 @@ pub enum Error {
/// current state.
#[error("Bad parameters")]
BadParameters,
+ /// Error across Foreign Function Interface.
+ #[error("Error across Foreign Function Interface")]
+ ForeignFunctionInterface,
/// The maximum number of sessions has been reached.
#[error("The maximum number of sessions has been reached")]
MaxSessionsExceeded,
@@ -43,12 +46,15 @@ pub enum Error {
/// Duplicated SessionId.
#[error("Duplicated SessionId")]
DuplicatedSessionId,
+ /// Packet Tx Error
+ #[error("The packet send failed with an error")]
+ PacketTxError,
/// The unknown error.
#[error("The unknown error")]
Unknown,
/// The result of the mock method is not assigned
- #[cfg(test)]
+ #[cfg(any(test, feature = "mock-utils"))]
#[error("The result of the mock method is not assigned")]
MockUndefined,
}
diff --git a/src/rust/uwb_core/src/lib.rs b/src/rust/uwb_core/src/lib.rs
index 9049525..8f1eb1f 100644
--- a/src/rust/uwb_core/src/lib.rs
+++ b/src/rust/uwb_core/src/lib.rs
@@ -19,5 +19,7 @@ pub(crate) mod utils;
pub mod error;
pub mod params;
+#[cfg(feature = "proto")]
+pub mod proto;
pub mod service;
pub mod uci;
diff --git a/src/rust/uwb_core/src/params/app_config_params.rs b/src/rust/uwb_core/src/params/app_config_params.rs
index 8d58366..bb06d52 100644
--- a/src/rust/uwb_core/src/params/app_config_params.rs
+++ b/src/rust/uwb_core/src/params/app_config_params.rs
@@ -26,7 +26,7 @@ pub(super) type AppConfigTlvMap = HashMap<AppConfigTlvType, Vec<u8>>;
/// The application configuration parameters of the UWB session. It is used to generate the
/// parameters for the SESSION_SET_APP_CONFIG_CMD, or converted from the result of the
/// SESSION_GET_APP_CONFIG_CMD.
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AppConfigParams {
Fira(FiraAppConfigParams),
Ccc(CccAppConfigParams),
diff --git a/src/rust/uwb_core/src/params/fira_app_config_params.rs b/src/rust/uwb_core/src/params/fira_app_config_params.rs
index dbe959d..880d197 100644
--- a/src/rust/uwb_core/src/params/fira_app_config_params.rs
+++ b/src/rust/uwb_core/src/params/fira_app_config_params.rs
@@ -1265,8 +1265,8 @@ mod tests {
),
(AppConfigTlvType::DeviceRole, vec![device_role as u8]),
(AppConfigTlvType::RframeConfig, vec![rframe_config as u8]),
- (AppConfigTlvType::PreambleCodeIndex, vec![preamble_code_index as u8]),
- (AppConfigTlvType::SfdId, vec![sfd_id as u8]),
+ (AppConfigTlvType::PreambleCodeIndex, vec![preamble_code_index]),
+ (AppConfigTlvType::SfdId, vec![sfd_id]),
(AppConfigTlvType::PsduDataRate, vec![psdu_data_rate as u8]),
(AppConfigTlvType::PreambleDuration, vec![preamble_duration as u8]),
(AppConfigTlvType::RangingTimeStruct, vec![DEFAULT_RANGING_TIME_STRUCT as u8]),
@@ -1289,7 +1289,7 @@ mod tests {
(AppConfigTlvType::ResultReportConfig, vec![result_report_config.as_u8()]),
(
AppConfigTlvType::InBandTerminationAttemptCount,
- vec![in_band_termination_attempt_count as u8],
+ vec![in_band_termination_attempt_count],
),
(AppConfigTlvType::BprfPhrDataRate, vec![DEFAULT_BPRF_PHR_DATA_RATE as u8]),
(
diff --git a/src/rust/uwb_core/src/params/uci_packets.rs b/src/rust/uwb_core/src/params/uci_packets.rs
index 421ed1e..2e0941e 100644
--- a/src/rust/uwb_core/src/params/uci_packets.rs
+++ b/src/rust/uwb_core/src/params/uci_packets.rs
@@ -21,11 +21,18 @@ use std::iter::FromIterator;
// Re-export enums and structs from uwb_uci_packets.
pub use uwb_uci_packets::{
AppConfigStatus, AppConfigTlv as RawAppConfigTlv, AppConfigTlvType, CapTlv, CapTlvType,
- Controlee, ControleeStatus, ControleesV2, DeviceConfigId, DeviceConfigStatus, DeviceConfigTlv,
- DeviceState, ExtendedAddressTwoWayRangingMeasurement, MulticastUpdateStatusCode, PowerStats,
- RangingMeasurementType, ReasonCode, ResetConfig, SessionState, SessionType,
- ShortAddressTwoWayRangingMeasurement, StatusCode, UpdateMulticastListAction,
+ Controlee, ControleeStatus, Controlees, CreditAvailability, DataRcvStatusCode,
+ DataTransferNtfStatusCode, DeviceConfigId, DeviceConfigStatus, DeviceConfigTlv, DeviceState,
+ ExtendedAddressDlTdoaRangingMeasurement, ExtendedAddressOwrAoaRangingMeasurement,
+ ExtendedAddressTwoWayRangingMeasurement, FiraComponent, GroupId, MessageType,
+ MulticastUpdateStatusCode, OwrAoaStatusCode, PowerStats, RangingMeasurementType, ReasonCode,
+ ResetConfig, SessionState, SessionType, ShortAddressDlTdoaRangingMeasurement,
+ ShortAddressOwrAoaRangingMeasurement, ShortAddressTwoWayRangingMeasurement, StatusCode,
+ UpdateMulticastListAction,
};
+pub(crate) use uwb_uci_packets::{UciControlPacket, UciDataPacket, UciDataPacketHal};
+
+use crate::error::Error;
/// The type of the session identifier.
pub type SessionId = u32;
@@ -132,17 +139,30 @@ pub struct SetAppConfigResponse {
pub config_status: Vec<AppConfigStatus>,
}
+/// The response from UciManager::session_update_dt_tag_ranging_rounds() method.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct SessionUpdateDtTagRangingRoundsResponse {
+ /// The status code of the response.
+ pub status: StatusCode,
+ /// Indexes of unsuccessful ranging rounds.
+ pub ranging_round_indexes: Vec<u8>,
+}
+
/// The country code struct that contains 2 uppercase ASCII characters.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CountryCode([u8; 2]);
impl CountryCode {
+ const UNKNOWN_COUNTRY_CODE: &'static [u8] = "00".as_bytes();
+
/// Create a CountryCode instance.
pub fn new(code: &[u8; 2]) -> Option<Self> {
- if !code[0].is_ascii_uppercase() || !code[1].is_ascii_uppercase() {
+ if code != CountryCode::UNKNOWN_COUNTRY_CODE
+ && !code.iter().all(|x| (*x as char).is_ascii_alphabetic())
+ {
None
} else {
- Some(Self(*code))
+ Some(Self((*code).to_ascii_uppercase().try_into().ok()?))
}
}
}
@@ -153,6 +173,14 @@ impl From<CountryCode> for [u8; 2] {
}
}
+impl TryFrom<String> for CountryCode {
+ type Error = Error;
+ fn try_from(item: String) -> Result<Self, Self::Error> {
+ let code = item.as_bytes().try_into().map_err(|_| Error::BadParameters)?;
+ Self::new(code).ok_or(Error::BadParameters)
+ }
+}
+
/// The response of the UciManager::core_get_device_info() method.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GetDeviceInfoResponse {
@@ -170,7 +198,7 @@ pub struct GetDeviceInfoResponse {
/// The raw UCI message for the vendor commands.
#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct RawVendorMessage {
+pub struct RawUciMessage {
/// The group id of the message.
pub gid: u32,
/// The opcode of the message.
@@ -179,6 +207,16 @@ pub struct RawVendorMessage {
pub payload: Vec<u8>,
}
+impl From<UciControlPacket> for RawUciMessage {
+ fn from(packet: UciControlPacket) -> Self {
+ Self {
+ gid: packet.get_group_id().into(),
+ oid: packet.get_opcode() as u32,
+ payload: packet.to_raw_payload(),
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -199,4 +237,14 @@ mod tests {
let format_str = format!("{tlv:?}");
assert_eq!(format_str, "AppConfigTlv { cfg_id: DeviceType, v: [12, 34] }");
}
+
+ #[test]
+ fn test_country_code() {
+ let _country_code_ascii: CountryCode = String::from("US").try_into().unwrap();
+ let _country_code_unknown: CountryCode = String::from("00").try_into().unwrap();
+ let country_code_invalid_1: Result<CountryCode, Error> = String::from("0S").try_into();
+ country_code_invalid_1.unwrap_err();
+ let country_code_invalid_2: Result<CountryCode, Error> = String::from("ÀÈ").try_into();
+ country_code_invalid_2.unwrap_err();
+ }
}
diff --git a/src/rust/uwb_core/src/proto.rs b/src/rust/uwb_core/src/proto.rs
new file mode 100644
index 0000000..7cf2740
--- /dev/null
+++ b/src/rust/uwb_core/src/proto.rs
@@ -0,0 +1,21 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Provide the protobuf bindings and the conversion between the elements of uwb_core and protobuf.
+
+// Include the protobuf bindings generated from protoc_rust to "pub mod bindings;".
+include!(concat!(env!("OUT_DIR"), "/proto_bindings.rs"));
+
+pub(crate) mod mappings;
+pub mod utils;
diff --git a/src/rust/uwb_core/src/proto/mappings.rs b/src/rust/uwb_core/src/proto/mappings.rs
new file mode 100644
index 0000000..0d21c09
--- /dev/null
+++ b/src/rust/uwb_core/src/proto/mappings.rs
@@ -0,0 +1,1208 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Provide the conversion between the uwb_core's elements and protobuf bindings.
+
+use std::convert::{TryFrom, TryInto};
+
+use protobuf::RepeatedField;
+use zeroize::Zeroize;
+
+use crate::error::{Error, Result};
+use crate::params::fira_app_config_params::{
+ AoaResultRequest, BprfPhrDataRate, DeviceRole, DeviceType, FiraAppConfigParams,
+ FiraAppConfigParamsBuilder, HoppingMode, KeyRotation, MacAddressMode, MacFcsType,
+ MultiNodeMode, PreambleDuration, PrfMode, PsduDataRate, RangeDataNtfConfig,
+ RangingRoundControl, RangingRoundUsage, RangingTimeStruct, ResultReportConfig, RframeConfig,
+ ScheduledMode, StsConfig, StsLength, TxAdaptivePayloadPower, UwbAddress, UwbChannel,
+};
+use crate::params::uci_packets::{
+ Controlee, DeviceState, ExtendedAddressDlTdoaRangingMeasurement,
+ ExtendedAddressOwrAoaRangingMeasurement, ExtendedAddressTwoWayRangingMeasurement,
+ OwrAoaStatusCode, PowerStats, RangingMeasurementType, ReasonCode, SessionState, SessionType,
+ ShortAddressDlTdoaRangingMeasurement, ShortAddressOwrAoaRangingMeasurement,
+ ShortAddressTwoWayRangingMeasurement, StatusCode, UpdateMulticastListAction,
+};
+use crate::params::AppConfigParams;
+use crate::proto::bindings::{
+ AoaResultRequest as ProtoAoaResultRequest, BprfPhrDataRate as ProtoBprfPhrDataRate,
+ Controlee as ProtoControlee, DeviceRole as ProtoDeviceRole, DeviceState as ProtoDeviceState,
+ DeviceType as ProtoDeviceType, DlTDoARangingMeasurement as ProtoDlTDoARangingMeasurement,
+ FiraAppConfigParams as ProtoFiraAppConfigParams, HoppingMode as ProtoHoppingMode,
+ KeyRotation as ProtoKeyRotation, MacAddressMode as ProtoMacAddressMode,
+ MacFcsType as ProtoMacFcsType, MultiNodeMode as ProtoMultiNodeMode,
+ OwrAoaRangingMeasurement as ProtoOwrAoaRangingMeasurement,
+ OwrAoaStatusCode as ProtoOwrAoaStatusCode, PowerStats as ProtoPowerStats,
+ PreambleDuration as ProtoPreambleDuration, PrfMode as ProtoPrfMode,
+ PsduDataRate as ProtoPsduDataRate, RangeDataNtfConfig as ProtoRangeDataNtfConfig,
+ RangingMeasurementType as ProtoRangingMeasurementType,
+ RangingRoundControl as ProtoRangingRoundControl, RangingRoundUsage as ProtoRangingRoundUsage,
+ RangingTimeStruct as ProtoRangingTimeStruct, ReasonCode as ProtoReasonCode,
+ ResultReportConfig as ProtoResultReportConfig, RframeConfig as ProtoRframeConfig,
+ ScheduledMode as ProtoScheduledMode, SessionRangeData as ProtoSessionRangeData,
+ SessionState as ProtoSessionState, SessionType as ProtoSessionType, Status as ProtoStatus,
+ StatusCode as ProtoStatusCode, StsConfig as ProtoStsConfig, StsLength as ProtoStsLength,
+ TwoWayRangingMeasurement as ProtoTwoWayRangingMeasurement,
+ TxAdaptivePayloadPower as ProtoTxAdaptivePayloadPower, UciLoggerMode as ProtoUciLoggerMode,
+ UpdateMulticastListAction as ProtoUpdateMulticastListAction, UwbChannel as ProtoUwbChannel,
+};
+use crate::uci::notification::{RangingMeasurements, SessionRangeData};
+use crate::uci::uci_logger::UciLoggerMode;
+
+/// Generate the conversion functions between 2 enum types, which field is 1-to-1 mapping.
+///
+/// Example:
+/// ```
+/// enum EnumA {
+/// Value1,
+/// Value2,
+/// }
+/// enum EnumB {
+/// Foo,
+/// Bar,
+/// }
+/// // This macro generates `From<EnumA> for EnumB` and `From<EnumB> for EnumA`.
+/// uwb_core::enum_mapping! {
+/// EnumA => EnumB,
+/// Value1 => Foo,
+/// Value2 => Bar,
+/// }
+/// ```
+#[macro_export]
+macro_rules! enum_mapping {
+ ( $enum_a:ty => $enum_b:ty, $( $field_a:ident => $field_b:ident, )+ ) => {
+ impl From<$enum_a> for $enum_b {
+ fn from(item: $enum_a) -> $enum_b {
+ match item {
+ $(
+ <$enum_a>::$field_a => <$enum_b>::$field_b,
+ )*
+ }
+ }
+ }
+ impl From<$enum_b> for $enum_a {
+ fn from(item: $enum_b) -> $enum_a {
+ match item {
+ $(
+ <$enum_b>::$field_b => <$enum_a>::$field_a,
+ )*
+ }
+ }
+ }
+ };
+}
+
+impl From<ProtoStatusCode> for StatusCode {
+ fn from(item: ProtoStatusCode) -> Self {
+ match item {
+ ProtoStatusCode::UCI_STATUS_OK => StatusCode::UciStatusOk,
+ ProtoStatusCode::UCI_STATUS_REJECTED => StatusCode::UciStatusRejected,
+ ProtoStatusCode::UCI_STATUS_FAILED => StatusCode::UciStatusFailed,
+ ProtoStatusCode::UCI_STATUS_SYNTAX_ERROR => StatusCode::UciStatusSyntaxError,
+ ProtoStatusCode::UCI_STATUS_INVALID_PARAM => StatusCode::UciStatusInvalidParam,
+ ProtoStatusCode::UCI_STATUS_INVALID_RANGE => StatusCode::UciStatusInvalidRange,
+ ProtoStatusCode::UCI_STATUS_INVALID_MSG_SIZE => StatusCode::UciStatusInvalidMsgSize,
+ ProtoStatusCode::UCI_STATUS_UNKNOWN_GID => StatusCode::UciStatusUnknownGid,
+ ProtoStatusCode::UCI_STATUS_UNKNOWN_OID => StatusCode::UciStatusUnknownOid,
+ ProtoStatusCode::UCI_STATUS_READ_ONLY => StatusCode::UciStatusReadOnly,
+ ProtoStatusCode::UCI_STATUS_COMMAND_RETRY => StatusCode::UciStatusCommandRetry,
+ ProtoStatusCode::UCI_STATUS_SESSION_NOT_EXIST => StatusCode::UciStatusSessionNotExist,
+ ProtoStatusCode::UCI_STATUS_SESSION_DUPLICATE => StatusCode::UciStatusSessionDuplicate,
+ ProtoStatusCode::UCI_STATUS_SESSION_ACTIVE => StatusCode::UciStatusSessionActive,
+ ProtoStatusCode::UCI_STATUS_MAX_SESSIONS_EXCEEDED => {
+ StatusCode::UciStatusMaxSessionsExceeded
+ }
+ ProtoStatusCode::UCI_STATUS_SESSION_NOT_CONFIGURED => {
+ StatusCode::UciStatusSessionNotConfigured
+ }
+ ProtoStatusCode::UCI_STATUS_ACTIVE_SESSIONS_ONGOING => {
+ StatusCode::UciStatusActiveSessionsOngoing
+ }
+ ProtoStatusCode::UCI_STATUS_MULTICAST_LIST_FULL => {
+ StatusCode::UciStatusMulticastListFull
+ }
+ ProtoStatusCode::UCI_STATUS_ADDRESS_NOT_FOUND => StatusCode::UciStatusAddressNotFound,
+ ProtoStatusCode::UCI_STATUS_ADDRESS_ALREADY_PRESENT => {
+ StatusCode::UciStatusAddressAlreadyPresent
+ }
+ ProtoStatusCode::UCI_STATUS_OK_NEGATIVE_DISTANCE_REPORT => {
+ StatusCode::UciStatusOkNegativeDistanceReport
+ }
+ ProtoStatusCode::UCI_STATUS_RANGING_TX_FAILED => StatusCode::UciStatusRangingTxFailed,
+ ProtoStatusCode::UCI_STATUS_RANGING_RX_TIMEOUT => {
+ StatusCode::UciStatusRangingRxTimeout
+ }
+ ProtoStatusCode::UCI_STATUS_RANGING_RX_PHY_DEC_FAILED => {
+ StatusCode::UciStatusRangingRxPhyDecFailed
+ }
+ ProtoStatusCode::UCI_STATUS_RANGING_RX_PHY_TOA_FAILED => {
+ StatusCode::UciStatusRangingRxPhyToaFailed
+ }
+ ProtoStatusCode::UCI_STATUS_RANGING_RX_PHY_STS_FAILED => {
+ StatusCode::UciStatusRangingRxPhyStsFailed
+ }
+ ProtoStatusCode::UCI_STATUS_RANGING_RX_MAC_DEC_FAILED => {
+ StatusCode::UciStatusRangingRxMacDecFailed
+ }
+ ProtoStatusCode::UCI_STATUS_RANGING_RX_MAC_IE_DEC_FAILED => {
+ StatusCode::UciStatusRangingRxMacIeDecFailed
+ }
+ ProtoStatusCode::UCI_STATUS_RANGING_RX_MAC_IE_MISSING => {
+ StatusCode::UciStatusRangingRxMacIeMissing
+ }
+ ProtoStatusCode::UCI_STATUS_ERROR_ROUND_INDEX_NOT_ACTIVATED => {
+ StatusCode::UciStatusErrorRoundIndexNotActivated
+ }
+ ProtoStatusCode::UCI_STATUS_ERROR_NUMBER_OF_ACTIVE_RANGING_ROUNDS_EXCEEDED => {
+ StatusCode::UciStatusErrorNumberOfActiveRangingRoundsExceeded
+ }
+ ProtoStatusCode::UCI_STATUS_ERROR_ROUND_INDEX_NOT_SET_AS_INITIATOR => {
+ StatusCode::UciStatusErrorRoundIndexNotSetAsInitiator
+ }
+ ProtoStatusCode::UCI_STATUS_ERROR_DL_TDOA_DEVICE_ADDRESS_NOT_MATCHING_IN_REPLY_TIME_LIST =>
+ StatusCode::UciStatusErrorDlTdoaDeviceAddressNotMatchingInReplyTimeList,
+ ProtoStatusCode::UCI_STATUS_DATA_MAX_TX_PSDU_SIZE_EXCEEDED => {
+ StatusCode::UciStatusDataMaxTxPsduSizeExceeded
+ }
+ ProtoStatusCode::UCI_STATUS_DATA_RX_CRC_ERROR => StatusCode::UciStatusDataRxCrcError,
+ ProtoStatusCode::UCI_STATUS_ERROR_CCC_SE_BUSY => StatusCode::UciStatusErrorCccSeBusy,
+ ProtoStatusCode::UCI_STATUS_ERROR_CCC_LIFECYCLE => {
+ StatusCode::UciStatusErrorCccLifecycle
+ }
+ ProtoStatusCode::UCI_STATUS_ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT => {
+ StatusCode::UciStatusErrorStoppedDueToOtherSessionConflict
+ }
+ _ => StatusCode::VendorSpecificStatusCode2,
+ }
+ }
+}
+
+impl From<StatusCode> for ProtoStatusCode {
+ fn from(item: StatusCode) -> Self {
+ match item {
+ StatusCode::UciStatusOk => ProtoStatusCode::UCI_STATUS_OK,
+ StatusCode::UciStatusRejected => ProtoStatusCode::UCI_STATUS_REJECTED,
+ StatusCode::UciStatusFailed => ProtoStatusCode::UCI_STATUS_FAILED,
+ StatusCode::UciStatusSyntaxError => ProtoStatusCode::UCI_STATUS_SYNTAX_ERROR,
+ StatusCode::UciStatusInvalidParam => ProtoStatusCode::UCI_STATUS_INVALID_PARAM,
+ StatusCode::UciStatusInvalidRange => ProtoStatusCode::UCI_STATUS_INVALID_RANGE,
+ StatusCode::UciStatusInvalidMsgSize => ProtoStatusCode::UCI_STATUS_INVALID_MSG_SIZE,
+ StatusCode::UciStatusUnknownGid => ProtoStatusCode::UCI_STATUS_UNKNOWN_GID,
+ StatusCode::UciStatusUnknownOid => ProtoStatusCode::UCI_STATUS_UNKNOWN_OID,
+ StatusCode::UciStatusReadOnly => ProtoStatusCode::UCI_STATUS_READ_ONLY,
+ StatusCode::UciStatusCommandRetry => ProtoStatusCode::UCI_STATUS_COMMAND_RETRY,
+ StatusCode::UciStatusSessionNotExist => ProtoStatusCode::UCI_STATUS_SESSION_NOT_EXIST,
+ StatusCode::UciStatusSessionDuplicate => ProtoStatusCode::UCI_STATUS_SESSION_DUPLICATE,
+ StatusCode::UciStatusSessionActive => ProtoStatusCode::UCI_STATUS_SESSION_ACTIVE,
+ StatusCode::UciStatusMaxSessionsExceeded => {
+ ProtoStatusCode::UCI_STATUS_MAX_SESSIONS_EXCEEDED
+ }
+ StatusCode::UciStatusSessionNotConfigured => {
+ ProtoStatusCode::UCI_STATUS_SESSION_NOT_CONFIGURED
+ }
+ StatusCode::UciStatusActiveSessionsOngoing => {
+ ProtoStatusCode::UCI_STATUS_ACTIVE_SESSIONS_ONGOING
+ }
+ StatusCode::UciStatusMulticastListFull => {
+ ProtoStatusCode::UCI_STATUS_MULTICAST_LIST_FULL
+ }
+ StatusCode::UciStatusAddressNotFound => {
+ ProtoStatusCode::UCI_STATUS_ADDRESS_NOT_FOUND
+ }
+ StatusCode::UciStatusAddressAlreadyPresent => {
+ ProtoStatusCode::UCI_STATUS_ADDRESS_ALREADY_PRESENT
+ }
+ StatusCode::UciStatusOkNegativeDistanceReport => {
+ ProtoStatusCode::UCI_STATUS_OK_NEGATIVE_DISTANCE_REPORT
+ }
+ StatusCode::UciStatusRangingTxFailed => {
+ ProtoStatusCode::UCI_STATUS_RANGING_TX_FAILED
+ }
+ StatusCode::UciStatusRangingRxTimeout => {
+ ProtoStatusCode::UCI_STATUS_RANGING_RX_TIMEOUT
+ }
+ StatusCode::UciStatusRangingRxPhyDecFailed => {
+ ProtoStatusCode::UCI_STATUS_RANGING_RX_PHY_DEC_FAILED
+ }
+ StatusCode::UciStatusRangingRxPhyToaFailed => {
+ ProtoStatusCode::UCI_STATUS_RANGING_RX_PHY_TOA_FAILED
+ }
+ StatusCode::UciStatusRangingRxPhyStsFailed => {
+ ProtoStatusCode::UCI_STATUS_RANGING_RX_PHY_STS_FAILED
+ }
+ StatusCode::UciStatusRangingRxMacDecFailed => {
+ ProtoStatusCode::UCI_STATUS_RANGING_RX_MAC_DEC_FAILED
+ }
+ StatusCode::UciStatusRangingRxMacIeDecFailed => {
+ ProtoStatusCode::UCI_STATUS_RANGING_RX_MAC_IE_DEC_FAILED
+ }
+ StatusCode::UciStatusRangingRxMacIeMissing => {
+ ProtoStatusCode::UCI_STATUS_RANGING_RX_MAC_IE_MISSING
+ }
+ StatusCode::UciStatusErrorRoundIndexNotActivated => {
+ ProtoStatusCode::UCI_STATUS_ERROR_ROUND_INDEX_NOT_ACTIVATED
+ }
+ StatusCode::UciStatusErrorNumberOfActiveRangingRoundsExceeded => {
+ ProtoStatusCode::UCI_STATUS_ERROR_NUMBER_OF_ACTIVE_RANGING_ROUNDS_EXCEEDED
+ }
+ StatusCode::UciStatusErrorRoundIndexNotSetAsInitiator => {
+ ProtoStatusCode::UCI_STATUS_ERROR_ROUND_INDEX_NOT_SET_AS_INITIATOR
+ }
+ StatusCode::UciStatusErrorDlTdoaDeviceAddressNotMatchingInReplyTimeList => {
+ ProtoStatusCode::UCI_STATUS_ERROR_DL_TDOA_DEVICE_ADDRESS_NOT_MATCHING_IN_REPLY_TIME_LIST
+ }
+ StatusCode::UciStatusDataMaxTxPsduSizeExceeded => {
+ ProtoStatusCode::UCI_STATUS_DATA_MAX_TX_PSDU_SIZE_EXCEEDED
+ }
+ StatusCode::UciStatusDataRxCrcError => {
+ ProtoStatusCode::UCI_STATUS_DATA_RX_CRC_ERROR
+ }
+ StatusCode::UciStatusErrorCccSeBusy => {
+ ProtoStatusCode::UCI_STATUS_ERROR_CCC_SE_BUSY
+ }
+ StatusCode::UciStatusErrorCccLifecycle => {
+ ProtoStatusCode::UCI_STATUS_ERROR_CCC_LIFECYCLE
+ }
+ StatusCode::UciStatusErrorStoppedDueToOtherSessionConflict => {
+ ProtoStatusCode::UCI_STATUS_ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT
+ }
+ _ => ProtoStatusCode::UCI_STATUS_RFU_OR_VENDOR_SPECIFIC,
+ }
+ }
+}
+
+enum_mapping! {
+ ProtoOwrAoaStatusCode => OwrAoaStatusCode,
+ UCI_STATUS_SUCCESS => UciStatusSuccess,
+ UCI_STATUS_INTER_FRAME_INTERVAL_TIMEOUT => UciStatusInterFrameIntervalTimeout,
+}
+
+enum_mapping! {
+ ProtoDeviceState => DeviceState,
+ DEVICE_STATE_READY => DeviceStateReady,
+ DEVICE_STATE_ACTIVE => DeviceStateActive,
+ DEVICE_STATE_ERROR => DeviceStateError,
+}
+
+enum_mapping! {
+ ProtoSessionState => SessionState,
+ INIT => SessionStateInit,
+ DEINIT => SessionStateDeinit,
+ ACTIVE => SessionStateActive,
+ IDLE => SessionStateIdle,
+}
+
+impl From<ProtoReasonCode> for ReasonCode {
+ fn from(item: ProtoReasonCode) -> Self {
+ match item {
+ ProtoReasonCode::STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS => {
+ ReasonCode::StateChangeWithSessionManagementCommands
+ }
+ ProtoReasonCode::MAX_RANGING_ROUND_RETRY_COUNT_REACHED => {
+ ReasonCode::MaxRangingRoundRetryCountReached
+ }
+ ProtoReasonCode::MAX_NUMBER_OF_MEASUREMENTS_REACHED => {
+ ReasonCode::MaxNumberOfMeasurementsReached
+ }
+ ProtoReasonCode::SESSION_SUSPENDED_DUE_TO_INBAND_SIGNAL => {
+ ReasonCode::SessionSuspendedDueToInbandSignal
+ }
+ ProtoReasonCode::SESSION_RESUMED_DUE_TO_INBAND_SIGNAL => {
+ ReasonCode::SessionResumedDueToInbandSignal
+ }
+ ProtoReasonCode::SESSION_STOPPED_DUE_TO_INBAND_SIGNAL => {
+ ReasonCode::SessionStoppedDueToInbandSignal
+ }
+ ProtoReasonCode::ERROR_INVALID_UL_TDOA_RANDOM_WINDOW => {
+ ReasonCode::ErrorInvalidUlTdoaRandomWindow
+ }
+ ProtoReasonCode::ERROR_MIN_RFRAMES_PER_RR_NOT_SUPPORTED => {
+ ReasonCode::ErrorMinRframesPerRrNotSupported
+ }
+ ProtoReasonCode::ERROR_TX_DELAY_NOT_SUPPORTED => ReasonCode::ErrorTxDelayNotSupported,
+ ProtoReasonCode::ERROR_SLOT_LENGTH_NOT_SUPPORTED => {
+ ReasonCode::ErrorSlotLengthNotSupported
+ }
+ ProtoReasonCode::ERROR_INSUFFICIENT_SLOTS_PER_RR => {
+ ReasonCode::ErrorInsufficientSlotsPerRr
+ }
+ ProtoReasonCode::ERROR_MAC_ADDRESS_MODE_NOT_SUPPORTED => {
+ ReasonCode::ErrorMacAddressModeNotSupported
+ }
+ ProtoReasonCode::ERROR_INVALID_RANGING_DURATION => {
+ ReasonCode::ErrorInvalidRangingDuration
+ }
+ ProtoReasonCode::ERROR_INVALID_STS_CONFIG => ReasonCode::ErrorInvalidStsConfig,
+ ProtoReasonCode::ERROR_INVALID_RFRAME_CONFIG => ReasonCode::ErrorInvalidRframeConfig,
+ ProtoReasonCode::ERROR_HUS_NOT_ENOUGH_SLOTS => ReasonCode::ErrorHusNotEnoughSlots,
+ ProtoReasonCode::ERROR_HUS_CFP_PHASE_TOO_SHORT => ReasonCode::ErrorHusCfpPhaseTooShort,
+ ProtoReasonCode::ERROR_HUS_CAP_PHASE_TOO_SHORT => ReasonCode::ErrorHusCapPhaseTooShort,
+ ProtoReasonCode::ERROR_HUS_OTHERS => ReasonCode::ErrorHusOthers,
+ ProtoReasonCode::ERROR_STATUS_SESSION_KEY_NOT_FOUND => {
+ ReasonCode::ErrorStatusSessionKeyNotFound
+ }
+ ProtoReasonCode::ERROR_STATUS_SUB_SESSION_KEY_NOT_FOUND => {
+ ReasonCode::ErrorStatusSubSessionKeyNotFound
+ }
+ ProtoReasonCode::ERROR_INVALID_PREAMBLE_CODE_INDEX => {
+ ReasonCode::ErrorInvalidPreambleCodeIndex
+ }
+ ProtoReasonCode::ERROR_INVALID_SFD_ID => ReasonCode::ErrorInvalidSfdId,
+ ProtoReasonCode::ERROR_INVALID_PSDU_DATA_RATE => ReasonCode::ErrorInvalidPsduDataRate,
+ ProtoReasonCode::ERROR_INVALID_PHR_DATA_RATE => ReasonCode::ErrorInvalidPhrDataRate,
+ ProtoReasonCode::ERROR_INVALID_PREAMBLE_DURATION => {
+ ReasonCode::ErrorInvalidPreambleDuration
+ }
+ ProtoReasonCode::ERROR_INVALID_STS_LENGTH => ReasonCode::ErrorInvalidStsLength,
+ ProtoReasonCode::ERROR_INVALID_NUM_OF_STS_SEGMENTS => {
+ ReasonCode::ErrorInvalidNumOfStsSegments
+ }
+ ProtoReasonCode::ERROR_INVALID_NUM_OF_CONTROLEES => {
+ ReasonCode::ErrorInvalidNumOfControlees
+ }
+ ProtoReasonCode::ERROR_MAX_RANGING_REPLY_TIME_EXCEEDED => {
+ ReasonCode::ErrorMaxRangingReplyTimeExceeded
+ }
+ ProtoReasonCode::ERROR_INVALID_DST_ADDRESS_LIST => {
+ ReasonCode::ErrorInvalidDstAddressList
+ }
+ ProtoReasonCode::ERROR_INVALID_OR_NOT_FOUND_SUB_SESSION_ID => {
+ ReasonCode::ErrorInvalidOrNotFoundSubSessionId
+ }
+ ProtoReasonCode::ERROR_INVALID_RESULT_REPORT_CONFIG => {
+ ReasonCode::ErrorInvalidResultReportConfig
+ }
+ ProtoReasonCode::ERROR_INVALID_RANGING_ROUND_USAGE => {
+ ReasonCode::ErrorInvalidRangingRoundUsage
+ }
+ ProtoReasonCode::ERROR_INVALID_MULTI_NODE_MODE => ReasonCode::ErrorInvalidMultiNodeMode,
+ ProtoReasonCode::ERROR_RDS_FETCH_FAILURE => ReasonCode::ErrorRdsFetchFailure,
+ ProtoReasonCode::ERROR_REF_UWB_SESSION_DOES_NOT_EXIST => {
+ ReasonCode::ErrorRefUwbSessionDoesNotExist
+ }
+ ProtoReasonCode::ERROR_REF_UWB_SESSION_RANGING_DURATION_MISMATCH => {
+ ReasonCode::ErrorRefUwbSessionRangingDurationMismatch
+ }
+ ProtoReasonCode::ERROR_REF_UWB_SESSION_INVALID_OFFSET_TIME => {
+ ReasonCode::ErrorRefUwbSessionInvalidOffsetTime
+ }
+ ProtoReasonCode::ERROR_REF_UWB_SESSION_LOST => ReasonCode::ErrorRefUwbSessionLost,
+ ProtoReasonCode::ERROR_INVALID_CHANNEL_WITH_AOA => {
+ ReasonCode::ErrorInvalidChannelWithAoa
+ }
+ ProtoReasonCode::ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT => {
+ ReasonCode::ErrorStoppedDueToOtherSessionConflict
+ }
+ _ => ReasonCode::VendorSpecificReasonCode2,
+ }
+ }
+}
+
+impl From<ReasonCode> for ProtoReasonCode {
+ fn from(item: ReasonCode) -> Self {
+ match item {
+ ReasonCode::StateChangeWithSessionManagementCommands => {
+ ProtoReasonCode::STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS
+ }
+ ReasonCode::MaxRangingRoundRetryCountReached => {
+ ProtoReasonCode::MAX_RANGING_ROUND_RETRY_COUNT_REACHED
+ }
+ ReasonCode::MaxNumberOfMeasurementsReached => {
+ ProtoReasonCode::MAX_NUMBER_OF_MEASUREMENTS_REACHED
+ }
+ ReasonCode::SessionSuspendedDueToInbandSignal => {
+ ProtoReasonCode::SESSION_SUSPENDED_DUE_TO_INBAND_SIGNAL
+ }
+ ReasonCode::SessionResumedDueToInbandSignal => {
+ ProtoReasonCode::SESSION_RESUMED_DUE_TO_INBAND_SIGNAL
+ }
+ ReasonCode::SessionStoppedDueToInbandSignal => {
+ ProtoReasonCode::SESSION_STOPPED_DUE_TO_INBAND_SIGNAL
+ }
+ ReasonCode::ErrorInvalidUlTdoaRandomWindow => {
+ ProtoReasonCode::ERROR_INVALID_UL_TDOA_RANDOM_WINDOW
+ }
+ ReasonCode::ErrorMinRframesPerRrNotSupported => {
+ ProtoReasonCode::ERROR_MIN_RFRAMES_PER_RR_NOT_SUPPORTED
+ }
+ ReasonCode::ErrorTxDelayNotSupported => ProtoReasonCode::ERROR_TX_DELAY_NOT_SUPPORTED,
+ ReasonCode::ErrorSlotLengthNotSupported => {
+ ProtoReasonCode::ERROR_SLOT_LENGTH_NOT_SUPPORTED
+ }
+ ReasonCode::ErrorInsufficientSlotsPerRr => {
+ ProtoReasonCode::ERROR_INSUFFICIENT_SLOTS_PER_RR
+ }
+ ReasonCode::ErrorMacAddressModeNotSupported => {
+ ProtoReasonCode::ERROR_MAC_ADDRESS_MODE_NOT_SUPPORTED
+ }
+ ReasonCode::ErrorInvalidRangingDuration => {
+ ProtoReasonCode::ERROR_INVALID_RANGING_DURATION
+ }
+ ReasonCode::ErrorInvalidStsConfig => ProtoReasonCode::ERROR_INVALID_STS_CONFIG,
+ ReasonCode::ErrorInvalidRframeConfig => ProtoReasonCode::ERROR_INVALID_RFRAME_CONFIG,
+ ReasonCode::ErrorHusNotEnoughSlots => ProtoReasonCode::ERROR_HUS_NOT_ENOUGH_SLOTS,
+ ReasonCode::ErrorHusCfpPhaseTooShort => ProtoReasonCode::ERROR_HUS_CFP_PHASE_TOO_SHORT,
+ ReasonCode::ErrorHusCapPhaseTooShort => ProtoReasonCode::ERROR_HUS_CAP_PHASE_TOO_SHORT,
+ ReasonCode::ErrorHusOthers => ProtoReasonCode::ERROR_HUS_OTHERS,
+ ReasonCode::ErrorStatusSessionKeyNotFound => {
+ ProtoReasonCode::ERROR_STATUS_SESSION_KEY_NOT_FOUND
+ }
+ ReasonCode::ErrorStatusSubSessionKeyNotFound => {
+ ProtoReasonCode::ERROR_STATUS_SUB_SESSION_KEY_NOT_FOUND
+ }
+ ReasonCode::ErrorInvalidPreambleCodeIndex => {
+ ProtoReasonCode::ERROR_INVALID_PREAMBLE_CODE_INDEX
+ }
+ ReasonCode::ErrorInvalidSfdId => ProtoReasonCode::ERROR_INVALID_SFD_ID,
+ ReasonCode::ErrorInvalidPsduDataRate => ProtoReasonCode::ERROR_INVALID_PSDU_DATA_RATE,
+ ReasonCode::ErrorInvalidPhrDataRate => ProtoReasonCode::ERROR_INVALID_PHR_DATA_RATE,
+ ReasonCode::ErrorInvalidPreambleDuration => {
+ ProtoReasonCode::ERROR_INVALID_PREAMBLE_DURATION
+ }
+ ReasonCode::ErrorInvalidStsLength => ProtoReasonCode::ERROR_INVALID_STS_LENGTH,
+ ReasonCode::ErrorInvalidNumOfStsSegments => {
+ ProtoReasonCode::ERROR_INVALID_NUM_OF_STS_SEGMENTS
+ }
+ ReasonCode::ErrorInvalidNumOfControlees => {
+ ProtoReasonCode::ERROR_INVALID_NUM_OF_CONTROLEES
+ }
+ ReasonCode::ErrorMaxRangingReplyTimeExceeded => {
+ ProtoReasonCode::ERROR_MAX_RANGING_REPLY_TIME_EXCEEDED
+ }
+ ReasonCode::ErrorInvalidDstAddressList => {
+ ProtoReasonCode::ERROR_INVALID_DST_ADDRESS_LIST
+ }
+ ReasonCode::ErrorInvalidOrNotFoundSubSessionId => {
+ ProtoReasonCode::ERROR_INVALID_OR_NOT_FOUND_SUB_SESSION_ID
+ }
+ ReasonCode::ErrorInvalidResultReportConfig => {
+ ProtoReasonCode::ERROR_INVALID_RESULT_REPORT_CONFIG
+ }
+ ReasonCode::ErrorInvalidRangingRoundUsage => {
+ ProtoReasonCode::ERROR_INVALID_RANGING_ROUND_USAGE
+ }
+ ReasonCode::ErrorInvalidMultiNodeMode => ProtoReasonCode::ERROR_INVALID_MULTI_NODE_MODE,
+ ReasonCode::ErrorRdsFetchFailure => ProtoReasonCode::ERROR_RDS_FETCH_FAILURE,
+ ReasonCode::ErrorRefUwbSessionDoesNotExist => {
+ ProtoReasonCode::ERROR_REF_UWB_SESSION_DOES_NOT_EXIST
+ }
+ ReasonCode::ErrorRefUwbSessionRangingDurationMismatch => {
+ ProtoReasonCode::ERROR_REF_UWB_SESSION_RANGING_DURATION_MISMATCH
+ }
+ ReasonCode::ErrorRefUwbSessionInvalidOffsetTime => {
+ ProtoReasonCode::ERROR_REF_UWB_SESSION_INVALID_OFFSET_TIME
+ }
+ ReasonCode::ErrorRefUwbSessionLost => ProtoReasonCode::ERROR_REF_UWB_SESSION_LOST,
+ ReasonCode::ErrorInvalidChannelWithAoa => {
+ ProtoReasonCode::ERROR_INVALID_CHANNEL_WITH_AOA
+ }
+ ReasonCode::ErrorStoppedDueToOtherSessionConflict => {
+ ProtoReasonCode::ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT
+ }
+ ReasonCode::ErrorDtAnchorRangingRoundsNotConfigured => {
+ ProtoReasonCode::ERROR_DT_ANCHOR_RANGING_ROUNDS_NOT_CONFIGURED
+ }
+ ReasonCode::ErrorDtTagRangingRoundsNotConfigured => {
+ ProtoReasonCode::ERROR_DT_TAG_RANGING_ROUNDS_NOT_CONFIGURED
+ }
+ _ => ProtoReasonCode::ERROR_RFU_OR_VENDOR_SPECIFIC,
+ }
+ }
+}
+
+enum_mapping! {
+ ProtoUciLoggerMode => UciLoggerMode,
+ UCI_LOGGER_MODE_DISABLED => Disabled,
+ UCI_LOGGER_MODE_UNFILTERED => Unfiltered,
+ UCI_LOGGER_MODE_FILTERED => Filtered,
+}
+
+enum_mapping! {
+ ProtoRangingMeasurementType => RangingMeasurementType,
+ ONE_WAY => OneWay,
+ TWO_WAY => TwoWay,
+ DL_TDOA => DlTdoa,
+ OWR_AOA => OwrAoa,
+}
+
+enum_mapping! {
+ ProtoSessionType => SessionType,
+ FIRA_RANGING_SESSION => FiraRangingSession,
+ FIRA_DATA_TRANSFER => FiraDataTransfer,
+ CCC => Ccc,
+}
+
+enum_mapping! {
+ ProtoDeviceType => DeviceType,
+ CONTROLEE => Controlee,
+ CONTROLLER => Controller,
+}
+
+enum_mapping! {
+ ProtoRangingRoundUsage => RangingRoundUsage,
+ SS_TWR => SsTwr,
+ DS_TWR => DsTwr,
+ SS_TWR_NON => SsTwrNon,
+ DS_TWR_NON => DsTwrNon,
+}
+
+enum_mapping! {
+ ProtoStsConfig => StsConfig,
+ STATIC => Static,
+ DYNAMIC => Dynamic,
+ DYNAMIC_FOR_CONTROLEE_INDIVIDUAL_KEY => DynamicForControleeIndividualKey,
+}
+
+enum_mapping! {
+ ProtoMultiNodeMode => MultiNodeMode,
+ UNICAST => Unicast,
+ ONE_TO_MANY => OneToMany,
+ MANY_TO_MANY => ManyToMany,
+}
+
+enum_mapping! {
+ ProtoUwbChannel => UwbChannel,
+ CHANNEL_5 => Channel5,
+ CHANNEL_6 => Channel6,
+ CHANNEL_8 => Channel8,
+ CHANNEL_9 => Channel9,
+ CHANNEL_10 => Channel10,
+ CHANNEL_12 => Channel12,
+ CHANNEL_13 => Channel13,
+ CHANNEL_14 => Channel14,
+}
+
+enum_mapping! {
+ ProtoMacFcsType => MacFcsType,
+ CRC_16 => Crc16,
+ CRC_32 => Crc32,
+}
+
+enum_mapping! {
+ ProtoAoaResultRequest => AoaResultRequest,
+ NO_AOA_REPORT => NoAoaReport,
+ REQ_AOA_RESULTS => ReqAoaResults,
+ REQ_AOA_RESULTS_AZIMUTH_ONLY => ReqAoaResultsAzimuthOnly,
+ REQ_AOA_RESULTS_ELEVATION_ONLY => ReqAoaResultsElevationOnly,
+ REQ_AOA_RESULTS_INTERLEAVED => ReqAoaResultsInterleaved,
+}
+
+enum_mapping! {
+ ProtoRangeDataNtfConfig => RangeDataNtfConfig,
+ RANGE_DATA_NTF_CONFIG_DISABLE => Disable,
+ RANGE_DATA_NTF_CONFIG_ENABLE => Enable,
+ RANGE_DATA_NTF_CONFIG_ENABLE_PROXIMITY => EnableProximity,
+}
+
+enum_mapping! {
+ ProtoDeviceRole => DeviceRole,
+ RESPONDER => Responder,
+ INITIATOR => Initiator,
+}
+
+enum_mapping! {
+ ProtoRframeConfig => RframeConfig,
+ SP0 => SP0,
+ SP1 => SP1,
+ SP3 => SP3,
+}
+
+enum_mapping! {
+ ProtoPsduDataRate => PsduDataRate,
+ RATE_6M_81 => Rate6m81,
+ RATE_7M_80 => Rate7m80,
+ RATE_27M_2 => Rate27m2,
+ RATE_31M_2 => Rate31m2,
+ RATE_850K => Rate850k,
+}
+
+enum_mapping! {
+ ProtoPreambleDuration => PreambleDuration,
+ T32_SYMBOLS => T32Symbols,
+ T64_SYMBOLS => T64Symbols,
+}
+
+enum_mapping! {
+ ProtoRangingTimeStruct => RangingTimeStruct,
+ INTERVAL_BASED_SCHEDULING => IntervalBasedScheduling,
+ BLOCK_BASED_SCHEDULING => BlockBasedScheduling,
+}
+
+enum_mapping! {
+ ProtoTxAdaptivePayloadPower => TxAdaptivePayloadPower,
+ TX_ADAPTIVE_PAYLOAD_POWER_DISABLE => Disable,
+ TX_ADAPTIVE_PAYLOAD_POWER_ENABLE => Enable,
+}
+
+enum_mapping! {
+ ProtoPrfMode => PrfMode,
+ BPRF => Bprf,
+ HPRF_WITH_124_8_MHZ => HprfWith124_8MHz,
+ HPRF_WITH_249_6_MHZ => HprfWith249_6MHz,
+}
+
+enum_mapping! {
+ ProtoScheduledMode => ScheduledMode,
+ TIME_SCHEDULED_RANGING => TimeScheduledRanging,
+}
+
+enum_mapping! {
+ ProtoKeyRotation => KeyRotation,
+ KEY_ROTATION_DISABLE => Disable,
+ KEY_ROTATION_ENABLE => Enable,
+}
+
+enum_mapping! {
+ ProtoMacAddressMode => MacAddressMode,
+ MAC_ADDRESS_2_BYTES => MacAddress2Bytes,
+ MAC_ADDRESS_8_BYTES_2_BYTES_HEADER => MacAddress8Bytes2BytesHeader,
+ MAC_ADDRESS_8_BYTES => MacAddress8Bytes,
+}
+
+enum_mapping! {
+ ProtoHoppingMode => HoppingMode,
+ HOPPING_MODE_DISABLE => Disable,
+ FIRA_HOPPING_ENABLE => FiraHoppingEnable,
+}
+
+enum_mapping! {
+ ProtoBprfPhrDataRate => BprfPhrDataRate,
+ BPRF_PHR_DATA_RATE_850K => Rate850k,
+ BPRF_PHR_DATA_RATE_6M_81 => Rate6m81,
+}
+
+enum_mapping! {
+ ProtoStsLength => StsLength,
+ LENGTH_32 => Length32,
+ LENGTH_64 => Length64,
+ LENGTH_128 => Length128,
+}
+
+enum_mapping! {
+ ProtoUpdateMulticastListAction => UpdateMulticastListAction,
+ ADD_CONTROLEE => AddControlee,
+ REMOVE_CONTROLEE => RemoveControlee,
+ ADD_CONTROLEE_WITH_SHORT_SUB_SESSION_KEY => AddControleeWithShortSubSessionKey,
+ ADD_CONTROLEE_WITH_LONG_SUB_SESSION_KEY => AddControleeWithLongSubSessionKey,
+}
+
+pub enum ProtoRangingMeasurements {
+ TwoWay(Vec<ProtoTwoWayRangingMeasurement>),
+ OwrAoa(ProtoOwrAoaRangingMeasurement),
+ DlTDoa(Vec<ProtoDlTDoARangingMeasurement>),
+}
+
+impl<T> From<Result<T>> for ProtoStatus {
+ fn from(item: Result<T>) -> Self {
+ match item {
+ Ok(_) => Self::OK,
+ Err(Error::BadParameters) => Self::BAD_PARAMETERS,
+ Err(Error::MaxSessionsExceeded) => Self::MAX_SESSIONS_EXCEEDED,
+ Err(Error::MaxRrRetryReached) => Self::MAX_RR_RETRY_REACHED,
+ Err(Error::ProtocolSpecific) => Self::PROTOCOL_SPECIFIC,
+ Err(Error::RemoteRequest) => Self::REMOTE_REQUEST,
+ Err(Error::Timeout) => Self::TIMEOUT,
+ Err(Error::CommandRetry) => Self::COMMAND_RETRY,
+ Err(Error::DuplicatedSessionId) => Self::DUPLICATED_SESSION_ID,
+ Err(_) => Self::UNKNOWN,
+ }
+ }
+}
+
+impl From<ShortAddressTwoWayRangingMeasurement> for ProtoTwoWayRangingMeasurement {
+ fn from(item: ShortAddressTwoWayRangingMeasurement) -> Self {
+ let mut result = Self::new();
+ result.set_mac_address(item.mac_address.into());
+ result.set_status(item.status.into());
+ result.set_nlos(item.nlos.into());
+ result.set_distance(item.distance.into());
+ result.set_aoa_azimuth(item.aoa_azimuth.into());
+ result.set_aoa_azimuth_fom(item.aoa_azimuth_fom.into());
+ result.set_aoa_elevation(item.aoa_elevation.into());
+ result.set_aoa_elevation_fom(item.aoa_elevation_fom.into());
+ result.set_aoa_destination_azimuth(item.aoa_destination_azimuth.into());
+ result.set_aoa_destination_azimuth_fom(item.aoa_destination_azimuth_fom.into());
+ result.set_aoa_destination_elevation(item.aoa_destination_elevation.into());
+ result.set_aoa_destination_elevation_fom(item.aoa_destination_elevation_fom.into());
+ result.set_slot_index(item.slot_index.into());
+ result.set_rssi(item.rssi.into());
+ result
+ }
+}
+
+impl From<ExtendedAddressTwoWayRangingMeasurement> for ProtoTwoWayRangingMeasurement {
+ fn from(item: ExtendedAddressTwoWayRangingMeasurement) -> Self {
+ let mut result = Self::new();
+ result.set_mac_address(item.mac_address);
+ result.set_status(item.status.into());
+ result.set_nlos(item.nlos.into());
+ result.set_distance(item.distance.into());
+ result.set_aoa_azimuth(item.aoa_azimuth.into());
+ result.set_aoa_azimuth_fom(item.aoa_azimuth_fom.into());
+ result.set_aoa_elevation(item.aoa_elevation.into());
+ result.set_aoa_elevation_fom(item.aoa_elevation_fom.into());
+ result.set_aoa_destination_azimuth(item.aoa_destination_azimuth.into());
+ result.set_aoa_destination_azimuth_fom(item.aoa_destination_azimuth_fom.into());
+ result.set_aoa_destination_elevation(item.aoa_destination_elevation.into());
+ result.set_aoa_destination_elevation_fom(item.aoa_destination_elevation_fom.into());
+ result.set_slot_index(item.slot_index.into());
+ result.set_rssi(item.rssi.into());
+ result
+ }
+}
+
+impl From<ShortAddressOwrAoaRangingMeasurement> for ProtoOwrAoaRangingMeasurement {
+ fn from(item: ShortAddressOwrAoaRangingMeasurement) -> Self {
+ let mut result = Self::new();
+ result.set_mac_address(item.mac_address.into());
+ result.set_owr_aoa_status_code(item.status.into());
+ result.set_nlos(item.nlos.into());
+ result.set_block_index(item.block_index.into());
+ result.set_frame_sequence_number(item.frame_sequence_number.into());
+ result.set_aoa_azimuth(item.aoa_azimuth.into());
+ result.set_aoa_azimuth_fom(item.aoa_azimuth_fom.into());
+ result.set_aoa_elevation(item.aoa_elevation.into());
+ result.set_aoa_elevation_fom(item.aoa_elevation_fom.into());
+ result
+ }
+}
+
+impl From<ExtendedAddressOwrAoaRangingMeasurement> for ProtoOwrAoaRangingMeasurement {
+ fn from(item: ExtendedAddressOwrAoaRangingMeasurement) -> Self {
+ let mut result = Self::new();
+ result.set_mac_address(item.mac_address);
+ result.set_owr_aoa_status_code(item.status.into());
+ result.set_nlos(item.nlos.into());
+ result.set_block_index(item.block_index.into());
+ result.set_frame_sequence_number(item.frame_sequence_number.into());
+ result.set_aoa_azimuth(item.aoa_azimuth.into());
+ result.set_aoa_azimuth_fom(item.aoa_azimuth_fom.into());
+ result.set_aoa_elevation(item.aoa_elevation.into());
+ result.set_aoa_elevation_fom(item.aoa_elevation_fom.into());
+ result
+ }
+}
+
+impl From<ShortAddressDlTdoaRangingMeasurement> for ProtoDlTDoARangingMeasurement {
+ fn from(item: ShortAddressDlTdoaRangingMeasurement) -> Self {
+ let mut result = Self::new();
+ result.set_mac_address(item.mac_address.into());
+ result.set_status(
+ StatusCode::try_from(item.measurement.status)
+ .unwrap_or(StatusCode::UciStatusFailed)
+ .into(),
+ );
+ result.set_message_control(item.measurement.message_control.into());
+ result.set_block_index(item.measurement.block_index.into());
+ result.set_round_index(item.measurement.round_index.into());
+ result.set_nlos(item.measurement.nlos.into());
+ result.set_aoa_azimuth(item.measurement.aoa_azimuth.into());
+ result.set_aoa_azimuth_fom(item.measurement.aoa_azimuth_fom.into());
+ result.set_aoa_elevation(item.measurement.aoa_elevation.into());
+ result.set_aoa_elevation_fom(item.measurement.aoa_elevation_fom.into());
+ result.set_rssi(item.measurement.rssi.into());
+ result.set_tx_timestamp(item.measurement.tx_timestamp);
+ result.set_rx_timestamp(item.measurement.rx_timestamp);
+ result.set_anchor_cfo(item.measurement.anchor_cfo.into());
+ result.set_cfo(item.measurement.cfo.into());
+ result.set_initiator_reply_time(item.measurement.initiator_reply_time);
+ result.set_responder_reply_time(item.measurement.responder_reply_time);
+ result.set_initiator_responder_tof(item.measurement.initiator_responder_tof.into());
+ result.set_dt_anchor_location(
+ item.measurement
+ .dt_anchor_location
+ .into_iter()
+ .map(|val| val as u32)
+ .collect::<Vec<u32>>(),
+ );
+ result.set_ranging_rounds(
+ item.measurement.ranging_rounds.into_iter().map(|val| val as u32).collect::<Vec<u32>>(),
+ );
+ result
+ }
+}
+
+impl From<ExtendedAddressDlTdoaRangingMeasurement> for ProtoDlTDoARangingMeasurement {
+ fn from(item: ExtendedAddressDlTdoaRangingMeasurement) -> Self {
+ let mut result = Self::new();
+ result.set_mac_address(item.mac_address);
+ result.set_status(
+ StatusCode::try_from(item.measurement.status)
+ .unwrap_or(StatusCode::UciStatusFailed)
+ .into(),
+ );
+ result.set_message_control(item.measurement.message_control.into());
+ result.set_block_index(item.measurement.block_index.into());
+ result.set_round_index(item.measurement.round_index.into());
+ result.set_nlos(item.measurement.nlos.into());
+ result.set_aoa_azimuth(item.measurement.aoa_azimuth.into());
+ result.set_aoa_azimuth_fom(item.measurement.aoa_azimuth_fom.into());
+ result.set_aoa_elevation(item.measurement.aoa_elevation.into());
+ result.set_aoa_elevation_fom(item.measurement.aoa_elevation_fom.into());
+ result.set_rssi(item.measurement.rssi.into());
+ result.set_tx_timestamp(item.measurement.tx_timestamp);
+ result.set_rx_timestamp(item.measurement.rx_timestamp);
+ result.set_anchor_cfo(item.measurement.anchor_cfo.into());
+ result.set_cfo(item.measurement.cfo.into());
+ result.set_initiator_reply_time(item.measurement.initiator_reply_time);
+ result.set_responder_reply_time(item.measurement.responder_reply_time);
+ result.set_initiator_responder_tof(item.measurement.initiator_responder_tof.into());
+ result.set_dt_anchor_location(
+ item.measurement
+ .dt_anchor_location
+ .into_iter()
+ .map(|val| val as u32)
+ .collect::<Vec<u32>>(),
+ );
+ result.set_ranging_rounds(
+ item.measurement.ranging_rounds.into_iter().map(|val| val as u32).collect::<Vec<u32>>(),
+ );
+ result
+ }
+}
+
+impl From<SessionRangeData> for ProtoSessionRangeData {
+ fn from(item: SessionRangeData) -> Self {
+ let mut result = Self::new();
+ result.set_sequence_number(item.sequence_number);
+ result.set_session_id(item.session_id);
+ result.set_current_ranging_interval_ms(item.current_ranging_interval_ms);
+ result.set_ranging_measurement_type(item.ranging_measurement_type.into());
+ match to_proto_ranging_measurements(item.ranging_measurements) {
+ ProtoRangingMeasurements::TwoWay(twoway_measurements) => {
+ result.set_twoway_ranging_measurements(RepeatedField::from_vec(twoway_measurements))
+ }
+ ProtoRangingMeasurements::OwrAoa(owraoa_measurement) => {
+ result.set_owraoa_ranging_measurement(owraoa_measurement)
+ }
+ ProtoRangingMeasurements::DlTDoa(dltdoa_measurements) => {
+ result.set_dltdoa_ranging_measurements(RepeatedField::from_vec(dltdoa_measurements))
+ }
+ }
+ result
+ }
+}
+
+fn to_proto_ranging_measurements(item: RangingMeasurements) -> ProtoRangingMeasurements {
+ match item {
+ RangingMeasurements::ShortAddressTwoWay(arr) => {
+ ProtoRangingMeasurements::TwoWay(arr.into_iter().map(|item| item.into()).collect())
+ }
+ RangingMeasurements::ExtendedAddressTwoWay(arr) => {
+ ProtoRangingMeasurements::TwoWay(arr.into_iter().map(|item| item.into()).collect())
+ }
+ RangingMeasurements::ShortAddressOwrAoa(r) => ProtoRangingMeasurements::OwrAoa(r.into()),
+ RangingMeasurements::ExtendedAddressOwrAoa(r) => ProtoRangingMeasurements::OwrAoa(r.into()),
+ RangingMeasurements::ShortAddressDltdoa(arr) => {
+ ProtoRangingMeasurements::DlTDoa(arr.into_iter().map(|item| item.into()).collect())
+ }
+ RangingMeasurements::ExtendedAddressDltdoa(arr) => {
+ ProtoRangingMeasurements::DlTDoa(arr.into_iter().map(|item| item.into()).collect())
+ }
+ }
+}
+
+impl From<ProtoRangingRoundControl> for RangingRoundControl {
+ fn from(item: ProtoRangingRoundControl) -> Self {
+ Self {
+ ranging_result_report_message: item.ranging_result_report_message,
+ control_message: item.control_message,
+ measurement_report_message: item.measurement_report_message,
+ }
+ }
+}
+
+impl From<RangingRoundControl> for ProtoRangingRoundControl {
+ fn from(item: RangingRoundControl) -> Self {
+ let mut res = Self::new();
+ res.set_ranging_result_report_message(item.ranging_result_report_message);
+ res.set_control_message(item.control_message);
+ res.set_measurement_report_message(item.measurement_report_message);
+ res
+ }
+}
+
+impl From<ProtoResultReportConfig> for ResultReportConfig {
+ fn from(item: ProtoResultReportConfig) -> Self {
+ Self {
+ tof: item.tof,
+ aoa_azimuth: item.aoa_azimuth,
+ aoa_elevation: item.aoa_elevation,
+ aoa_fom: item.aoa_fom,
+ }
+ }
+}
+
+impl From<ResultReportConfig> for ProtoResultReportConfig {
+ fn from(item: ResultReportConfig) -> Self {
+ let mut res = Self::new();
+ res.set_tof(item.tof);
+ res.set_aoa_azimuth(item.aoa_azimuth);
+ res.set_aoa_elevation(item.aoa_elevation);
+ res.set_aoa_fom(item.aoa_fom);
+ res
+ }
+}
+
+fn to_uwb_address(bytes: Vec<u8>, mode: ProtoMacAddressMode) -> Option<UwbAddress> {
+ match mode {
+ ProtoMacAddressMode::MAC_ADDRESS_2_BYTES
+ | ProtoMacAddressMode::MAC_ADDRESS_8_BYTES_2_BYTES_HEADER => {
+ Some(UwbAddress::Short(bytes.try_into().ok()?))
+ }
+ ProtoMacAddressMode::MAC_ADDRESS_8_BYTES => {
+ Some(UwbAddress::Extended(bytes.try_into().ok()?))
+ }
+ }
+}
+
+impl TryFrom<ProtoControlee> for Controlee {
+ type Error = String;
+ fn try_from(item: ProtoControlee) -> std::result::Result<Self, Self::Error> {
+ Ok(Self {
+ short_address: item
+ .short_address
+ .try_into()
+ .map_err(|_| "Failed to convert short_address")?,
+ subsession_id: item.subsession_id,
+ })
+ }
+}
+
+impl From<PowerStats> for ProtoPowerStats {
+ fn from(item: PowerStats) -> Self {
+ let mut res = Self::new();
+ res.set_status(item.status.into());
+ res.set_idle_time_ms(item.idle_time_ms);
+ res.set_tx_time_ms(item.tx_time_ms);
+ res.set_rx_time_ms(item.rx_time_ms);
+ res.set_total_wake_count(item.total_wake_count);
+ res
+ }
+}
+
+impl From<FiraAppConfigParams> for ProtoFiraAppConfigParams {
+ fn from(item: FiraAppConfigParams) -> Self {
+ let mut res = Self::new();
+ res.set_device_type((*item.device_type()).into());
+ res.set_ranging_round_usage((*item.ranging_round_usage()).into());
+ res.set_sts_config((*item.sts_config()).into());
+ res.set_multi_node_mode((*item.multi_node_mode()).into());
+ res.set_channel_number((*item.channel_number()).into());
+ res.set_device_mac_address(item.device_mac_address().clone().into());
+ res.set_dst_mac_address(
+ item.dst_mac_address()
+ .clone()
+ .into_iter()
+ .map(|addr| addr.into())
+ .collect::<Vec<_>>()
+ .into(),
+ );
+ res.set_slot_duration_rstu((*item.slot_duration_rstu()).into());
+ res.set_ranging_interval_ms(*item.ranging_interval_ms());
+ res.set_mac_fcs_type((*item.mac_fcs_type()).into());
+ res.set_ranging_round_control(item.ranging_round_control().clone().into());
+ res.set_aoa_result_request((*item.aoa_result_request()).into());
+ res.set_range_data_ntf_config((*item.range_data_ntf_config()).into());
+ res.set_range_data_ntf_proximity_near_cm((*item.range_data_ntf_proximity_near_cm()).into());
+ res.set_range_data_ntf_proximity_far_cm((*item.range_data_ntf_proximity_far_cm()).into());
+ res.set_device_role((*item.device_role()).into());
+ res.set_rframe_config((*item.rframe_config()).into());
+ res.set_preamble_code_index((*item.preamble_code_index()).into());
+ res.set_sfd_id((*item.sfd_id()).into());
+ res.set_psdu_data_rate((*item.psdu_data_rate()).into());
+ res.set_preamble_duration((*item.preamble_duration()).into());
+ res.set_ranging_time_struct((*item.ranging_time_struct()).into());
+ res.set_slots_per_rr((*item.slots_per_rr()).into());
+ res.set_tx_adaptive_payload_power((*item.tx_adaptive_payload_power()).into());
+ res.set_responder_slot_index((*item.responder_slot_index()).into());
+ res.set_prf_mode((*item.prf_mode()).into());
+ res.set_scheduled_mode((*item.scheduled_mode()).into());
+ res.set_key_rotation((*item.key_rotation()).into());
+ res.set_key_rotation_rate((*item.key_rotation_rate()).into());
+ res.set_session_priority((*item.session_priority()).into());
+ res.set_mac_address_mode((*item.mac_address_mode()).into());
+ res.set_vendor_id((*item.vendor_id()).into());
+ res.set_static_sts_iv((*item.static_sts_iv()).into());
+ res.set_number_of_sts_segments((*item.number_of_sts_segments()).into());
+ res.set_max_rr_retry((*item.max_rr_retry()).into());
+ res.set_uwb_initiation_time_ms(*item.uwb_initiation_time_ms());
+ res.set_hopping_mode((*item.hopping_mode()).into());
+ res.set_block_stride_length((*item.block_stride_length()).into());
+ res.set_result_report_config(item.result_report_config().clone().into());
+ res.set_in_band_termination_attempt_count(
+ (*item.in_band_termination_attempt_count()).into(),
+ );
+ res.set_sub_session_id(*item.sub_session_id());
+ res.set_bprf_phr_data_rate((*item.bprf_phr_data_rate()).into());
+ res.set_max_number_of_measurements((*item.max_number_of_measurements()).into());
+ res.set_sts_length((*item.sts_length()).into());
+ res.set_number_of_range_measurements((*item.number_of_range_measurements()).into());
+ res.set_number_of_aoa_azimuth_measurements(
+ (*item.number_of_aoa_azimuth_measurements()).into(),
+ );
+ res.set_number_of_aoa_elevation_measurements(
+ (*item.number_of_aoa_elevation_measurements()).into(),
+ );
+
+ res
+ }
+}
+
+impl TryFrom<ProtoFiraAppConfigParams> for AppConfigParams {
+ type Error = String;
+ fn try_from(mut item: ProtoFiraAppConfigParams) -> std::result::Result<Self, Self::Error> {
+ let device_mac_address =
+ to_uwb_address(item.device_mac_address.clone(), item.mac_address_mode)
+ .ok_or("Failed to convert device_mac_address")?;
+ let mut dst_mac_address = vec![];
+ for addr in item.dst_mac_address.clone().into_iter() {
+ let addr = to_uwb_address(addr, item.mac_address_mode)
+ .ok_or("Failed to convert dst_mac_address")?;
+ dst_mac_address.push(addr);
+ }
+
+ let mut builder = FiraAppConfigParamsBuilder::new();
+ builder
+ .device_type(item.device_type.into())
+ .ranging_round_usage(item.ranging_round_usage.into())
+ .sts_config(item.sts_config.into())
+ .multi_node_mode(item.multi_node_mode.into())
+ .channel_number(item.channel_number.into())
+ .device_mac_address(device_mac_address)
+ .dst_mac_address(dst_mac_address)
+ .slot_duration_rstu(
+ item.slot_duration_rstu
+ .try_into()
+ .map_err(|_| "Failed to convert slot_duration_rstu")?,
+ )
+ .ranging_interval_ms(item.ranging_interval_ms)
+ .mac_fcs_type(item.mac_fcs_type.into())
+ .ranging_round_control(
+ item.ranging_round_control.take().ok_or("ranging_round_control is empty")?.into(),
+ )
+ .aoa_result_request(item.aoa_result_request.into())
+ .range_data_ntf_config(item.range_data_ntf_config.into())
+ .range_data_ntf_proximity_near_cm(
+ item.range_data_ntf_proximity_near_cm
+ .try_into()
+ .map_err(|_| "Failed to convert range_data_ntf_proximity_near_cm")?,
+ )
+ .range_data_ntf_proximity_far_cm(
+ item.range_data_ntf_proximity_far_cm
+ .try_into()
+ .map_err(|_| "Failed to convert range_data_ntf_proximity_far_cm")?,
+ )
+ .device_role(item.device_role.into())
+ .rframe_config(item.rframe_config.into())
+ .preamble_code_index(
+ item.preamble_code_index
+ .try_into()
+ .map_err(|_| "Failed to convert preamble_code_index")?,
+ )
+ .sfd_id(item.sfd_id.try_into().map_err(|_| "Failed to convert sfd_id")?)
+ .psdu_data_rate(item.psdu_data_rate.into())
+ .preamble_duration(item.preamble_duration.into())
+ .ranging_time_struct(item.ranging_time_struct.into())
+ .slots_per_rr(
+ item.slots_per_rr.try_into().map_err(|_| "Failed to convert slots_per_rr")?,
+ )
+ .tx_adaptive_payload_power(item.tx_adaptive_payload_power.into())
+ .responder_slot_index(
+ item.responder_slot_index
+ .try_into()
+ .map_err(|_| "Failed to convert responder_slot_index")?,
+ )
+ .prf_mode(item.prf_mode.into())
+ .scheduled_mode(item.scheduled_mode.into())
+ .key_rotation(item.key_rotation.into())
+ .key_rotation_rate(
+ item.key_rotation_rate
+ .try_into()
+ .map_err(|_| "Failed to convert key_rotation_rate")?,
+ )
+ .session_priority(
+ item.session_priority
+ .try_into()
+ .map_err(|_| "Failed to convert session_priority")?,
+ )
+ .mac_address_mode(item.mac_address_mode.into())
+ .vendor_id(
+ item.vendor_id.clone().try_into().map_err(|_| "Failed to convert vendor_id")?,
+ )
+ .static_sts_iv(
+ item.static_sts_iv
+ .clone()
+ .try_into()
+ .map_err(|_| "Failed to convert static_sts_iv")?,
+ )
+ .number_of_sts_segments(
+ item.number_of_sts_segments
+ .try_into()
+ .map_err(|_| "Failed to convert number_of_sts_segments")?,
+ )
+ .max_rr_retry(
+ item.max_rr_retry.try_into().map_err(|_| "Failed to convert max_rr_retry")?,
+ )
+ .uwb_initiation_time_ms(item.uwb_initiation_time_ms)
+ .hopping_mode(item.hopping_mode.into())
+ .block_stride_length(
+ item.block_stride_length
+ .try_into()
+ .map_err(|_| "Failed to convert block_stride_length")?,
+ )
+ .result_report_config(
+ item.result_report_config.take().ok_or("ranging_round_control is empty")?.into(),
+ )
+ .in_band_termination_attempt_count(
+ item.in_band_termination_attempt_count
+ .try_into()
+ .map_err(|_| "Failed to convert in_band_termination_attempt_count")?,
+ )
+ .sub_session_id(item.sub_session_id)
+ .bprf_phr_data_rate(item.bprf_phr_data_rate.into())
+ .max_number_of_measurements(
+ item.max_number_of_measurements
+ .try_into()
+ .map_err(|_| "Failed to convert max_number_of_measurements")?,
+ )
+ .sts_length(item.sts_length.into())
+ .number_of_range_measurements(
+ item.number_of_range_measurements
+ .try_into()
+ .map_err(|_| "Failed to convert number_of_range_measurements")?,
+ )
+ .number_of_aoa_azimuth_measurements(
+ item.number_of_aoa_azimuth_measurements
+ .try_into()
+ .map_err(|_| "Failed to convert number_of_aoa_azimuth_measurements")?,
+ )
+ .number_of_aoa_elevation_measurements(
+ item.number_of_aoa_elevation_measurements
+ .try_into()
+ .map_err(|_| "Failed to convert number_of_aoa_elevation_measurements")?,
+ );
+
+ Ok(builder.build().ok_or("Failed to build FiraAppConfigParam from builder")?)
+ }
+}
+
+impl Drop for ProtoFiraAppConfigParams {
+ fn drop(&mut self) {
+ // Zero out the sensitive data before releasing memory.
+ self.vendor_id.zeroize();
+ self.static_sts_iv.zeroize();
+ self.sub_session_id.zeroize();
+ }
+}
diff --git a/src/rust/uwb_core/src/proto/utils.rs b/src/rust/uwb_core/src/proto/utils.rs
new file mode 100644
index 0000000..8f73e20
--- /dev/null
+++ b/src/rust/uwb_core/src/proto/utils.rs
@@ -0,0 +1,36 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Provide the conversion between the elements of uwb_core and protobuf.
+
+use log::error;
+use protobuf::Message;
+
+use crate::error::{Error, Result};
+
+/// Convert the protobuf message to a byte buffers. Return dbus::MethodErr when conversion fails.
+pub fn write_to_bytes<M: Message>(msg: &M) -> Result<Vec<u8>> {
+ msg.write_to_bytes().map_err(|e| {
+ error!("Failed to write protobuf {} to bytes: {:?}", msg.descriptor().name(), e);
+ Error::Unknown
+ })
+}
+
+/// Parse the byte buffer to the protobuf message. Return dbus::MethodErr when failed to parse.
+pub fn parse_from_bytes<M: Message>(bytes: &[u8]) -> Result<M> {
+ M::parse_from_bytes(bytes).map_err(|e| {
+ error!("Failed to parse {:?}: {:?}", M::descriptor_static().name(), e);
+ Error::BadParameters
+ })
+}
diff --git a/src/rust/uwb_core/src/service.rs b/src/rust/uwb_core/src/service.rs
index 2371bfe..979cad2 100644
--- a/src/rust/uwb_core/src/service.rs
+++ b/src/rust/uwb_core/src/service.rs
@@ -14,6 +14,8 @@
//! This module provides the public interface of the UWB core library.
+#[cfg(feature = "proto")]
+pub mod proto_uwb_service;
pub mod uwb_service;
pub mod uwb_service_builder;
pub mod uwb_service_callback_builder;
@@ -22,6 +24,10 @@ pub mod uwb_service_callback_builder;
mod mock_uwb_service_callback;
// Re-export the public elements.
-pub use uwb_service::{UwbService, UwbServiceCallback, UwbServiceCallbackBuilder};
+#[cfg(feature = "proto")]
+pub use proto_uwb_service::{ProtoUwbService, ProtoUwbServiceCallback};
+pub use uwb_service::{
+ NopUwbServiceCallback, UwbService, UwbServiceCallback, UwbServiceCallbackBuilder,
+};
pub use uwb_service_builder::{default_runtime, UwbServiceBuilder};
pub use uwb_service_callback_builder::UwbServiceCallbackSendBuilder;
diff --git a/src/rust/uwb_core/src/service/proto_uwb_service.rs b/src/rust/uwb_core/src/service/proto_uwb_service.rs
new file mode 100644
index 0000000..747865a
--- /dev/null
+++ b/src/rust/uwb_core/src/service/proto_uwb_service.rs
@@ -0,0 +1,325 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! This module provides a thin adapter of UwbService and UwbServiceCallback that encodes the
+//! arguments to protobuf.
+
+use log::{debug, error};
+
+use crate::error::{Error, Result};
+use crate::params::{AppConfigParams, DeviceState, ReasonCode, SessionId, SessionState};
+use crate::proto::bindings::{
+ AndroidGetPowerStatsResponse, AndroidSetCountryCodeRequest, AndroidSetCountryCodeResponse,
+ DeinitSessionRequest, DeinitSessionResponse, DisableResponse, EnableResponse,
+ InitSessionRequest, InitSessionResponse, RangeDataReceivedSignal, ReconfigureRequest,
+ ReconfigureResponse, SendVendorCmdRequest, SendVendorCmdResponse, ServiceResetSignal,
+ SessionParamsRequest, SessionParamsResponse, SessionStateChangedSignal, SetLoggerModeRequest,
+ SetLoggerModeResponse, StartRangingRequest, StartRangingResponse, Status as ProtoStatus,
+ StopRangingRequest, StopRangingResponse, UciDeviceStatusChangedSignal,
+ UpdateControllerMulticastListRequest, UpdateControllerMulticastListResponse,
+ VendorNotificationReceivedSignal,
+};
+use crate::proto::utils::{parse_from_bytes, write_to_bytes};
+use crate::service::uwb_service::{UwbService, UwbServiceCallback};
+use crate::uci::notification::SessionRangeData;
+
+/// A thin adapter of UwbService. The argument and the response of each method are protobuf-encoded
+/// buffer. The definition of the protobuf is at protos/uwb_core_protos.proto.
+///
+/// For the naming of the protobuf struct, the argument of a method `do_something()` will be called
+/// `DoSomethingRequest`, and the result will be called `DoSomethingResponse`.
+pub struct ProtoUwbService {
+ service: UwbService,
+}
+
+impl ProtoUwbService {
+ /// Create a ProtoUwbService.
+ pub fn new(service: UwbService) -> Self {
+ Self { service }
+ }
+
+ /// Set UCI log mode.
+ pub fn set_logger_mode(&self, request: &[u8]) -> Result<Vec<u8>> {
+ let request = parse_from_bytes::<SetLoggerModeRequest>(request)?;
+ let mut resp = SetLoggerModeResponse::new();
+ resp.set_status(self.service.set_logger_mode(request.logger_mode.into()).into());
+ write_to_bytes(&resp)
+ }
+
+ /// Enable the UWB service.
+ pub fn enable(&self) -> Result<Vec<u8>> {
+ let mut resp = EnableResponse::new();
+ resp.set_status(self.service.enable().into());
+ write_to_bytes(&resp)
+ }
+
+ /// Disable the UWB service.
+ pub fn disable(&self) -> Result<Vec<u8>> {
+ let mut resp = DisableResponse::new();
+ resp.set_status(self.service.disable().into());
+ write_to_bytes(&resp)
+ }
+
+ /// Initialize a new ranging session with the given parameters.
+ ///
+ /// Note: Currently the protobuf only support Fira parameters, but not support CCC parameters.
+ pub fn init_session(&self, request: &[u8]) -> Result<Vec<u8>> {
+ let mut request = parse_from_bytes::<InitSessionRequest>(request)?;
+ let params = request
+ .params
+ .take()
+ .ok_or_else(|| {
+ error!("InitSessionRequest.params is empty");
+ Error::BadParameters
+ })?
+ .try_into()
+ .map_err(|e| {
+ error!("Failed to convert to AppConfigParams: {}", e);
+ Error::BadParameters
+ })?;
+
+ let mut resp = InitSessionResponse::new();
+ resp.set_status(
+ self.service
+ .init_session(request.session_id, request.session_type.into(), params)
+ .into(),
+ );
+ write_to_bytes(&resp)
+ }
+
+ /// Destroy the session.
+ pub fn deinit_session(&self, request: &[u8]) -> Result<Vec<u8>> {
+ let request = parse_from_bytes::<DeinitSessionRequest>(request)?;
+ let mut resp = DeinitSessionResponse::new();
+ resp.set_status(self.service.deinit_session(request.session_id).into());
+ write_to_bytes(&resp)
+ }
+
+ /// Start ranging of the session.
+ pub fn start_ranging(&self, request: &[u8]) -> Result<Vec<u8>> {
+ let request = parse_from_bytes::<StartRangingRequest>(request)?;
+ // Currently we only support FiRa session, not CCC. For FiRa session, the returned
+ // AppConfigParams is the same as the configured one before start_ranging(). Therefore, we
+ // don't reply the AppConfigParams received from uwb_core.
+ let mut resp = StartRangingResponse::new();
+ resp.set_status(self.service.start_ranging(request.session_id).into());
+ write_to_bytes(&resp)
+ }
+
+ /// Stop ranging.
+ pub fn stop_ranging(&self, request: &[u8]) -> Result<Vec<u8>> {
+ let request = parse_from_bytes::<StopRangingRequest>(request)?;
+ let mut resp = StopRangingResponse::new();
+ resp.set_status(self.service.stop_ranging(request.session_id).into());
+ write_to_bytes(&resp)
+ }
+
+ /// Reconfigure the parameters of the session.
+ pub fn reconfigure(&self, request: &[u8]) -> Result<Vec<u8>> {
+ let mut request = parse_from_bytes::<ReconfigureRequest>(request)?;
+ let params = request
+ .params
+ .take()
+ .ok_or_else(|| {
+ error!("ReconfigureRequest.params is empty");
+ Error::BadParameters
+ })?
+ .try_into()
+ .map_err(|e| {
+ error!("Failed to convert to AppConfigParams: {}", e);
+ Error::BadParameters
+ })?;
+
+ let mut resp = ReconfigureResponse::new();
+ resp.set_status(self.service.reconfigure(request.session_id, params).into());
+ write_to_bytes(&resp)
+ }
+
+ /// Update the list of the controlees to the ongoing session.
+ pub fn update_controller_multicast_list(&self, request: &[u8]) -> Result<Vec<u8>> {
+ let request = parse_from_bytes::<UpdateControllerMulticastListRequest>(request)?;
+ let mut controlees = vec![];
+ for controlee in request.controlees.into_iter() {
+ let controlee = controlee.try_into().map_err(|e| {
+ error!("Failed to convert Controlee: {:?}", e);
+ Error::BadParameters
+ })?;
+ controlees.push(controlee);
+ }
+
+ let mut resp = UpdateControllerMulticastListResponse::new();
+ resp.set_status(
+ self.service
+ .update_controller_multicast_list(
+ request.session_id,
+ request.action.into(),
+ controlees,
+ )
+ .into(),
+ );
+ write_to_bytes(&resp)
+ }
+
+ /// Set the country code. Android-specific method.
+ pub fn android_set_country_code(&self, request: &[u8]) -> Result<Vec<u8>> {
+ let request = parse_from_bytes::<AndroidSetCountryCodeRequest>(request)?;
+ let country_code = request.country_code.try_into()?;
+
+ let mut resp = AndroidSetCountryCodeResponse::new();
+ resp.set_status(self.service.android_set_country_code(country_code).into());
+ write_to_bytes(&resp)
+ }
+
+ /// Get the power statistics. Android-specific method.
+ pub fn android_get_power_stats(&self) -> Result<Vec<u8>> {
+ let mut resp = AndroidGetPowerStatsResponse::new();
+ match self.service.android_get_power_stats() {
+ Ok(power_stats) => {
+ resp.set_status(Ok(()).into());
+ resp.set_power_stats(power_stats.into());
+ }
+ Err(e) => {
+ resp.set_status(From::<Result<()>>::from(Err(e)));
+ }
+ }
+ write_to_bytes(&resp)
+ }
+
+ /// Send a raw UCI message.
+ pub fn raw_uci_cmd(&self, request: &[u8]) -> Result<Vec<u8>> {
+ let request = parse_from_bytes::<SendVendorCmdRequest>(request)?;
+ let mut resp = SendVendorCmdResponse::new();
+ match self.service.raw_uci_cmd(request.mt, request.gid, request.oid, request.payload) {
+ Ok(msg) => {
+ resp.set_status(Ok(()).into());
+ resp.set_gid(msg.gid);
+ resp.set_oid(msg.oid);
+ resp.set_payload(msg.payload);
+ }
+ Err(e) => {
+ resp.set_status(From::<Result<()>>::from(Err(e)));
+ }
+ }
+ write_to_bytes(&resp)
+ }
+
+ /// Get app config params for the given session id
+ pub fn session_params(&self, request: &[u8]) -> Result<Vec<u8>> {
+ let request = parse_from_bytes::<SessionParamsRequest>(request)?;
+ let mut resp = SessionParamsResponse::new();
+ match self.service.session_params(request.session_id) {
+ Ok(AppConfigParams::Fira(params)) => {
+ resp.set_status(Ok(()).into());
+ resp.set_params(params.into());
+ }
+ Ok(params) => {
+ error!("Received non-Fira session parameters: {:?}", params);
+ resp.set_status(ProtoStatus::UNKNOWN);
+ }
+ Err(e) => {
+ resp.set_status(From::<Result<()>>::from(Err(e)));
+ }
+ }
+ write_to_bytes(&resp)
+ }
+}
+
+/// The trait that provides the same callbacks of UwbServiceCallback. It has the blanket
+/// implementation of UwbServiceCallback trait that converts the arguments to one protobuf-encoded
+/// payload.
+///
+/// For the naming of the protobuf struct, the payload of a callback `on_something_happened()`
+/// will be called `SomethingHappenedSignal`.
+pub trait ProtoUwbServiceCallback: 'static {
+ /// Notify the UWB service has been reset due to internal error. All the sessions are closed.
+ fn on_service_reset(&mut self, payload: Vec<u8>);
+ /// Notify the status of the UCI device.
+ fn on_uci_device_status_changed(&mut self, payload: Vec<u8>);
+ /// Notify the state of the session is changed.
+ fn on_session_state_changed(&mut self, payload: Vec<u8>);
+ /// Notify the ranging data of the session is received.
+ fn on_range_data_received(&mut self, payload: Vec<u8>);
+ /// Notify the vendor notification is received.
+ fn on_vendor_notification_received(&mut self, payload: Vec<u8>);
+}
+
+impl<C: ProtoUwbServiceCallback> UwbServiceCallback for C {
+ fn on_service_reset(&mut self, success: bool) {
+ debug!("UwbService is reset, success: {}", success);
+ let mut msg = ServiceResetSignal::new();
+ msg.set_success(success);
+ if let Ok(payload) = write_to_bytes(&msg) {
+ ProtoUwbServiceCallback::on_service_reset(self, payload);
+ } else {
+ error!("Failed to call on_service_reset()");
+ }
+ }
+
+ fn on_uci_device_status_changed(&mut self, state: DeviceState) {
+ debug!("UCI device status is changed: {:?}", state);
+ let mut msg = UciDeviceStatusChangedSignal::new();
+ msg.set_state(state.into());
+ if let Ok(payload) = write_to_bytes(&msg) {
+ ProtoUwbServiceCallback::on_uci_device_status_changed(self, payload);
+ } else {
+ error!("Failed to call on_uci_device_status_changed()");
+ }
+ }
+
+ fn on_session_state_changed(
+ &mut self,
+ session_id: SessionId,
+ session_state: SessionState,
+ reason_code: ReasonCode,
+ ) {
+ debug!(
+ "Session {:?}'s state is changed to {:?}, reason: {:?}",
+ session_id, session_state, reason_code
+ );
+ let mut msg = SessionStateChangedSignal::new();
+ msg.set_session_id(session_id);
+ msg.set_session_state(session_state.into());
+ msg.set_reason_code(reason_code.into());
+ if let Ok(payload) = write_to_bytes(&msg) {
+ ProtoUwbServiceCallback::on_session_state_changed(self, payload);
+ } else {
+ error!("Failed to call on_session_state_changed()");
+ }
+ }
+
+ fn on_range_data_received(&mut self, session_id: SessionId, range_data: SessionRangeData) {
+ debug!("Received range data {:?} from Session {:?}", range_data, session_id);
+ let mut msg = RangeDataReceivedSignal::new();
+ msg.set_session_id(session_id);
+ msg.set_range_data(range_data.into());
+ if let Ok(payload) = write_to_bytes(&msg) {
+ ProtoUwbServiceCallback::on_range_data_received(self, payload);
+ } else {
+ error!("Failed to call on_range_data_received()");
+ }
+ }
+
+ fn on_vendor_notification_received(&mut self, gid: u32, oid: u32, payload: Vec<u8>) {
+ debug!("Received vendor notification: gid={}, oid={}, payload={:?}", gid, oid, payload);
+ let mut msg = VendorNotificationReceivedSignal::new();
+ msg.set_gid(gid);
+ msg.set_oid(oid);
+ msg.set_payload(payload);
+ if let Ok(payload) = write_to_bytes(&msg) {
+ ProtoUwbServiceCallback::on_vendor_notification_received(self, payload);
+ } else {
+ error!("Failed to call on_vendor_notification_received()");
+ }
+ }
+}
diff --git a/src/rust/uwb_core/src/service/uwb_service.rs b/src/rust/uwb_core/src/service/uwb_service.rs
index 46c17f6..a2ecb85 100644
--- a/src/rust/uwb_core/src/service/uwb_service.rs
+++ b/src/rust/uwb_core/src/service/uwb_service.rs
@@ -22,7 +22,7 @@ use tokio::task;
use crate::error::{Error, Result};
use crate::params::app_config_params::AppConfigParams;
use crate::params::uci_packets::{
- Controlee, CountryCode, DeviceState, PowerStats, RawVendorMessage, ReasonCode, SessionId,
+ Controlee, CountryCode, DeviceState, PowerStats, RawUciMessage, ReasonCode, SessionId,
SessionState, SessionType, UpdateMulticastListAction,
};
use crate::session::session_manager::{SessionManager, SessionNotification};
@@ -59,6 +59,24 @@ pub trait UwbServiceCallback: 'static {
/// Notify the vendor notification is received.
fn on_vendor_notification_received(&mut self, gid: u32, oid: u32, payload: Vec<u8>);
+
+ // TODO(b/270443790): In the future, add a callback here to notify the Data Rx packet.
+}
+
+/// A placeholder implementation for UwbServiceCallback that does nothing.
+pub struct NopUwbServiceCallback {}
+impl UwbServiceCallback for NopUwbServiceCallback {
+ fn on_service_reset(&mut self, _success: bool) {}
+ fn on_uci_device_status_changed(&mut self, _state: DeviceState) {}
+ fn on_session_state_changed(
+ &mut self,
+ _session_id: SessionId,
+ _session_state: SessionState,
+ _reason_code: ReasonCode,
+ ) {
+ }
+ fn on_range_data_received(&mut self, _session_id: SessionId, _range_data: SessionRangeData) {}
+ fn on_vendor_notification_received(&mut self, _gid: u32, _oid: u32, _payload: Vec<u8>) {}
}
/// The entry class (a.k.a top shim) of the core library. The class accepts requests from the
@@ -127,26 +145,26 @@ impl UwbService {
}
/// Set UCI log mode.
- pub fn set_logger_mode(&mut self, logger_mode: UciLoggerMode) -> Result<()> {
+ pub fn set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()> {
self.block_on_cmd(Command::SetLoggerMode { logger_mode })?;
Ok(())
}
/// Enable the UWB service.
- pub fn enable(&mut self) -> Result<()> {
+ pub fn enable(&self) -> Result<()> {
self.block_on_cmd(Command::Enable)?;
Ok(())
}
/// Disable the UWB service.
- pub fn disable(&mut self) -> Result<()> {
+ pub fn disable(&self) -> Result<()> {
self.block_on_cmd(Command::Disable)?;
Ok(())
}
/// Initialize a new ranging session with the given parameters.
pub fn init_session(
- &mut self,
+ &self,
session_id: SessionId,
session_type: SessionType,
params: AppConfigParams,
@@ -156,13 +174,13 @@ impl UwbService {
}
/// Destroy the session.
- pub fn deinit_session(&mut self, session_id: SessionId) -> Result<()> {
+ pub fn deinit_session(&self, session_id: SessionId) -> Result<()> {
self.block_on_cmd(Command::DeinitSession { session_id })?;
Ok(())
}
/// Start ranging of the session.
- pub fn start_ranging(&mut self, session_id: SessionId) -> Result<AppConfigParams> {
+ pub fn start_ranging(&self, session_id: SessionId) -> Result<AppConfigParams> {
match self.block_on_cmd(Command::StartRanging { session_id })? {
Response::AppConfigParams(params) => Ok(params),
_ => panic!("start_ranging() should return AppConfigParams"),
@@ -170,20 +188,20 @@ impl UwbService {
}
/// Stop ranging.
- pub fn stop_ranging(&mut self, session_id: SessionId) -> Result<()> {
+ pub fn stop_ranging(&self, session_id: SessionId) -> Result<()> {
self.block_on_cmd(Command::StopRanging { session_id })?;
Ok(())
}
/// Reconfigure the parameters of the session.
- pub fn reconfigure(&mut self, session_id: SessionId, params: AppConfigParams) -> Result<()> {
+ pub fn reconfigure(&self, session_id: SessionId, params: AppConfigParams) -> Result<()> {
self.block_on_cmd(Command::Reconfigure { session_id, params })?;
Ok(())
}
/// Update the list of the controlees to the ongoing session.
pub fn update_controller_multicast_list(
- &mut self,
+ &self,
session_id: SessionId,
action: UpdateMulticastListAction,
controlees: Vec<Controlee>,
@@ -197,34 +215,35 @@ impl UwbService {
}
/// Set the country code. Android-specific method.
- pub fn android_set_country_code(&mut self, country_code: CountryCode) -> Result<()> {
+ pub fn android_set_country_code(&self, country_code: CountryCode) -> Result<()> {
self.block_on_cmd(Command::AndroidSetCountryCode { country_code })?;
Ok(())
}
/// Get the power statistics. Android-specific method.
- pub fn android_get_power_stats(&mut self) -> Result<PowerStats> {
+ pub fn android_get_power_stats(&self) -> Result<PowerStats> {
match self.block_on_cmd(Command::AndroidGetPowerStats)? {
Response::PowerStats(stats) => Ok(stats),
_ => panic!("android_get_power_stats() should return PowerStats"),
}
}
- /// Send a vendor-specific UCI message.
- pub fn send_vendor_cmd(
- &mut self,
+ /// Send a raw UCI message.
+ pub fn raw_uci_cmd(
+ &self,
+ mt: u32,
gid: u32,
oid: u32,
payload: Vec<u8>,
- ) -> Result<RawVendorMessage> {
- match self.block_on_cmd(Command::SendVendorCmd { gid, oid, payload })? {
- Response::RawVendorMessage(msg) => Ok(msg),
- _ => panic!("send_vendor_cmd() should return RawVendorMessage"),
+ ) -> Result<RawUciMessage> {
+ match self.block_on_cmd(Command::RawUciCmd { mt, gid, oid, payload })? {
+ Response::RawUciMessage(msg) => Ok(msg),
+ _ => panic!("raw_uci_cmd() should return RawUciMessage"),
}
}
/// Get app config params for the given session id
- pub fn session_params(&mut self, session_id: SessionId) -> Result<AppConfigParams> {
+ pub fn session_params(&self, session_id: SessionId) -> Result<AppConfigParams> {
match self.block_on_cmd(Command::GetParams { session_id })? {
Response::AppConfigParams(params) => Ok(params),
_ => panic!("session_params() should return AppConfigParams"),
@@ -261,7 +280,7 @@ struct UwbServiceActor<C: UwbServiceCallback, U: UciManager> {
session_manager: Option<SessionManager>,
core_notf_receiver: mpsc::UnboundedReceiver<CoreNotification>,
session_notf_receiver: mpsc::UnboundedReceiver<SessionNotification>,
- vendor_notf_receiver: mpsc::UnboundedReceiver<RawVendorMessage>,
+ vendor_notf_receiver: mpsc::UnboundedReceiver<RawUciMessage>,
}
impl<C: UwbServiceCallback, U: UciManager> UwbServiceActor<C, U> {
@@ -396,9 +415,9 @@ impl<C: UwbServiceCallback, U: UciManager> UwbServiceActor<C, U> {
let stats = self.uci_manager.android_get_power_stats().await?;
Ok(Response::PowerStats(stats))
}
- Command::SendVendorCmd { gid, oid, payload } => {
- let msg = self.uci_manager.raw_vendor_cmd(gid, oid, payload).await?;
- Ok(Response::RawVendorMessage(msg))
+ Command::RawUciCmd { mt, gid, oid, payload } => {
+ let msg = self.uci_manager.raw_uci_cmd(mt, gid, oid, payload).await?;
+ Ok(Response::RawUciMessage(msg))
}
Command::GetParams { session_id } => {
if let Some(session_manager) = self.session_manager.as_mut() {
@@ -438,7 +457,7 @@ impl<C: UwbServiceCallback, U: UciManager> UwbServiceActor<C, U> {
}
}
- async fn handle_vendor_notification(&mut self, notf: RawVendorMessage) {
+ async fn handle_vendor_notification(&mut self, notf: RawUciMessage) {
self.callback.on_vendor_notification_received(notf.gid, notf.oid, notf.payload);
}
@@ -530,7 +549,8 @@ enum Command {
country_code: CountryCode,
},
AndroidGetPowerStats,
- SendVendorCmd {
+ RawUciCmd {
+ mt: u32,
gid: u32,
oid: u32,
payload: Vec<u8>,
@@ -545,7 +565,7 @@ enum Response {
Null,
AppConfigParams(AppConfigParams),
PowerStats(PowerStats),
- RawVendorMessage(RawVendorMessage),
+ RawUciMessage(RawUciMessage),
}
type ResponseSender = oneshot::Sender<Result<Response>>;
@@ -581,7 +601,7 @@ mod tests {
let mut uci_manager = MockUciManager::new();
uci_manager.expect_open_hal(vec![], Ok(()));
uci_manager.expect_close_hal(false, Ok(()));
- let (mut service, _, _runtime) = setup_uwb_service(uci_manager);
+ let (service, _, _runtime) = setup_uwb_service(uci_manager);
let result = service.enable();
assert!(result.is_ok());
@@ -630,7 +650,7 @@ mod tests {
Ok(()),
);
- let (mut service, mut callback, _runtime) = setup_uwb_service(uci_manager.clone());
+ let (service, mut callback, _runtime) = setup_uwb_service(uci_manager.clone());
service.enable().unwrap();
// Initialize a normal session.
@@ -692,7 +712,7 @@ mod tests {
let controlees = vec![Controlee { short_address: 0x13, subsession_id: 0x24 }];
let uci_manager = MockUciManager::new();
- let (mut service, _, _runtime) = setup_uwb_service(uci_manager);
+ let (service, _, _runtime) = setup_uwb_service(uci_manager);
let result = service.init_session(session_id, session_type, params.clone());
assert!(result.is_err());
@@ -713,7 +733,7 @@ mod tests {
let country_code = CountryCode::new(b"US").unwrap();
let mut uci_manager = MockUciManager::new();
uci_manager.expect_android_set_country_code(country_code.clone(), Ok(()));
- let (mut service, _, _runtime) = setup_uwb_service(uci_manager);
+ let (service, _, _runtime) = setup_uwb_service(uci_manager);
let result = service.android_set_country_code(country_code);
assert!(result.is_ok());
@@ -730,30 +750,32 @@ mod tests {
};
let mut uci_manager = MockUciManager::new();
uci_manager.expect_android_get_power_stats(Ok(stats.clone()));
- let (mut service, _, _runtime) = setup_uwb_service(uci_manager);
+ let (service, _, _runtime) = setup_uwb_service(uci_manager);
let result = service.android_get_power_stats().unwrap();
assert_eq!(result, stats);
}
#[test]
- fn test_send_vendor_cmd() {
+ fn test_send_raw_cmd() {
+ let mt = 0x01;
let gid = 0x09;
let oid = 0x35;
let cmd_payload = vec![0x12, 0x34];
let resp_payload = vec![0x56, 0x78];
let mut uci_manager = MockUciManager::new();
- uci_manager.expect_raw_vendor_cmd(
+ uci_manager.expect_raw_uci_cmd(
+ mt,
gid,
oid,
cmd_payload.clone(),
- Ok(RawVendorMessage { gid, oid, payload: resp_payload.clone() }),
+ Ok(RawUciMessage { gid, oid, payload: resp_payload.clone() }),
);
- let (mut service, _, _runtime) = setup_uwb_service(uci_manager);
+ let (service, _, _runtime) = setup_uwb_service(uci_manager);
- let result = service.send_vendor_cmd(gid, oid, cmd_payload).unwrap();
- assert_eq!(result, RawVendorMessage { gid, oid, payload: resp_payload });
+ let result = service.raw_uci_cmd(mt, gid, oid, cmd_payload).unwrap();
+ assert_eq!(result, RawUciMessage { gid, oid, payload: resp_payload });
}
#[test]
@@ -764,10 +786,10 @@ mod tests {
let mut uci_manager = MockUciManager::new();
uci_manager.expect_open_hal(
- vec![UciNotification::Vendor(RawVendorMessage { gid, oid, payload: payload.clone() })],
+ vec![UciNotification::Vendor(RawUciMessage { gid, oid, payload: payload.clone() })],
Ok(()),
);
- let (mut service, mut callback, _runtime) = setup_uwb_service(uci_manager);
+ let (service, mut callback, _runtime) = setup_uwb_service(uci_manager);
callback.expect_on_vendor_notification_received(gid, oid, payload);
service.enable().unwrap();
@@ -783,7 +805,7 @@ mod tests {
vec![UciNotification::Core(CoreNotification::DeviceStatus(state))],
Ok(()),
);
- let (mut service, mut callback, _runtime) = setup_uwb_service(uci_manager);
+ let (service, mut callback, _runtime) = setup_uwb_service(uci_manager);
callback.expect_on_uci_device_status_changed(state);
service.enable().unwrap();
assert!(service.block_on_for_testing(callback.wait_expected_calls_done()));
@@ -797,7 +819,7 @@ mod tests {
// Then UwbService should close_hal() and open_hal() to reset the HAL.
uci_manager.expect_close_hal(true, Ok(()));
uci_manager.expect_open_hal(vec![], Ok(()));
- let (mut service, mut callback, _runtime) = setup_uwb_service(uci_manager.clone());
+ let (service, mut callback, _runtime) = setup_uwb_service(uci_manager.clone());
callback.expect_on_service_reset(true);
let result = service.enable();
@@ -820,7 +842,7 @@ mod tests {
// Then UwbService should close_hal() and open_hal() to reset the HAL.
uci_manager.expect_close_hal(true, Ok(()));
uci_manager.expect_open_hal(vec![], Ok(()));
- let (mut service, mut callback, _runtime) = setup_uwb_service(uci_manager.clone());
+ let (service, mut callback, _runtime) = setup_uwb_service(uci_manager.clone());
callback.expect_on_service_reset(true);
let result = service.enable();
diff --git a/src/rust/uwb_core/src/service/uwb_service_builder.rs b/src/rust/uwb_core/src/service/uwb_service_builder.rs
index 9075368..20a4f2b 100644
--- a/src/rust/uwb_core/src/service/uwb_service_builder.rs
+++ b/src/rust/uwb_core/src/service/uwb_service_builder.rs
@@ -103,7 +103,7 @@ mod tests {
use crate::service::mock_uwb_service_callback::MockUwbServiceCallback;
use crate::service::uwb_service_callback_builder::UwbServiceCallbackSendBuilder;
use crate::uci::mock_uci_hal::MockUciHal;
- use crate::uci::uci_logger_factory::UciLoggerFactoryNull;
+ use crate::uci::uci_logger_factory::NopUciLoggerFactory;
#[test]
fn test_build_fail() {
@@ -111,7 +111,7 @@ mod tests {
UwbServiceCallbackSendBuilder<MockUwbServiceCallback>,
MockUwbServiceCallback,
MockUciHal,
- UciLoggerFactoryNull,
+ NopUciLoggerFactory,
>::new()
.build();
assert!(result.is_none());
@@ -125,7 +125,7 @@ mod tests {
.runtime_handle(runtime.handle().to_owned())
.callback_builder(UwbServiceCallbackSendBuilder::new(callback))
.uci_hal(MockUciHal::new())
- .uci_logger_factory(UciLoggerFactoryNull::default())
+ .uci_logger_factory(NopUciLoggerFactory::default())
.build();
assert!(result.is_some());
}
diff --git a/src/rust/uwb_core/src/session/session_manager.rs b/src/rust/uwb_core/src/session/session_manager.rs
index 667879f..e9432ba 100644
--- a/src/rust/uwb_core/src/session/session_manager.rs
+++ b/src/rust/uwb_core/src/session/session_manager.rs
@@ -295,6 +295,16 @@ impl<T: UciManager> SessionManagerActor<T> {
fn handle_uci_notification(&mut self, notf: UciSessionNotification) {
match notf {
UciSessionNotification::Status { session_id, session_state, reason_code } => {
+ let reason_code = match ReasonCode::try_from(reason_code) {
+ Ok(r) => r,
+ Err(_) => {
+ error!(
+ "Received unknown reason_code {:?} in UciSessionNotification",
+ reason_code
+ );
+ return;
+ }
+ };
if session_state == SessionState::SessionStateDeinit {
debug!("Session {} is deinitialized", session_id);
let _ = self.active_sessions.remove(&session_id);
@@ -336,7 +346,7 @@ impl<T: UciManager> SessionManagerActor<T> {
);
}
},
- UciSessionNotification::RangeData(range_data) => {
+ UciSessionNotification::SessionInfo(range_data) => {
if self.active_sessions.get(&range_data.session_id).is_some() {
let _ = self.session_notf_sender.send(SessionNotification::RangeData {
session_id: range_data.session_id,
@@ -346,6 +356,42 @@ impl<T: UciManager> SessionManagerActor<T> {
warn!("Received range data of the unknown Session: {:?}", range_data);
}
}
+ UciSessionNotification::DataCredit { session_id, credit_availability: _ } => {
+ match self.active_sessions.get(&session_id) {
+ Some(_) => {
+ /*
+ * TODO(b/270443790): Handle the DataCredit notification in the new
+ * code flow.
+ */
+ }
+ None => {
+ warn!(
+ "Received the Data Credit notification for an unknown Session {}",
+ session_id
+ );
+ }
+ }
+ }
+ UciSessionNotification::DataTransferStatus {
+ session_id,
+ uci_sequence_number: _,
+ status: _,
+ } => {
+ match self.active_sessions.get(&session_id) {
+ Some(_) => {
+ /*
+ * TODO(b/270443790): Handle the DataTransferStatus notification in the
+ * new code flow.
+ */
+ }
+ None => {
+ warn!(
+ "Received a Data Transfer Status notification for unknown Session {}",
+ session_id
+ );
+ }
+ }
+ }
}
}
}
@@ -438,7 +484,7 @@ pub(crate) mod test_utils {
session_id,
current_ranging_interval_ms: 3,
ranging_measurement_type: RangingMeasurementType::TwoWay,
- ranging_measurements: RangingMeasurements::Short(vec![
+ ranging_measurements: RangingMeasurements::ShortAddressTwoWay(vec![
ShortAddressTwoWayRangingMeasurement {
mac_address: 0x123,
status: StatusCode::UciStatusOk,
@@ -468,12 +514,12 @@ pub(crate) mod test_utils {
UciNotification::Session(UciSessionNotification::Status {
session_id,
session_state,
- reason_code: ReasonCode::StateChangeWithSessionManagementCommands,
+ reason_code: ReasonCode::StateChangeWithSessionManagementCommands.into(),
})
}
pub(crate) fn range_data_notf(range_data: SessionRangeData) -> UciNotification {
- UciNotification::Session(UciSessionNotification::RangeData(range_data))
+ UciNotification::Session(UciSessionNotification::SessionInfo(range_data))
}
pub(super) async fn setup_session_manager<F>(
@@ -508,8 +554,8 @@ mod tests {
use crate::params::ccc_started_app_config_params::CccStartedAppConfigParams;
use crate::params::uci_packets::{
- AppConfigTlv, AppConfigTlvType, ControleeStatus, MulticastUpdateStatusCode,
- SetAppConfigResponse, StatusCode,
+ AppConfigTlv, AppConfigTlvType, ControleeStatus, Controlees, MulticastUpdateStatusCode,
+ ReasonCode, SetAppConfigResponse, StatusCode,
};
use crate::params::utils::{u32_to_bytes, u64_to_bytes, u8_to_bytes};
use crate::params::{FiraAppConfigParamsBuilder, KeyRotation};
@@ -761,7 +807,7 @@ mod tests {
uci_manager.expect_session_update_controller_multicast_list(
session_id,
action,
- controlees_clone,
+ Controlees::NoSessionKey(controlees_clone),
multicast_list_notf,
Ok(()),
);
@@ -846,7 +892,7 @@ mod tests {
uci_manager.expect_session_update_controller_multicast_list(
session_id,
action,
- controlees_clone,
+ uwb_uci_packets::Controlees::NoSessionKey(controlees_clone),
vec![], // Not sending notification.
Ok(()),
);
diff --git a/src/rust/uwb_core/src/session/uwb_session.rs b/src/rust/uwb_core/src/session/uwb_session.rs
index 6f1de24..91bd6ce 100644
--- a/src/rust/uwb_core/src/session/uwb_session.rs
+++ b/src/rust/uwb_core/src/session/uwb_session.rs
@@ -24,8 +24,8 @@ use crate::error::{Error, Result};
use crate::params::app_config_params::AppConfigParams;
use crate::params::ccc_started_app_config_params::CccStartedAppConfigParams;
use crate::params::uci_packets::{
- Controlee, ControleeStatus, MulticastUpdateStatusCode, SessionId, SessionState, SessionType,
- UpdateMulticastListAction,
+ Controlee, ControleeStatus, Controlees, MulticastUpdateStatusCode, SessionId, SessionState,
+ SessionType, UpdateMulticastListAction,
};
use crate::uci::error::status_code_to_result;
use crate::uci::uci_manager::UciManager;
@@ -306,7 +306,11 @@ impl<T: UciManager> UwbSessionActor<T> {
}
self.uci_manager
- .session_update_controller_multicast_list(self.session_id, action, controlees)
+ .session_update_controller_multicast_list(
+ self.session_id,
+ action,
+ Controlees::NoSessionKey(controlees),
+ )
.await?;
// Wait for the notification of the update status.
diff --git a/src/rust/uwb_core/src/uci.rs b/src/rust/uwb_core/src/uci.rs
index bcf4586..cac1be2 100644
--- a/src/rust/uwb_core/src/uci.rs
+++ b/src/rust/uwb_core/src/uci.rs
@@ -35,12 +35,15 @@ pub mod uci_manager_sync;
pub(crate) mod mock_uci_hal;
#[cfg(test)]
pub(crate) mod mock_uci_logger;
-#[cfg(test)]
-pub(crate) mod mock_uci_manager;
+#[cfg(any(test, feature = "mock-utils"))]
+pub mod mock_uci_manager;
// Re-export the public elements.
pub use command::UciCommand;
pub use notification::{
- CoreNotification, RangingMeasurements, SessionNotification, SessionRangeData, UciNotification,
+ CoreNotification, DataRcvNotification, RangingMeasurements, SessionNotification,
+ SessionRangeData, UciNotification,
};
-pub use uci_hal::{UciHal, UciHalPacket};
+pub use uci_hal::{NopUciHal, UciHal, UciHalPacket};
+pub use uci_logger_factory::{NopUciLoggerFactory, UciLoggerFactory};
+pub use uci_manager::UciManagerImpl;
diff --git a/src/rust/uwb_core/src/uci/command.rs b/src/rust/uwb_core/src/uci/command.rs
index 76edd72..dc06dab 100644
--- a/src/rust/uwb_core/src/uci/command.rs
+++ b/src/rust/uwb_core/src/uci/command.rs
@@ -12,21 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use std::convert::{TryFrom, TryInto};
+use std::convert::TryFrom;
use bytes::Bytes;
use log::error;
-use num_traits::FromPrimitive;
use crate::error::{Error, Result};
use crate::params::uci_packets::{
- AppConfigTlv, AppConfigTlvType, Controlee, CountryCode, DeviceConfigId, DeviceConfigTlv,
+ AppConfigTlv, AppConfigTlvType, Controlees, CountryCode, DeviceConfigId, DeviceConfigTlv,
ResetConfig, SessionId, SessionType, UpdateMulticastListAction,
};
-use uwb_uci_packets::{
- build_session_update_controller_multicast_list_cmd_v1,
- build_session_update_controller_multicast_list_cmd_v2, ControleesV2,
-};
+use uwb_uci_packets::{build_session_update_controller_multicast_list_cmd, GroupId, MessageType};
/// The enum to represent the UCI commands. The definition of each field should follow UCI spec.
#[allow(missing_docs)]
@@ -65,49 +61,47 @@ pub enum UciCommand {
SessionUpdateControllerMulticastList {
session_id: SessionId,
action: UpdateMulticastListAction,
- controlees: Vec<Controlee>,
+ controlees: Controlees,
+ },
+ SessionUpdateDtTagRangingRounds {
+ session_id: u32,
+ ranging_round_indexes: Vec<u8>,
},
- SessionUpdateControllerMulticastListV2 {
+ SessionQueryMaxDataSize {
session_id: SessionId,
- action: UpdateMulticastListAction,
- controlees: ControleesV2,
},
- RangeStart {
+ SessionStart {
session_id: SessionId,
},
- RangeStop {
+ SessionStop {
session_id: SessionId,
},
- RangeGetRangingCount {
+ SessionGetRangingCount {
session_id: SessionId,
},
AndroidSetCountryCode {
country_code: CountryCode,
},
AndroidGetPowerStats,
- RawVendorCmd {
+ RawUciCmd {
+ mt: u32,
gid: u32,
oid: u32,
payload: Vec<u8>,
},
}
-impl TryFrom<UciCommand> for uwb_uci_packets::UciCommandPacket {
+impl TryFrom<UciCommand> for uwb_uci_packets::UciControlPacket {
type Error = Error;
fn try_from(cmd: UciCommand) -> std::result::Result<Self, Self::Error> {
let packet = match cmd {
+ // UCI Session Config Commands
UciCommand::SessionInit { session_id, session_type } => {
uwb_uci_packets::SessionInitCmdBuilder { session_id, session_type }.build().into()
}
UciCommand::SessionDeinit { session_id } => {
uwb_uci_packets::SessionDeinitCmdBuilder { session_id }.build().into()
}
- UciCommand::RangeStart { session_id } => {
- uwb_uci_packets::RangeStartCmdBuilder { session_id }.build().into()
- }
- UciCommand::RangeStop { session_id } => {
- uwb_uci_packets::RangeStopCmdBuilder { session_id }.build().into()
- }
UciCommand::CoreGetDeviceInfo => {
uwb_uci_packets::GetDeviceInfoCmdBuilder {}.build().into()
}
@@ -116,24 +110,15 @@ impl TryFrom<UciCommand> for uwb_uci_packets::UciCommandPacket {
uwb_uci_packets::SessionGetStateCmdBuilder { session_id }.build().into()
}
UciCommand::SessionUpdateControllerMulticastList { session_id, action, controlees } => {
- build_session_update_controller_multicast_list_cmd_v1(
- session_id, action, controlees,
- )
- .into()
+ build_session_update_controller_multicast_list_cmd(session_id, action, controlees)
+ .map_err(|_| Error::BadParameters)?
+ .into()
}
- UciCommand::SessionUpdateControllerMulticastListV2 {
- session_id,
- action,
- controlees,
- } => build_session_update_controller_multicast_list_cmd_v2(
- session_id, action, controlees,
- )
- .into(),
UciCommand::CoreSetConfig { config_tlvs } => {
uwb_uci_packets::SetConfigCmdBuilder { tlvs: config_tlvs }.build().into()
}
UciCommand::CoreGetConfig { cfg_id } => uwb_uci_packets::GetConfigCmdBuilder {
- cfg_id: cfg_id.into_iter().map(|item| item as u8).collect(),
+ cfg_id: cfg_id.into_iter().map(u8::from).collect(),
}
.build()
.into(),
@@ -148,7 +133,15 @@ impl TryFrom<UciCommand> for uwb_uci_packets::UciCommandPacket {
UciCommand::SessionGetAppConfig { session_id, app_cfg } => {
uwb_uci_packets::SessionGetAppConfigCmdBuilder {
session_id,
- app_cfg: app_cfg.into_iter().map(|item| item as u8).collect(),
+ app_cfg: app_cfg.into_iter().map(u8::from).collect(),
+ }
+ .build()
+ .into()
+ }
+ UciCommand::SessionUpdateDtTagRangingRounds { session_id, ranging_round_indexes } => {
+ uwb_uci_packets::SessionUpdateDtTagRangingRoundsCmdBuilder {
+ session_id,
+ ranging_round_indexes,
}
.build()
.into()
@@ -156,8 +149,8 @@ impl TryFrom<UciCommand> for uwb_uci_packets::UciCommandPacket {
UciCommand::AndroidGetPowerStats => {
uwb_uci_packets::AndroidGetPowerStatsCmdBuilder {}.build().into()
}
- UciCommand::RawVendorCmd { gid, oid, payload } => {
- build_uci_vendor_cmd_packet(gid, oid, payload)?
+ UciCommand::RawUciCmd { mt, gid, oid, payload } => {
+ build_raw_uci_cmd_packet(mt, gid, oid, payload)?
}
UciCommand::SessionGetCount => {
uwb_uci_packets::SessionGetCountCmdBuilder {}.build().into()
@@ -172,49 +165,213 @@ impl TryFrom<UciCommand> for uwb_uci_packets::UciCommandPacket {
UciCommand::DeviceReset { reset_config } => {
uwb_uci_packets::DeviceResetCmdBuilder { reset_config }.build().into()
}
- UciCommand::RangeGetRangingCount { session_id } => {
- uwb_uci_packets::RangeGetRangingCountCmdBuilder { session_id }.build().into()
+ // UCI Session Control Commands
+ UciCommand::SessionStart { session_id } => {
+ uwb_uci_packets::SessionStartCmdBuilder { session_id }.build().into()
+ }
+ UciCommand::SessionStop { session_id } => {
+ uwb_uci_packets::SessionStopCmdBuilder { session_id }.build().into()
+ }
+ UciCommand::SessionGetRangingCount { session_id } => {
+ uwb_uci_packets::SessionGetRangingCountCmdBuilder { session_id }.build().into()
+ }
+ UciCommand::SessionQueryMaxDataSize { session_id } => {
+ uwb_uci_packets::SessionQueryMaxDataSizeCmdBuilder { session_id }.build().into()
}
};
Ok(packet)
}
}
-fn build_uci_vendor_cmd_packet(
+fn build_raw_uci_cmd_packet(
+ mt: u32,
gid: u32,
oid: u32,
payload: Vec<u8>,
-) -> Result<uwb_uci_packets::UciCommandPacket> {
- use uwb_uci_packets::GroupId;
- let group_id = GroupId::from_u32(gid).ok_or_else(|| {
+) -> Result<uwb_uci_packets::UciControlPacket> {
+ let group_id = u8::try_from(gid).or(Err(0)).and_then(GroupId::try_from).map_err(|_| {
error!("Invalid GroupId: {}", gid);
Error::BadParameters
})?;
let payload = if payload.is_empty() { None } else { Some(Bytes::from(payload)) };
- let opcode = oid.try_into().map_err(|_| {
+ let opcode = u8::try_from(oid).map_err(|_| {
error!("Invalid opcod: {}", oid);
Error::BadParameters
})?;
- let packet = match group_id {
- GroupId::VendorReserved9 => {
- uwb_uci_packets::UciVendor_9_CommandBuilder { opcode, payload }.build().into()
- }
- GroupId::VendorReservedA => {
- uwb_uci_packets::UciVendor_A_CommandBuilder { opcode, payload }.build().into()
- }
- GroupId::VendorReservedB => {
- uwb_uci_packets::UciVendor_B_CommandBuilder { opcode, payload }.build().into()
- }
- GroupId::VendorReservedE => {
- uwb_uci_packets::UciVendor_E_CommandBuilder { opcode, payload }.build().into()
- }
- GroupId::VendorReservedF => {
- uwb_uci_packets::UciVendor_F_CommandBuilder { opcode, payload }.build().into()
- }
- _ => {
- error!("Invalid vendor gid {:?}", gid);
- return Err(Error::BadParameters);
- }
- };
- Ok(packet)
+ let message_type =
+ u8::try_from(mt).or(Err(0)).and_then(MessageType::try_from).map_err(|_| {
+ error!("Invalid MessageType: {}", mt);
+ Error::BadParameters
+ })?;
+ match uwb_uci_packets::build_uci_control_packet(message_type, group_id, opcode, payload) {
+ Some(cmd) => Ok(cmd),
+ None => Err(Error::BadParameters),
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_build_raw_uci_cmd() {
+ let payload = vec![0x01, 0x02];
+ let cmd_packet = build_raw_uci_cmd_packet(1, 9, 0, payload.clone()).unwrap();
+ assert_eq!(payload, cmd_packet.to_raw_payload());
+ }
+
+ #[test]
+ fn test_convert_uci_cmd_to_packets() {
+ let mut cmd = UciCommand::DeviceReset { reset_config: ResetConfig::UwbsReset };
+ let mut packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(
+ packet,
+ uwb_uci_packets::DeviceResetCmdBuilder { reset_config: ResetConfig::UwbsReset }
+ .build()
+ .into()
+ );
+
+ cmd = UciCommand::CoreGetDeviceInfo {};
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(packet, uwb_uci_packets::GetDeviceInfoCmdBuilder {}.build().into());
+
+ cmd = UciCommand::CoreGetCapsInfo {};
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(packet, uwb_uci_packets::GetCapsInfoCmdBuilder {}.build().into());
+
+ let device_cfg_tlv = DeviceConfigTlv { cfg_id: DeviceConfigId::DeviceState, v: vec![0] };
+ cmd = UciCommand::CoreSetConfig { config_tlvs: vec![device_cfg_tlv.clone()] };
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(
+ packet,
+ uwb_uci_packets::SetConfigCmdBuilder { tlvs: vec![device_cfg_tlv] }.build().into()
+ );
+
+ cmd = UciCommand::CoreGetConfig { cfg_id: vec![DeviceConfigId::DeviceState] };
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(packet, uwb_uci_packets::GetConfigCmdBuilder { cfg_id: vec![0] }.build().into());
+
+ cmd = UciCommand::SessionInit {
+ session_id: 1,
+ session_type: SessionType::FiraRangingSession,
+ };
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(
+ packet,
+ uwb_uci_packets::SessionInitCmdBuilder {
+ session_id: 1,
+ session_type: SessionType::FiraRangingSession
+ }
+ .build()
+ .into()
+ );
+
+ cmd = UciCommand::SessionDeinit { session_id: 1 };
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(
+ packet,
+ uwb_uci_packets::SessionDeinitCmdBuilder { session_id: 1 }.build().into()
+ );
+
+ cmd = UciCommand::SessionSetAppConfig { session_id: 1, config_tlvs: vec![] };
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(
+ packet,
+ uwb_uci_packets::SessionSetAppConfigCmdBuilder { session_id: 1, tlvs: vec![] }
+ .build()
+ .into()
+ );
+
+ cmd = UciCommand::SessionGetAppConfig { session_id: 1, app_cfg: vec![] };
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(
+ packet,
+ uwb_uci_packets::SessionGetAppConfigCmdBuilder { session_id: 1, app_cfg: vec![] }
+ .build()
+ .into()
+ );
+
+ cmd = UciCommand::SessionGetCount {};
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(packet, uwb_uci_packets::SessionGetCountCmdBuilder {}.build().into());
+
+ cmd = UciCommand::SessionGetState { session_id: 1 };
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(
+ packet,
+ uwb_uci_packets::SessionGetStateCmdBuilder { session_id: 1 }.build().into()
+ );
+
+ cmd = UciCommand::SessionUpdateControllerMulticastList {
+ session_id: 1,
+ action: UpdateMulticastListAction::AddControlee,
+ controlees: Controlees::NoSessionKey(vec![]),
+ };
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(
+ packet,
+ build_session_update_controller_multicast_list_cmd(
+ 1,
+ UpdateMulticastListAction::AddControlee,
+ Controlees::NoSessionKey(vec![])
+ )
+ .map_err(|_| Error::BadParameters)
+ .unwrap()
+ .into()
+ );
+
+ cmd = UciCommand::SessionUpdateDtTagRangingRounds {
+ session_id: 1,
+ ranging_round_indexes: vec![0],
+ };
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(
+ packet,
+ uwb_uci_packets::SessionUpdateDtTagRangingRoundsCmdBuilder {
+ session_id: 1,
+ ranging_round_indexes: vec![0]
+ }
+ .build()
+ .into()
+ );
+
+ cmd = UciCommand::SessionQueryMaxDataSize { session_id: 1 };
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(
+ packet,
+ uwb_uci_packets::SessionQueryMaxDataSizeCmdBuilder { session_id: 1 }.build().into()
+ );
+
+ cmd = UciCommand::SessionStart { session_id: 1 };
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(
+ packet,
+ uwb_uci_packets::SessionStartCmdBuilder { session_id: 1 }.build().into()
+ );
+
+ cmd = UciCommand::SessionStop { session_id: 1 };
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(packet, uwb_uci_packets::SessionStopCmdBuilder { session_id: 1 }.build().into());
+
+ cmd = UciCommand::SessionGetRangingCount { session_id: 1 };
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(
+ packet,
+ uwb_uci_packets::SessionGetRangingCountCmdBuilder { session_id: 1 }.build().into()
+ );
+
+ let country_code: [u8; 2] = [85, 83];
+ cmd = UciCommand::AndroidSetCountryCode {
+ country_code: CountryCode::new(&country_code).unwrap(),
+ };
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
+ assert_eq!(
+ packet,
+ uwb_uci_packets::AndroidSetCountryCodeCmdBuilder { country_code }.build().into()
+ );
+
+ cmd = UciCommand::AndroidGetPowerStats {};
+ packet = uwb_uci_packets::UciControlPacket::try_from(cmd).unwrap();
+ assert_eq!(packet, uwb_uci_packets::AndroidGetPowerStatsCmdBuilder {}.build().into());
+ }
}
diff --git a/src/rust/uwb_core/src/uci/message.rs b/src/rust/uwb_core/src/uci/message.rs
index e386ca8..fcbc65d 100644
--- a/src/rust/uwb_core/src/uci/message.rs
+++ b/src/rust/uwb_core/src/uci/message.rs
@@ -26,14 +26,14 @@ pub(super) enum UciMessage {
Notification(UciNotification),
}
-impl TryFrom<uwb_uci_packets::UciPacketPacket> for UciMessage {
+impl TryFrom<uwb_uci_packets::UciControlPacket> for UciMessage {
type Error = Error;
- fn try_from(packet: uwb_uci_packets::UciPacketPacket) -> Result<Self, Self::Error> {
+ fn try_from(packet: uwb_uci_packets::UciControlPacket) -> Result<Self, Self::Error> {
match packet.specialize() {
- uwb_uci_packets::UciPacketChild::UciResponse(evt) => {
+ uwb_uci_packets::UciControlPacketChild::UciResponse(evt) => {
Ok(UciMessage::Response(evt.try_into()?))
}
- uwb_uci_packets::UciPacketChild::UciNotification(evt) => {
+ uwb_uci_packets::UciControlPacketChild::UciNotification(evt) => {
Ok(UciMessage::Notification(evt.try_into()?))
}
_ => {
diff --git a/src/rust/uwb_core/src/uci/mock_uci_hal.rs b/src/rust/uwb_core/src/uci/mock_uci_hal.rs
index eb27e00..7e7cfc0 100644
--- a/src/rust/uwb_core/src/uci/mock_uci_hal.rs
+++ b/src/rust/uwb_core/src/uci/mock_uci_hal.rs
@@ -59,6 +59,19 @@ impl MockUciHal {
});
}
+ pub fn expected_send_packet(
+ &mut self,
+ expected_packet_tx: UciHalPacket,
+ inject_packets_rx: Vec<UciHalPacket>,
+ out: Result<()>,
+ ) {
+ self.expected_calls.lock().unwrap().push_back(ExpectedCall::SendPacket {
+ expected_packet_tx,
+ inject_packets_rx,
+ out,
+ });
+ }
+
pub fn expected_notify_session_initialized(
&mut self,
expected_session_id: SessionId,
@@ -145,9 +158,26 @@ impl UciHal for MockUciHal {
}
}
- async fn send_packet(&mut self, _packet: UciHalPacket) -> Result<()> {
- // We mock the send_command(), so send_packet() would not be called.
- Err(Error::MockUndefined)
+ async fn send_packet(&mut self, packet_tx: UciHalPacket) -> Result<()> {
+ // send_packet() will be directly called for sending UCI Data packets.
+ let mut expected_calls = self.expected_calls.lock().unwrap();
+ match expected_calls.pop_front() {
+ Some(ExpectedCall::SendPacket { expected_packet_tx, inject_packets_rx, out })
+ if expected_packet_tx == packet_tx =>
+ {
+ self.expect_call_consumed.notify_one();
+ let packet_sender = self.packet_sender.as_mut().unwrap();
+ for msg in inject_packets_rx.into_iter() {
+ let _ = packet_sender.send(msg);
+ }
+ out
+ }
+ Some(call) => {
+ expected_calls.push_front(call);
+ Err(Error::MockUndefined)
+ }
+ None => Err(Error::MockUndefined),
+ }
}
async fn notify_session_initialized(&mut self, session_id: SessionId) -> Result<()> {
@@ -169,8 +199,25 @@ impl UciHal for MockUciHal {
}
enum ExpectedCall {
- Open { packets: Option<Vec<UciHalPacket>>, out: Result<()> },
- Close { out: Result<()> },
- SendCommand { expected_cmd: UciCommand, packets: Vec<UciHalPacket>, out: Result<()> },
- NotifySessionInitialized { expected_session_id: SessionId, out: Result<()> },
+ Open {
+ packets: Option<Vec<UciHalPacket>>,
+ out: Result<()>,
+ },
+ Close {
+ out: Result<()>,
+ },
+ SendCommand {
+ expected_cmd: UciCommand,
+ packets: Vec<UciHalPacket>,
+ out: Result<()>,
+ },
+ SendPacket {
+ expected_packet_tx: UciHalPacket,
+ inject_packets_rx: Vec<UciHalPacket>,
+ out: Result<()>,
+ },
+ NotifySessionInitialized {
+ expected_session_id: SessionId,
+ out: Result<()>,
+ },
}
diff --git a/src/rust/uwb_core/src/uci/mock_uci_logger.rs b/src/rust/uwb_core/src/uci/mock_uci_logger.rs
index 64f173d..e21fb71 100644
--- a/src/rust/uwb_core/src/uci/mock_uci_logger.rs
+++ b/src/rust/uwb_core/src/uci/mock_uci_logger.rs
@@ -15,7 +15,7 @@
use std::convert::TryFrom;
use tokio::sync::mpsc;
-use uwb_uci_packets::UciPacketPacket;
+use uwb_uci_packets::{UciControlPacket, UciDataPacket};
use crate::error::{Error, Result};
use crate::uci::uci_logger::UciLogger;
@@ -57,7 +57,11 @@ impl UciLogger for MockUciLogger {
let _ = self.log_sender.send(UciLogEvent::HalOpen(result));
}
- fn log_uci_packet(&mut self, packet: UciPacketPacket) {
+ fn log_uci_control_packet(&mut self, packet: UciControlPacket) {
let _ = self.log_sender.send(UciLogEvent::Packet(packet.into()));
}
+
+ fn log_uci_data_packet(&mut self, packet: &UciDataPacket) {
+ let _ = self.log_sender.send(UciLogEvent::Packet(packet.clone().into()));
+ }
}
diff --git a/src/rust/uwb_core/src/uci/mock_uci_manager.rs b/src/rust/uwb_core/src/uci/mock_uci_manager.rs
index e8215d4..a206392 100644
--- a/src/rust/uwb_core/src/uci/mock_uci_manager.rs
+++ b/src/rust/uwb_core/src/uci/mock_uci_manager.rs
@@ -12,8 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//! This module offers a mocked version of UciManager for testing.
+//!
+//! The mocked version of UciManager mimics the behavior of the UCI manager and
+//! stacks below it, such that tests can be run on a target without the UWB
+//! hardware.
use std::collections::VecDeque;
-use std::iter::zip;
use std::sync::{Arc, Mutex};
use std::time::Duration;
@@ -23,27 +27,32 @@ use tokio::time::timeout;
use crate::error::{Error, Result};
use crate::params::uci_packets::{
- app_config_tlvs_eq, device_config_tlvs_eq, AppConfigTlv, AppConfigTlvType, CapTlv, Controlee,
- CoreSetConfigResponse, CountryCode, DeviceConfigId, DeviceConfigTlv, GetDeviceInfoResponse,
- PowerStats, RawVendorMessage, ResetConfig, SessionId, SessionState, SessionType,
- SetAppConfigResponse, UpdateMulticastListAction,
+ app_config_tlvs_eq, device_config_tlvs_eq, AppConfigTlv, AppConfigTlvType, CapTlv, Controlees,
+ CoreSetConfigResponse, CountryCode, DeviceConfigId, DeviceConfigTlv, FiraComponent,
+ GetDeviceInfoResponse, PowerStats, RawUciMessage, ResetConfig, SessionId, SessionState,
+ SessionType, SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse,
+ UpdateMulticastListAction,
+};
+use crate::uci::notification::{
+ CoreNotification, DataRcvNotification, SessionNotification, UciNotification,
};
-use crate::uci::notification::{CoreNotification, SessionNotification, UciNotification};
use crate::uci::uci_logger::UciLoggerMode;
use crate::uci::uci_manager::UciManager;
-use uwb_uci_packets::ControleesV2;
#[derive(Clone)]
-pub(crate) struct MockUciManager {
+/// Mock version of UciManager for testing.
+pub struct MockUciManager {
expected_calls: Arc<Mutex<VecDeque<ExpectedCall>>>,
expect_call_consumed: Arc<Notify>,
core_notf_sender: mpsc::UnboundedSender<CoreNotification>,
session_notf_sender: mpsc::UnboundedSender<SessionNotification>,
- vendor_notf_sender: mpsc::UnboundedSender<RawVendorMessage>,
+ vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>,
+ data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>,
}
#[allow(dead_code)]
impl MockUciManager {
+ /// Constructor.
pub fn new() -> Self {
Self {
expected_calls: Default::default(),
@@ -51,9 +60,13 @@ impl MockUciManager {
core_notf_sender: mpsc::unbounded_channel().0,
session_notf_sender: mpsc::unbounded_channel().0,
vendor_notf_sender: mpsc::unbounded_channel().0,
+ data_rcv_notf_sender: mpsc::unbounded_channel().0,
}
}
+ /// Wait until expected calls are done.
+ ///
+ /// Returns false if calls are pending after 1 second.
pub async fn wait_expected_calls_done(&mut self) -> bool {
while !self.expected_calls.lock().unwrap().is_empty() {
if timeout(Duration::from_secs(1), self.expect_call_consumed.notified()).await.is_err()
@@ -64,10 +77,16 @@ impl MockUciManager {
true
}
+ /// Prepare Mock to expect for open_hal.
+ ///
+ /// MockUciManager expects call, returns out as response, followed by notfs sent.
pub fn expect_open_hal(&mut self, notfs: Vec<UciNotification>, out: Result<()>) {
self.expected_calls.lock().unwrap().push_back(ExpectedCall::OpenHal { notfs, out });
}
+ /// Prepare Mock to expect for close_call.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response.
pub fn expect_close_hal(&mut self, expected_force: bool, out: Result<()>) {
self.expected_calls
.lock()
@@ -75,6 +94,9 @@ impl MockUciManager {
.push_back(ExpectedCall::CloseHal { expected_force, out });
}
+ /// Prepare Mock to expect device_reset.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response.
pub fn expect_device_reset(&mut self, expected_reset_config: ResetConfig, out: Result<()>) {
self.expected_calls
.lock()
@@ -82,14 +104,23 @@ impl MockUciManager {
.push_back(ExpectedCall::DeviceReset { expected_reset_config, out });
}
+ /// Prepare Mock to expect core_get_device_info.
+ ///
+ /// MockUciManager expects call, returns out as response.
pub fn expect_core_get_device_info(&mut self, out: Result<GetDeviceInfoResponse>) {
self.expected_calls.lock().unwrap().push_back(ExpectedCall::CoreGetDeviceInfo { out });
}
+ /// Prepare Mock to expect core_get_caps_info.
+ ///
+ /// MockUciManager expects call, returns out as response.
pub fn expect_core_get_caps_info(&mut self, out: Result<Vec<CapTlv>>) {
self.expected_calls.lock().unwrap().push_back(ExpectedCall::CoreGetCapsInfo { out });
}
+ /// Prepare Mock to expect core_set_config.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response.
pub fn expect_core_set_config(
&mut self,
expected_config_tlvs: Vec<DeviceConfigTlv>,
@@ -101,6 +132,9 @@ impl MockUciManager {
.push_back(ExpectedCall::CoreSetConfig { expected_config_tlvs, out });
}
+ /// Prepare Mock to expect core_get_config.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response.
pub fn expect_core_get_config(
&mut self,
expected_config_ids: Vec<DeviceConfigId>,
@@ -112,6 +146,10 @@ impl MockUciManager {
.push_back(ExpectedCall::CoreGetConfig { expected_config_ids, out });
}
+ /// Prepare Mock to expect session_init.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response, followed by notfs
+ /// sent.
pub fn expect_session_init(
&mut self,
expected_session_id: SessionId,
@@ -127,6 +165,10 @@ impl MockUciManager {
});
}
+ /// Prepare Mock to expect session_deinit.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response, followed by notfs
+ /// sent.
pub fn expect_session_deinit(
&mut self,
expected_session_id: SessionId,
@@ -140,6 +182,10 @@ impl MockUciManager {
});
}
+ /// Prepare Mock to expect session_set_app_config.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response, followed by notfs
+ /// sent.
pub fn expect_session_set_app_config(
&mut self,
expected_session_id: SessionId,
@@ -155,6 +201,9 @@ impl MockUciManager {
});
}
+ /// Prepare Mock to expect session_get_app_config.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response.
pub fn expect_session_get_app_config(
&mut self,
expected_session_id: SessionId,
@@ -168,10 +217,16 @@ impl MockUciManager {
});
}
+ /// Prepare Mock to expect session_get_count.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response.
pub fn expect_session_get_count(&mut self, out: Result<u8>) {
self.expected_calls.lock().unwrap().push_back(ExpectedCall::SessionGetCount { out });
}
+ /// Prepare Mock to expect session_get_state.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response.
pub fn expect_session_get_state(
&mut self,
expected_session_id: SessionId,
@@ -183,11 +238,15 @@ impl MockUciManager {
.push_back(ExpectedCall::SessionGetState { expected_session_id, out });
}
+ /// Prepare Mock to expect update_controller_multicast_list.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response, followed by notfs
+ /// sent.
pub fn expect_session_update_controller_multicast_list(
&mut self,
expected_session_id: SessionId,
expected_action: UpdateMulticastListAction,
- expected_controlees: Vec<Controlee>,
+ expected_controlees: Controlees,
notfs: Vec<UciNotification>,
out: Result<()>,
) {
@@ -202,25 +261,42 @@ impl MockUciManager {
);
}
- pub fn expect_session_update_controller_multicast_list_v2(
+ /// Prepare Mock to expect session_update_active_rounds_dt_tag.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response.
+ pub fn expect_session_update_dt_tag_ranging_rounds(
&mut self,
- expected_session_id: SessionId,
- expected_action: UpdateMulticastListAction,
- expected_controlees: ControleesV2,
- notfs: Vec<UciNotification>,
- out: Result<()>,
+ expected_session_id: u32,
+ expected_ranging_round_indexes: Vec<u8>,
+ out: Result<SessionUpdateDtTagRangingRoundsResponse>,
) {
self.expected_calls.lock().unwrap().push_back(
- ExpectedCall::SessionUpdateControllerMulticastListV2 {
+ ExpectedCall::SessionUpdateDtTagRangingRounds {
expected_session_id,
- expected_action,
- expected_controlees,
- notfs,
+ expected_ranging_round_indexes,
out,
},
);
}
+ /// Prepare Mock to expect for session_query_max_data_size.
+ ///
+ /// MockUciManager expects call, returns out as response.
+ pub fn expect_session_query_max_data_size(
+ &mut self,
+ expected_session_id: SessionId,
+ out: Result<u16>,
+ ) {
+ self.expected_calls
+ .lock()
+ .unwrap()
+ .push_back(ExpectedCall::SessionQueryMaxDataSize { expected_session_id, out });
+ }
+
+ /// Prepare Mock to expect range_start.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response, followed by notfs
+ /// sent.
pub fn expect_range_start(
&mut self,
expected_session_id: SessionId,
@@ -234,6 +310,10 @@ impl MockUciManager {
});
}
+ /// Prepare Mock to expect range_stop.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response, followed by notfs
+ /// sent.
pub fn expect_range_stop(
&mut self,
expected_session_id: SessionId,
@@ -247,6 +327,9 @@ impl MockUciManager {
});
}
+ /// Prepare Mock to expect range_get_ranging_count.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response.
pub fn expect_range_get_ranging_count(
&mut self,
expected_session_id: SessionId,
@@ -258,6 +341,9 @@ impl MockUciManager {
.push_back(ExpectedCall::RangeGetRangingCount { expected_session_id, out });
}
+ /// Prepare Mock to expect android_set_country_code.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response.
pub fn expect_android_set_country_code(
&mut self,
expected_country_code: CountryCode,
@@ -269,18 +355,26 @@ impl MockUciManager {
.push_back(ExpectedCall::AndroidSetCountryCode { expected_country_code, out });
}
+ /// Prepare Mock to expect android_set_country_code.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response.
pub fn expect_android_get_power_stats(&mut self, out: Result<PowerStats>) {
self.expected_calls.lock().unwrap().push_back(ExpectedCall::AndroidGetPowerStats { out });
}
- pub fn expect_raw_vendor_cmd(
+ /// Prepare Mock to expect raw_uci_cmd.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response.
+ pub fn expect_raw_uci_cmd(
&mut self,
+ expected_mt: u32,
expected_gid: u32,
expected_oid: u32,
expected_payload: Vec<u8>,
- out: Result<RawVendorMessage>,
+ out: Result<RawUciMessage>,
) {
- self.expected_calls.lock().unwrap().push_back(ExpectedCall::RawVendorCmd {
+ self.expected_calls.lock().unwrap().push_back(ExpectedCall::RawUciCmd {
+ expected_mt,
expected_gid,
expected_oid,
expected_payload,
@@ -288,6 +382,29 @@ impl MockUciManager {
});
}
+ /// Prepare Mock to expect send_data_packet.
+ ///
+ /// MockUciManager expects call with parameters, returns out as response.
+ pub fn expect_send_data_packet(
+ &mut self,
+ expected_session_id: SessionId,
+ expected_address: Vec<u8>,
+ expected_dest_end_point: FiraComponent,
+ expected_uci_sequence_num: u8,
+ expected_app_payload_data: Vec<u8>,
+ out: Result<()>,
+ ) {
+ self.expected_calls.lock().unwrap().push_back(ExpectedCall::SendDataPacket {
+ expected_session_id,
+ expected_address,
+ expected_dest_end_point,
+ expected_uci_sequence_num,
+ expected_app_payload_data,
+ out,
+ });
+ }
+
+ /// Call Mock to send notifications.
fn send_notifications(&self, notfs: Vec<UciNotification>) {
for notf in notfs.into_iter() {
match notf {
@@ -305,9 +422,15 @@ impl MockUciManager {
}
}
+impl Default for MockUciManager {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
#[async_trait]
impl UciManager for MockUciManager {
- async fn set_logger_mode(&mut self, _logger_mode: UciLoggerMode) -> Result<()> {
+ async fn set_logger_mode(&self, _logger_mode: UciLoggerMode) -> Result<()> {
Ok(())
}
async fn set_core_notification_sender(
@@ -324,12 +447,18 @@ impl UciManager for MockUciManager {
}
async fn set_vendor_notification_sender(
&mut self,
- vendor_notf_sender: mpsc::UnboundedSender<RawVendorMessage>,
+ vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>,
) {
self.vendor_notf_sender = vendor_notf_sender;
}
+ async fn set_data_rcv_notification_sender(
+ &mut self,
+ data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>,
+ ) {
+ self.data_rcv_notf_sender = data_rcv_notf_sender;
+ }
- async fn open_hal(&mut self) -> Result<()> {
+ async fn open_hal(&self) -> Result<()> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
Some(ExpectedCall::OpenHal { notfs, out }) => {
@@ -345,7 +474,7 @@ impl UciManager for MockUciManager {
}
}
- async fn close_hal(&mut self, force: bool) -> Result<()> {
+ async fn close_hal(&self, force: bool) -> Result<()> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
Some(ExpectedCall::CloseHal { expected_force, out }) if expected_force == force => {
@@ -360,7 +489,7 @@ impl UciManager for MockUciManager {
}
}
- async fn device_reset(&mut self, reset_config: ResetConfig) -> Result<()> {
+ async fn device_reset(&self, reset_config: ResetConfig) -> Result<()> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
Some(ExpectedCall::DeviceReset { expected_reset_config, out })
@@ -377,7 +506,7 @@ impl UciManager for MockUciManager {
}
}
- async fn core_get_device_info(&mut self) -> Result<GetDeviceInfoResponse> {
+ async fn core_get_device_info(&self) -> Result<GetDeviceInfoResponse> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
Some(ExpectedCall::CoreGetDeviceInfo { out }) => {
@@ -392,7 +521,7 @@ impl UciManager for MockUciManager {
}
}
- async fn core_get_caps_info(&mut self) -> Result<Vec<CapTlv>> {
+ async fn core_get_caps_info(&self) -> Result<Vec<CapTlv>> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
Some(ExpectedCall::CoreGetCapsInfo { out }) => {
@@ -408,7 +537,7 @@ impl UciManager for MockUciManager {
}
async fn core_set_config(
- &mut self,
+ &self,
config_tlvs: Vec<DeviceConfigTlv>,
) -> Result<CoreSetConfigResponse> {
let mut expected_calls = self.expected_calls.lock().unwrap();
@@ -428,7 +557,7 @@ impl UciManager for MockUciManager {
}
async fn core_get_config(
- &mut self,
+ &self,
config_ids: Vec<DeviceConfigId>,
) -> Result<Vec<DeviceConfigTlv>> {
let mut expected_calls = self.expected_calls.lock().unwrap();
@@ -447,11 +576,7 @@ impl UciManager for MockUciManager {
}
}
- async fn session_init(
- &mut self,
- session_id: SessionId,
- session_type: SessionType,
- ) -> Result<()> {
+ async fn session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
Some(ExpectedCall::SessionInit {
@@ -472,7 +597,7 @@ impl UciManager for MockUciManager {
}
}
- async fn session_deinit(&mut self, session_id: SessionId) -> Result<()> {
+ async fn session_deinit(&self, session_id: SessionId) -> Result<()> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
Some(ExpectedCall::SessionDeinit { expected_session_id, notfs, out })
@@ -491,7 +616,7 @@ impl UciManager for MockUciManager {
}
async fn session_set_app_config(
- &mut self,
+ &self,
session_id: SessionId,
config_tlvs: Vec<AppConfigTlv>,
) -> Result<SetAppConfigResponse> {
@@ -518,7 +643,7 @@ impl UciManager for MockUciManager {
}
async fn session_get_app_config(
- &mut self,
+ &self,
session_id: SessionId,
config_ids: Vec<AppConfigTlvType>,
) -> Result<Vec<AppConfigTlv>> {
@@ -540,7 +665,7 @@ impl UciManager for MockUciManager {
}
}
- async fn session_get_count(&mut self) -> Result<u8> {
+ async fn session_get_count(&self) -> Result<u8> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
Some(ExpectedCall::SessionGetCount { out }) => {
@@ -555,7 +680,7 @@ impl UciManager for MockUciManager {
}
}
- async fn session_get_state(&mut self, session_id: SessionId) -> Result<SessionState> {
+ async fn session_get_state(&self, session_id: SessionId) -> Result<SessionState> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
Some(ExpectedCall::SessionGetState { expected_session_id, out })
@@ -573,10 +698,10 @@ impl UciManager for MockUciManager {
}
async fn session_update_controller_multicast_list(
- &mut self,
+ &self,
session_id: SessionId,
action: UpdateMulticastListAction,
- controlees: Vec<Controlee>,
+ controlees: Controlees,
) -> Result<()> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
@@ -588,9 +713,7 @@ impl UciManager for MockUciManager {
out,
}) if expected_session_id == session_id
&& expected_action == action
- && zip(&expected_controlees, &controlees).all(|(a, b)| {
- a.short_address == b.short_address && a.subsession_id == b.subsession_id
- }) =>
+ && expected_controlees == controlees =>
{
self.expect_call_consumed.notify_one();
self.send_notifications(notfs);
@@ -604,26 +727,21 @@ impl UciManager for MockUciManager {
}
}
- async fn session_update_controller_multicast_list_v2(
- &mut self,
- session_id: SessionId,
- action: UpdateMulticastListAction,
- controlees: ControleesV2,
- ) -> Result<()> {
+ async fn session_update_dt_tag_ranging_rounds(
+ &self,
+ session_id: u32,
+ ranging_round_indexes: Vec<u8>,
+ ) -> Result<SessionUpdateDtTagRangingRoundsResponse> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
- Some(ExpectedCall::SessionUpdateControllerMulticastListV2 {
+ Some(ExpectedCall::SessionUpdateDtTagRangingRounds {
expected_session_id,
- expected_action,
- expected_controlees,
- notfs,
+ expected_ranging_round_indexes,
out,
}) if expected_session_id == session_id
- && expected_action == action
- && expected_controlees == controlees =>
+ && expected_ranging_round_indexes == ranging_round_indexes =>
{
self.expect_call_consumed.notify_one();
- self.send_notifications(notfs);
out
}
Some(call) => {
@@ -634,7 +752,24 @@ impl UciManager for MockUciManager {
}
}
- async fn range_start(&mut self, session_id: SessionId) -> Result<()> {
+ async fn session_query_max_data_size(&self, session_id: SessionId) -> Result<u16> {
+ let mut expected_calls = self.expected_calls.lock().unwrap();
+ match expected_calls.pop_front() {
+ Some(ExpectedCall::SessionQueryMaxDataSize { expected_session_id, out })
+ if expected_session_id == session_id =>
+ {
+ self.expect_call_consumed.notify_one();
+ out
+ }
+ Some(call) => {
+ expected_calls.push_front(call);
+ Err(Error::MockUndefined)
+ }
+ None => Err(Error::MockUndefined),
+ }
+ }
+
+ async fn range_start(&self, session_id: SessionId) -> Result<()> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
Some(ExpectedCall::RangeStart { expected_session_id, notfs, out })
@@ -652,7 +787,7 @@ impl UciManager for MockUciManager {
}
}
- async fn range_stop(&mut self, session_id: SessionId) -> Result<()> {
+ async fn range_stop(&self, session_id: SessionId) -> Result<()> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
Some(ExpectedCall::RangeStop { expected_session_id, notfs, out })
@@ -670,7 +805,7 @@ impl UciManager for MockUciManager {
}
}
- async fn range_get_ranging_count(&mut self, session_id: SessionId) -> Result<usize> {
+ async fn range_get_ranging_count(&self, session_id: SessionId) -> Result<usize> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
Some(ExpectedCall::RangeGetRangingCount { expected_session_id, out })
@@ -687,7 +822,7 @@ impl UciManager for MockUciManager {
}
}
- async fn android_set_country_code(&mut self, country_code: CountryCode) -> Result<()> {
+ async fn android_set_country_code(&self, country_code: CountryCode) -> Result<()> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
Some(ExpectedCall::AndroidSetCountryCode { expected_country_code, out })
@@ -704,7 +839,7 @@ impl UciManager for MockUciManager {
}
}
- async fn android_get_power_stats(&mut self) -> Result<PowerStats> {
+ async fn android_get_power_stats(&self) -> Result<PowerStats> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
Some(ExpectedCall::AndroidGetPowerStats { out }) => {
@@ -719,20 +854,60 @@ impl UciManager for MockUciManager {
}
}
- async fn raw_vendor_cmd(
- &mut self,
+ async fn raw_uci_cmd(
+ &self,
+ mt: u32,
gid: u32,
oid: u32,
payload: Vec<u8>,
- ) -> Result<RawVendorMessage> {
+ ) -> Result<RawUciMessage> {
let mut expected_calls = self.expected_calls.lock().unwrap();
match expected_calls.pop_front() {
- Some(ExpectedCall::RawVendorCmd {
+ Some(ExpectedCall::RawUciCmd {
+ expected_mt,
expected_gid,
expected_oid,
expected_payload,
out,
- }) if expected_gid == gid && expected_oid == oid && expected_payload == payload => {
+ }) if expected_mt == mt
+ && expected_gid == gid
+ && expected_oid == oid
+ && expected_payload == payload =>
+ {
+ self.expect_call_consumed.notify_one();
+ out
+ }
+ Some(call) => {
+ expected_calls.push_front(call);
+ Err(Error::MockUndefined)
+ }
+ None => Err(Error::MockUndefined),
+ }
+ }
+
+ async fn send_data_packet(
+ &self,
+ session_id: SessionId,
+ address: Vec<u8>,
+ dest_end_point: FiraComponent,
+ uci_sequence_num: u8,
+ app_payload_data: Vec<u8>,
+ ) -> Result<()> {
+ let mut expected_calls = self.expected_calls.lock().unwrap();
+ match expected_calls.pop_front() {
+ Some(ExpectedCall::SendDataPacket {
+ expected_session_id,
+ expected_address,
+ expected_dest_end_point,
+ expected_uci_sequence_num,
+ expected_app_payload_data,
+ out,
+ }) if expected_session_id == session_id
+ && expected_address == address
+ && expected_dest_end_point == dest_end_point
+ && expected_uci_sequence_num == uci_sequence_num
+ && expected_app_payload_data == app_payload_data =>
+ {
self.expect_call_consumed.notify_one();
out
}
@@ -805,16 +980,18 @@ enum ExpectedCall {
SessionUpdateControllerMulticastList {
expected_session_id: SessionId,
expected_action: UpdateMulticastListAction,
- expected_controlees: Vec<Controlee>,
+ expected_controlees: Controlees,
notfs: Vec<UciNotification>,
out: Result<()>,
},
- SessionUpdateControllerMulticastListV2 {
+ SessionUpdateDtTagRangingRounds {
+ expected_session_id: u32,
+ expected_ranging_round_indexes: Vec<u8>,
+ out: Result<SessionUpdateDtTagRangingRoundsResponse>,
+ },
+ SessionQueryMaxDataSize {
expected_session_id: SessionId,
- expected_action: UpdateMulticastListAction,
- expected_controlees: ControleesV2,
- notfs: Vec<UciNotification>,
- out: Result<()>,
+ out: Result<u16>,
},
RangeStart {
expected_session_id: SessionId,
@@ -837,10 +1014,19 @@ enum ExpectedCall {
AndroidGetPowerStats {
out: Result<PowerStats>,
},
- RawVendorCmd {
+ RawUciCmd {
+ expected_mt: u32,
expected_gid: u32,
expected_oid: u32,
expected_payload: Vec<u8>,
- out: Result<RawVendorMessage>,
+ out: Result<RawUciMessage>,
+ },
+ SendDataPacket {
+ expected_session_id: SessionId,
+ expected_address: Vec<u8>,
+ expected_dest_end_point: FiraComponent,
+ expected_uci_sequence_num: u8,
+ expected_app_payload_data: Vec<u8>,
+ out: Result<()>,
},
}
diff --git a/src/rust/uwb_core/src/uci/notification.rs b/src/rust/uwb_core/src/uci/notification.rs
index f3507ba..8007158 100644
--- a/src/rust/uwb_core/src/uci/notification.rs
+++ b/src/rust/uwb_core/src/uci/notification.rs
@@ -15,29 +15,31 @@
use std::convert::{TryFrom, TryInto};
use log::{debug, error};
-use num_traits::ToPrimitive;
-use uwb_uci_packets::{parse_diagnostics_ntf, Packet};
+use uwb_uci_packets::{parse_diagnostics_ntf, Packet, UCI_PACKET_HEADER_LEN};
use crate::error::{Error, Result};
+use crate::params::fira_app_config_params::UwbAddress;
use crate::params::uci_packets::{
- ControleeStatus, DeviceState, ExtendedAddressTwoWayRangingMeasurement, RangingMeasurementType,
- RawVendorMessage, ReasonCode, SessionId, SessionState, ShortAddressTwoWayRangingMeasurement,
- StatusCode,
+ ControleeStatus, CreditAvailability, DataRcvStatusCode, DataTransferNtfStatusCode, DeviceState,
+ ExtendedAddressDlTdoaRangingMeasurement, ExtendedAddressOwrAoaRangingMeasurement,
+ ExtendedAddressTwoWayRangingMeasurement, FiraComponent, RangingMeasurementType, RawUciMessage,
+ SessionId, SessionState, ShortAddressDlTdoaRangingMeasurement,
+ ShortAddressOwrAoaRangingMeasurement, ShortAddressTwoWayRangingMeasurement, StatusCode,
};
/// enum of all UCI notifications with structured fields.
#[derive(Debug, Clone, PartialEq)]
pub enum UciNotification {
- /// CoreNotificationPacket equivalent.
+ /// CoreNotification equivalent.
Core(CoreNotification),
- /// SessionNotificationPacket equivalent.
+ /// SessionNotification equivalent.
Session(SessionNotification),
/// UciVendor_X_Notification equivalent.
- Vendor(RawVendorMessage),
+ Vendor(RawUciMessage),
}
/// UCI CoreNotification.
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CoreNotification {
/// DeviceStatusNtf equivalent.
DeviceStatus(DeviceState),
@@ -55,7 +57,7 @@ pub enum SessionNotification {
/// uwb_uci_packets::SessionState.
session_state: SessionState,
/// uwb_uci_packets::Reasoncode.
- reason_code: ReasonCode,
+ reason_code: u8,
},
/// SessionUpdateControllerMulticastListNtf equivalent.
UpdateControllerMulticastList {
@@ -66,8 +68,24 @@ pub enum SessionNotification {
/// list of controlees.
status_list: Vec<ControleeStatus>,
},
- /// (Short/Extended)Mac()RangeDataNtf equivalent
- RangeData(SessionRangeData),
+ /// (Short/Extended)Mac()SessionInfoNtf equivalent
+ SessionInfo(SessionRangeData),
+ /// DataCreditNtf equivalent.
+ DataCredit {
+ /// SessionId : u32
+ session_id: SessionId,
+ /// Credit Availability (for sending Data packets on UWB Session)
+ credit_availability: CreditAvailability,
+ },
+ /// DataTransferStatusNtf equivalent.
+ DataTransferStatus {
+ /// SessionId : u32
+ session_id: SessionId,
+ /// Sequence Number: u8
+ uci_sequence_number: u8,
+ /// Data Transfer Status Code
+ status: DataTransferNtfStatusCode,
+ },
}
/// The session range data.
@@ -99,11 +117,69 @@ pub struct SessionRangeData {
/// The ranging measurements.
#[derive(Debug, Clone, PartialEq)]
pub enum RangingMeasurements {
- /// The measurement with short address.
- Short(Vec<ShortAddressTwoWayRangingMeasurement>),
+ /// A Two-Way measurement with short address.
+ ShortAddressTwoWay(Vec<ShortAddressTwoWayRangingMeasurement>),
- /// The measurement with extended address.
- Extended(Vec<ExtendedAddressTwoWayRangingMeasurement>),
+ /// A Two-Way measurement with extended address.
+ ExtendedAddressTwoWay(Vec<ExtendedAddressTwoWayRangingMeasurement>),
+
+ /// Dl-TDoA measurement with short address.
+ ShortAddressDltdoa(Vec<ShortAddressDlTdoaRangingMeasurement>),
+
+ /// Dl-TDoA measurement with extended address.
+ ExtendedAddressDltdoa(Vec<ExtendedAddressDlTdoaRangingMeasurement>),
+
+ /// OWR for AoA measurement with short address.
+ ShortAddressOwrAoa(ShortAddressOwrAoaRangingMeasurement),
+
+ /// OWR for AoA measurement with extended address.
+ ExtendedAddressOwrAoa(ExtendedAddressOwrAoaRangingMeasurement),
+}
+
+/// The DATA_RCV packet
+#[derive(Debug, Clone)]
+pub struct DataRcvNotification {
+ /// The identifier of the session on which data transfer is happening.
+ pub session_id: SessionId,
+
+ /// The status of the data rx.
+ pub status: DataRcvStatusCode,
+
+ /// The sequence number of the data packet.
+ pub uci_sequence_num: u32,
+
+ /// MacAddress of the sender of the application data.
+ pub source_address: UwbAddress,
+
+ /// Identifier for the source FiraComponent.
+ pub source_fira_component: FiraComponent,
+
+ /// Identifier for the destination FiraComponent.
+ pub dest_fira_component: FiraComponent,
+
+ /// Application Payload Data
+ pub payload: Vec<u8>,
+}
+
+impl TryFrom<uwb_uci_packets::UciDataPacket> for DataRcvNotification {
+ type Error = Error;
+ fn try_from(evt: uwb_uci_packets::UciDataPacket) -> std::result::Result<Self, Self::Error> {
+ match evt.specialize() {
+ uwb_uci_packets::UciDataPacketChild::UciDataRcv(evt) => Ok(DataRcvNotification {
+ session_id: evt.get_session_id(),
+ status: evt.get_status(),
+ uci_sequence_num: evt.get_uci_sequence_number(),
+ source_address: UwbAddress::Extended(evt.get_source_mac_address().to_le_bytes()),
+ source_fira_component: evt.get_source_fira_component(),
+ dest_fira_component: evt.get_dest_fira_component(),
+ payload: evt.get_data().to_vec(),
+ }),
+ _ => {
+ error!("Unknown UciData packet: {:?}", evt);
+ Err(Error::Unknown)
+ }
+ }
+ }
}
impl UciNotification {
@@ -115,16 +191,18 @@ impl UciNotification {
}
}
-impl TryFrom<uwb_uci_packets::UciNotificationPacket> for UciNotification {
+impl TryFrom<uwb_uci_packets::UciNotification> for UciNotification {
type Error = Error;
- fn try_from(
- evt: uwb_uci_packets::UciNotificationPacket,
- ) -> std::result::Result<Self, Self::Error> {
+ fn try_from(evt: uwb_uci_packets::UciNotification) -> std::result::Result<Self, Self::Error> {
use uwb_uci_packets::UciNotificationChild;
match evt.specialize() {
UciNotificationChild::CoreNotification(evt) => Ok(Self::Core(evt.try_into()?)),
- UciNotificationChild::SessionNotification(evt) => Ok(Self::Session(evt.try_into()?)),
- UciNotificationChild::RangingNotification(evt) => Ok(Self::Session(evt.try_into()?)),
+ UciNotificationChild::SessionConfigNotification(evt) => {
+ Ok(Self::Session(evt.try_into()?))
+ }
+ UciNotificationChild::SessionControlNotification(evt) => {
+ Ok(Self::Session(evt.try_into()?))
+ }
UciNotificationChild::AndroidNotification(evt) => evt.try_into(),
UciNotificationChild::UciVendor_9_Notification(evt) => vendor_notification(evt.into()),
UciNotificationChild::UciVendor_A_Notification(evt) => vendor_notification(evt.into()),
@@ -132,18 +210,16 @@ impl TryFrom<uwb_uci_packets::UciNotificationPacket> for UciNotification {
UciNotificationChild::UciVendor_E_Notification(evt) => vendor_notification(evt.into()),
UciNotificationChild::UciVendor_F_Notification(evt) => vendor_notification(evt.into()),
_ => {
- error!("Unknown UciNotificationPacket: {:?}", evt);
+ error!("Unknown UciNotification: {:?}", evt);
Err(Error::Unknown)
}
}
}
}
-impl TryFrom<uwb_uci_packets::CoreNotificationPacket> for CoreNotification {
+impl TryFrom<uwb_uci_packets::CoreNotification> for CoreNotification {
type Error = Error;
- fn try_from(
- evt: uwb_uci_packets::CoreNotificationPacket,
- ) -> std::result::Result<Self, Self::Error> {
+ fn try_from(evt: uwb_uci_packets::CoreNotification) -> std::result::Result<Self, Self::Error> {
use uwb_uci_packets::CoreNotificationChild;
match evt.specialize() {
CoreNotificationChild::DeviceStatusNtf(evt) => {
@@ -151,26 +227,26 @@ impl TryFrom<uwb_uci_packets::CoreNotificationPacket> for CoreNotification {
}
CoreNotificationChild::GenericError(evt) => Ok(Self::GenericError(evt.get_status())),
_ => {
- error!("Unknown CoreNotificationPacket: {:?}", evt);
+ error!("Unknown CoreNotification: {:?}", evt);
Err(Error::Unknown)
}
}
}
}
-impl TryFrom<uwb_uci_packets::SessionNotificationPacket> for SessionNotification {
+impl TryFrom<uwb_uci_packets::SessionConfigNotification> for SessionNotification {
type Error = Error;
fn try_from(
- evt: uwb_uci_packets::SessionNotificationPacket,
+ evt: uwb_uci_packets::SessionConfigNotification,
) -> std::result::Result<Self, Self::Error> {
- use uwb_uci_packets::SessionNotificationChild;
+ use uwb_uci_packets::SessionConfigNotificationChild;
match evt.specialize() {
- SessionNotificationChild::SessionStatusNtf(evt) => Ok(Self::Status {
+ SessionConfigNotificationChild::SessionStatusNtf(evt) => Ok(Self::Status {
session_id: evt.get_session_id(),
session_state: evt.get_session_state(),
reason_code: evt.get_reason_code(),
}),
- SessionNotificationChild::SessionUpdateControllerMulticastListNtf(evt) => {
+ SessionConfigNotificationChild::SessionUpdateControllerMulticastListNtf(evt) => {
Ok(Self::UpdateControllerMulticastList {
session_id: evt.get_session_id(),
remaining_multicast_list_size: evt.get_remaining_multicast_list_size() as usize,
@@ -178,49 +254,114 @@ impl TryFrom<uwb_uci_packets::SessionNotificationPacket> for SessionNotification
})
}
_ => {
- error!("Unknown SessionNotificationPacket: {:?}", evt);
+ error!("Unknown SessionConfigNotification: {:?}", evt);
Err(Error::Unknown)
}
}
}
}
-impl TryFrom<uwb_uci_packets::RangingNotificationPacket> for SessionNotification {
+impl TryFrom<uwb_uci_packets::SessionControlNotification> for SessionNotification {
type Error = Error;
fn try_from(
- evt: uwb_uci_packets::RangingNotificationPacket,
+ evt: uwb_uci_packets::SessionControlNotification,
) -> std::result::Result<Self, Self::Error> {
- use uwb_uci_packets::RangingNotificationChild;
+ use uwb_uci_packets::SessionControlNotificationChild;
match evt.specialize() {
- RangingNotificationChild::RangeDataNtf(evt) => evt.try_into(),
+ SessionControlNotificationChild::SessionInfoNtf(evt) => evt.try_into(),
+ SessionControlNotificationChild::DataCreditNtf(evt) => Ok(Self::DataCredit {
+ session_id: evt.get_session_id(),
+ credit_availability: evt.get_credit_availability(),
+ }),
+ SessionControlNotificationChild::DataTransferStatusNtf(evt) => {
+ Ok(Self::DataTransferStatus {
+ session_id: evt.get_session_id(),
+ uci_sequence_number: evt.get_uci_sequence_number(),
+ status: evt.get_status(),
+ })
+ }
_ => {
- error!("Unknown RangingNotificationPacket: {:?}", evt);
+ error!("Unknown SessionControlNotification: {:?}", evt);
Err(Error::Unknown)
}
}
}
}
-impl TryFrom<uwb_uci_packets::RangeDataNtfPacket> for SessionNotification {
+impl TryFrom<uwb_uci_packets::SessionInfoNtf> for SessionNotification {
type Error = Error;
- fn try_from(
- evt: uwb_uci_packets::RangeDataNtfPacket,
- ) -> std::result::Result<Self, Self::Error> {
- let raw_ranging_data = evt.clone().to_vec();
- use uwb_uci_packets::RangeDataNtfChild;
+ fn try_from(evt: uwb_uci_packets::SessionInfoNtf) -> std::result::Result<Self, Self::Error> {
+ let raw_ranging_data = evt.clone().to_bytes()[UCI_PACKET_HEADER_LEN..].to_vec();
+ use uwb_uci_packets::SessionInfoNtfChild;
let ranging_measurements = match evt.specialize() {
- RangeDataNtfChild::ShortMacTwoWayRangeDataNtf(evt) => {
- RangingMeasurements::Short(evt.get_two_way_ranging_measurements().clone())
+ SessionInfoNtfChild::ShortMacTwoWaySessionInfoNtf(evt) => {
+ RangingMeasurements::ShortAddressTwoWay(
+ evt.get_two_way_ranging_measurements().clone(),
+ )
+ }
+ SessionInfoNtfChild::ExtendedMacTwoWaySessionInfoNtf(evt) => {
+ RangingMeasurements::ExtendedAddressTwoWay(
+ evt.get_two_way_ranging_measurements().clone(),
+ )
}
- RangeDataNtfChild::ExtendedMacTwoWayRangeDataNtf(evt) => {
- RangingMeasurements::Extended(evt.get_two_way_ranging_measurements().clone())
+ SessionInfoNtfChild::ShortMacOwrAoaSessionInfoNtf(evt) => {
+ if evt.get_owr_aoa_ranging_measurements().clone().len() == 1 {
+ RangingMeasurements::ShortAddressOwrAoa(
+ evt.get_owr_aoa_ranging_measurements().clone().pop().unwrap(),
+ )
+ } else {
+ error!("Wrong count of OwrAoA ranging measurements {:?}", evt);
+ return Err(Error::BadParameters);
+ }
+ }
+ SessionInfoNtfChild::ExtendedMacOwrAoaSessionInfoNtf(evt) => {
+ if evt.get_owr_aoa_ranging_measurements().clone().len() == 1 {
+ RangingMeasurements::ExtendedAddressOwrAoa(
+ evt.get_owr_aoa_ranging_measurements().clone().pop().unwrap(),
+ )
+ } else {
+ error!("Wrong count of OwrAoA ranging measurements {:?}", evt);
+ return Err(Error::BadParameters);
+ }
+ }
+ SessionInfoNtfChild::ShortMacDlTDoASessionInfoNtf(evt) => {
+ match ShortAddressDlTdoaRangingMeasurement::parse(
+ evt.get_dl_tdoa_measurements(),
+ evt.get_no_of_ranging_measurements(),
+ ) {
+ Some(v) => {
+ if v.len() == evt.get_no_of_ranging_measurements().into() {
+ RangingMeasurements::ShortAddressDltdoa(v)
+ } else {
+ error!("Wrong count of ranging measurements {:?}", evt);
+ return Err(Error::BadParameters);
+ }
+ }
+ None => return Err(Error::BadParameters),
+ }
+ }
+ SessionInfoNtfChild::ExtendedMacDlTDoASessionInfoNtf(evt) => {
+ match ExtendedAddressDlTdoaRangingMeasurement::parse(
+ evt.get_dl_tdoa_measurements(),
+ evt.get_no_of_ranging_measurements(),
+ ) {
+ Some(v) => {
+ if v.len() == evt.get_no_of_ranging_measurements().into() {
+ RangingMeasurements::ExtendedAddressDltdoa(v)
+ } else {
+ error!("Wrong count of ranging measurements {:?}", evt);
+ return Err(Error::BadParameters);
+ }
+ }
+ None => return Err(Error::BadParameters),
+ }
}
_ => {
- error!("Unknown RangeDataNtfPacket: {:?}", evt);
+ error!("Unknown SessionInfoNtf: {:?}", evt);
return Err(Error::Unknown);
}
};
- Ok(Self::RangeData(SessionRangeData {
+ Ok(Self::SessionInfo(SessionRangeData {
sequence_number: evt.get_sequence_number(),
session_id: evt.get_session_id(),
current_ranging_interval_ms: evt.get_current_ranging_interval(),
@@ -232,10 +373,10 @@ impl TryFrom<uwb_uci_packets::RangeDataNtfPacket> for SessionNotification {
}
}
-impl TryFrom<uwb_uci_packets::AndroidNotificationPacket> for UciNotification {
+impl TryFrom<uwb_uci_packets::AndroidNotification> for UciNotification {
type Error = Error;
fn try_from(
- evt: uwb_uci_packets::AndroidNotificationPacket,
+ evt: uwb_uci_packets::AndroidNotification,
) -> std::result::Result<Self, Self::Error> {
use uwb_uci_packets::AndroidNotificationChild;
@@ -243,27 +384,21 @@ impl TryFrom<uwb_uci_packets::AndroidNotificationPacket> for UciNotification {
if let AndroidNotificationChild::AndroidRangeDiagnosticsNtf(ntf) = evt.specialize() {
debug!("Received diagnostic packet: {:?}", parse_diagnostics_ntf(ntf));
} else {
- error!("Received unknown AndroidNotificationPacket: {:?}", evt);
+ error!("Received unknown AndroidNotification: {:?}", evt);
}
Err(Error::Unknown)
}
}
-fn vendor_notification(evt: uwb_uci_packets::UciNotificationPacket) -> Result<UciNotification> {
- Ok(UciNotification::Vendor(RawVendorMessage {
- gid: evt.get_group_id().to_u32().ok_or_else(|| {
- error!("Failed to get gid from packet: {:?}", evt);
- Error::Unknown
- })?,
- oid: evt.get_opcode().to_u32().ok_or_else(|| {
- error!("Failed to get opcode from packet: {:?}", evt);
- Error::Unknown
- })?,
+fn vendor_notification(evt: uwb_uci_packets::UciNotification) -> Result<UciNotification> {
+ Ok(UciNotification::Vendor(RawUciMessage {
+ gid: evt.get_group_id().into(),
+ oid: evt.get_opcode().into(),
payload: get_vendor_uci_payload(evt)?,
}))
}
-fn get_vendor_uci_payload(evt: uwb_uci_packets::UciNotificationPacket) -> Result<Vec<u8>> {
+fn get_vendor_uci_payload(evt: uwb_uci_packets::UciNotification) -> Result<Vec<u8>> {
match evt.specialize() {
uwb_uci_packets::UciNotificationChild::UciVendor_9_Notification(evt) => {
match evt.specialize() {
@@ -315,12 +450,14 @@ fn get_vendor_uci_payload(evt: uwb_uci_packets::UciNotificationPacket) -> Result
#[cfg(test)]
mod tests {
use super::*;
+ use crate::params::uci_packets::OwrAoaStatusCode;
+
#[test]
fn test_ranging_measurements_trait() {
- let empty_short_ranging_measurements = RangingMeasurements::Short(vec![]);
+ let empty_short_ranging_measurements = RangingMeasurements::ShortAddressTwoWay(vec![]);
assert_eq!(empty_short_ranging_measurements, empty_short_ranging_measurements);
- let extended_ranging_measurements =
- RangingMeasurements::Extended(vec![ExtendedAddressTwoWayRangingMeasurement {
+ let extended_ranging_measurements = RangingMeasurements::ExtendedAddressTwoWay(vec![
+ ExtendedAddressTwoWayRangingMeasurement {
mac_address: 0x1234_5678_90ab,
status: StatusCode::UciStatusOk,
nlos: 0,
@@ -335,10 +472,12 @@ mod tests {
aoa_destination_elevation_fom: 12,
slot_index: 0,
rssi: u8::MAX,
- }]);
+ },
+ ]);
let extended_ranging_measurements_copy = extended_ranging_measurements.clone();
assert_eq!(extended_ranging_measurements, extended_ranging_measurements_copy);
- let empty_extended_ranging_measurements = RangingMeasurements::Extended(vec![]);
+ let empty_extended_ranging_measurements =
+ RangingMeasurements::ExtendedAddressTwoWay(vec![]);
assert_eq!(empty_short_ranging_measurements, empty_short_ranging_measurements);
//short and extended measurements are unequal even if both are empty:
assert_ne!(empty_short_ranging_measurements, empty_extended_ranging_measurements);
@@ -350,7 +489,7 @@ mod tests {
}
.build();
let core_notification =
- uwb_uci_packets::CoreNotificationPacket::try_from(generic_error_packet).unwrap();
+ uwb_uci_packets::CoreNotification::try_from(generic_error_packet).unwrap();
let core_notification = CoreNotification::try_from(core_notification).unwrap();
let uci_notification_from_generic_error = UciNotification::Core(core_notification);
assert_eq!(
@@ -367,7 +506,7 @@ mod tests {
}
.build();
let core_notification =
- uwb_uci_packets::CoreNotificationPacket::try_from(device_status_ntf_packet).unwrap();
+ uwb_uci_packets::CoreNotification::try_from(device_status_ntf_packet).unwrap();
let uci_notification = CoreNotification::try_from(core_notification).unwrap();
let uci_notification_from_device_status_ntf = UciNotification::Core(uci_notification);
assert_eq!(
@@ -377,8 +516,9 @@ mod tests {
))
);
}
+
#[test]
- fn test_session_notification_casting_from_extended_mac_two_way_range_data_ntf() {
+ fn test_session_notification_casting_from_extended_mac_two_way_session_info_ntf() {
let extended_measurement = uwb_uci_packets::ExtendedAddressTwoWayRangingMeasurement {
mac_address: 0x1234_5678_90ab,
status: StatusCode::UciStatusOk,
@@ -395,30 +535,33 @@ mod tests {
slot_index: 0,
rssi: u8::MAX,
};
- let extended_two_way_range_data_ntf =
- uwb_uci_packets::ExtendedMacTwoWayRangeDataNtfBuilder {
+ let extended_two_way_session_info_ntf =
+ uwb_uci_packets::ExtendedMacTwoWaySessionInfoNtfBuilder {
sequence_number: 0x10,
session_id: 0x11,
rcr_indicator: 0x12,
current_ranging_interval: 0x13,
two_way_ranging_measurements: vec![extended_measurement.clone()],
+ vendor_data: vec![],
}
.build();
- let raw_ranging_data = extended_two_way_range_data_ntf.clone().to_vec();
+ let raw_ranging_data =
+ extended_two_way_session_info_ntf.clone().to_bytes()[UCI_PACKET_HEADER_LEN..].to_vec();
let range_notification =
- uwb_uci_packets::RangingNotificationPacket::try_from(extended_two_way_range_data_ntf)
- .unwrap();
+ uwb_uci_packets::SessionInfoNtf::try_from(extended_two_way_session_info_ntf).unwrap();
let session_notification = SessionNotification::try_from(range_notification).unwrap();
- let uci_notification_from_extended_two_way_range_data_ntf =
+ let uci_notification_from_extended_two_way_session_info_ntf =
UciNotification::Session(session_notification);
assert_eq!(
- uci_notification_from_extended_two_way_range_data_ntf,
- UciNotification::Session(SessionNotification::RangeData(SessionRangeData {
+ uci_notification_from_extended_two_way_session_info_ntf,
+ UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
sequence_number: 0x10,
session_id: 0x11,
ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::TwoWay,
current_ranging_interval_ms: 0x13,
- ranging_measurements: RangingMeasurements::Extended(vec![extended_measurement]),
+ ranging_measurements: RangingMeasurements::ExtendedAddressTwoWay(vec![
+ extended_measurement
+ ]),
rcr_indicator: 0x12,
raw_ranging_data,
}))
@@ -426,7 +569,7 @@ mod tests {
}
#[test]
- fn test_session_notification_casting_from_short_mac_two_way_range_data_ntf() {
+ fn test_session_notification_casting_from_short_mac_two_way_session_info_ntf() {
let short_measurement = uwb_uci_packets::ShortAddressTwoWayRangingMeasurement {
mac_address: 0x1234,
status: StatusCode::UciStatusOk,
@@ -443,29 +586,121 @@ mod tests {
slot_index: 0,
rssi: u8::MAX,
};
- let short_two_way_range_data_ntf = uwb_uci_packets::ShortMacTwoWayRangeDataNtfBuilder {
+ let short_two_way_session_info_ntf = uwb_uci_packets::ShortMacTwoWaySessionInfoNtfBuilder {
sequence_number: 0x10,
session_id: 0x11,
rcr_indicator: 0x12,
current_ranging_interval: 0x13,
two_way_ranging_measurements: vec![short_measurement.clone()],
+ vendor_data: vec![0x02, 0x01],
}
.build();
- let raw_ranging_data = short_two_way_range_data_ntf.clone().to_vec();
+ let raw_ranging_data =
+ short_two_way_session_info_ntf.clone().to_bytes()[UCI_PACKET_HEADER_LEN..].to_vec();
let range_notification =
- uwb_uci_packets::RangingNotificationPacket::try_from(short_two_way_range_data_ntf)
- .unwrap();
+ uwb_uci_packets::SessionInfoNtf::try_from(short_two_way_session_info_ntf).unwrap();
let session_notification = SessionNotification::try_from(range_notification).unwrap();
- let uci_notification_from_short_two_way_range_data_ntf =
+ let uci_notification_from_short_two_way_session_info_ntf =
UciNotification::Session(session_notification);
assert_eq!(
- uci_notification_from_short_two_way_range_data_ntf,
- UciNotification::Session(SessionNotification::RangeData(SessionRangeData {
+ uci_notification_from_short_two_way_session_info_ntf,
+ UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
sequence_number: 0x10,
session_id: 0x11,
ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::TwoWay,
current_ranging_interval_ms: 0x13,
- ranging_measurements: RangingMeasurements::Short(vec![short_measurement]),
+ ranging_measurements: RangingMeasurements::ShortAddressTwoWay(vec![
+ short_measurement
+ ]),
+ rcr_indicator: 0x12,
+ raw_ranging_data,
+ }))
+ );
+ }
+
+ #[test]
+ fn test_session_notification_casting_from_extended_mac_owr_aoa_session_info_ntf() {
+ let extended_measurement = uwb_uci_packets::ExtendedAddressOwrAoaRangingMeasurement {
+ mac_address: 0x1234_5678_90ab,
+ status: OwrAoaStatusCode::UciStatusSuccess,
+ nlos: 0,
+ frame_sequence_number: 1,
+ block_index: 1,
+ aoa_azimuth: 5,
+ aoa_azimuth_fom: 6,
+ aoa_elevation: 7,
+ aoa_elevation_fom: 8,
+ };
+ let extended_owr_aoa_session_info_ntf =
+ uwb_uci_packets::ExtendedMacOwrAoaSessionInfoNtfBuilder {
+ sequence_number: 0x10,
+ session_id: 0x11,
+ rcr_indicator: 0x12,
+ current_ranging_interval: 0x13,
+ owr_aoa_ranging_measurements: vec![extended_measurement.clone()],
+ vendor_data: vec![],
+ }
+ .build();
+ let raw_ranging_data =
+ extended_owr_aoa_session_info_ntf.clone().to_bytes()[UCI_PACKET_HEADER_LEN..].to_vec();
+ let range_notification =
+ uwb_uci_packets::SessionInfoNtf::try_from(extended_owr_aoa_session_info_ntf).unwrap();
+ let session_notification = SessionNotification::try_from(range_notification).unwrap();
+ let uci_notification_from_extended_owr_aoa_session_info_ntf =
+ UciNotification::Session(session_notification);
+ assert_eq!(
+ uci_notification_from_extended_owr_aoa_session_info_ntf,
+ UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
+ sequence_number: 0x10,
+ session_id: 0x11,
+ ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::OwrAoa,
+ current_ranging_interval_ms: 0x13,
+ ranging_measurements: RangingMeasurements::ExtendedAddressOwrAoa(
+ extended_measurement
+ ),
+ rcr_indicator: 0x12,
+ raw_ranging_data,
+ }))
+ );
+ }
+
+ #[test]
+ fn test_session_notification_casting_from_short_mac_owr_aoa_session_info_ntf() {
+ let short_measurement = uwb_uci_packets::ShortAddressOwrAoaRangingMeasurement {
+ mac_address: 0x1234,
+ status: OwrAoaStatusCode::UciStatusSuccess,
+ nlos: 0,
+ frame_sequence_number: 1,
+ block_index: 1,
+ aoa_azimuth: 5,
+ aoa_azimuth_fom: 6,
+ aoa_elevation: 7,
+ aoa_elevation_fom: 8,
+ };
+ let short_owr_aoa_session_info_ntf = uwb_uci_packets::ShortMacOwrAoaSessionInfoNtfBuilder {
+ sequence_number: 0x10,
+ session_id: 0x11,
+ rcr_indicator: 0x12,
+ current_ranging_interval: 0x13,
+ owr_aoa_ranging_measurements: vec![short_measurement.clone()],
+ vendor_data: vec![],
+ }
+ .build();
+ let raw_ranging_data =
+ short_owr_aoa_session_info_ntf.clone().to_bytes()[UCI_PACKET_HEADER_LEN..].to_vec();
+ let range_notification =
+ uwb_uci_packets::SessionInfoNtf::try_from(short_owr_aoa_session_info_ntf).unwrap();
+ let session_notification = SessionNotification::try_from(range_notification).unwrap();
+ let uci_notification_from_short_owr_aoa_session_info_ntf =
+ UciNotification::Session(session_notification);
+ assert_eq!(
+ uci_notification_from_short_owr_aoa_session_info_ntf,
+ UciNotification::Session(SessionNotification::SessionInfo(SessionRangeData {
+ sequence_number: 0x10,
+ session_id: 0x11,
+ ranging_measurement_type: uwb_uci_packets::RangingMeasurementType::OwrAoa,
+ current_ranging_interval_ms: 0x13,
+ ranging_measurements: RangingMeasurements::ShortAddressOwrAoa(short_measurement),
rcr_indicator: 0x12,
raw_ranging_data,
}))
@@ -477,11 +712,12 @@ mod tests {
let session_status_ntf = uwb_uci_packets::SessionStatusNtfBuilder {
session_id: 0x20,
session_state: uwb_uci_packets::SessionState::SessionStateActive,
- reason_code: uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands,
+ reason_code: uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands
+ .into(),
}
.build();
let session_notification_packet =
- uwb_uci_packets::SessionNotificationPacket::try_from(session_status_ntf).unwrap();
+ uwb_uci_packets::SessionConfigNotification::try_from(session_status_ntf).unwrap();
let session_notification =
SessionNotification::try_from(session_notification_packet).unwrap();
let uci_notification_from_session_status_ntf =
@@ -491,7 +727,8 @@ mod tests {
UciNotification::Session(SessionNotification::Status {
session_id: 0x20,
session_state: uwb_uci_packets::SessionState::SessionStateActive,
- reason_code: uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands,
+ reason_code: uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands
+ .into(),
})
);
}
@@ -516,7 +753,7 @@ mod tests {
controlee_status: vec![controlee_status.clone(), another_controlee_status.clone()],
}
.build();
- let session_notification_packet = uwb_uci_packets::SessionNotificationPacket::try_from(
+ let session_notification_packet = uwb_uci_packets::SessionConfigNotification::try_from(
session_update_controller_multicast_list_ntf,
)
.unwrap();
@@ -537,11 +774,11 @@ mod tests {
#[test]
#[allow(non_snake_case)] //override snake case for vendor_A
fn test_vendor_notification_casting() {
- let vendor_9_empty_notification: uwb_uci_packets::UciNotificationPacket =
+ let vendor_9_empty_notification: uwb_uci_packets::UciNotification =
uwb_uci_packets::UciVendor_9_NotificationBuilder { opcode: 0x40, payload: None }
.build()
.into();
- let vendor_A_nonempty_notification: uwb_uci_packets::UciNotificationPacket =
+ let vendor_A_nonempty_notification: uwb_uci_packets::UciNotification =
uwb_uci_packets::UciVendor_A_NotificationBuilder {
opcode: 0x41,
payload: Some(bytes::Bytes::from_static(b"Placeholder notification.")),
@@ -554,7 +791,7 @@ mod tests {
UciNotification::try_from(vendor_A_nonempty_notification).unwrap();
assert_eq!(
uci_notification_from_vendor_9,
- UciNotification::Vendor(RawVendorMessage {
+ UciNotification::Vendor(RawUciMessage {
gid: 0x9, // per enum GroupId in uci_packets.pdl
oid: 0x40,
payload: vec![],
@@ -562,7 +799,7 @@ mod tests {
);
assert_eq!(
uci_notification_from_vendor_A,
- UciNotification::Vendor(RawVendorMessage {
+ UciNotification::Vendor(RawUciMessage {
gid: 0xa,
oid: 0x41,
payload: b"Placeholder notification.".to_owned().into(),
diff --git a/src/rust/uwb_core/src/uci/pcapng_block.rs b/src/rust/uwb_core/src/uci/pcapng_block.rs
index c94ddac..6fcc670 100644
--- a/src/rust/uwb_core/src/uci/pcapng_block.rs
+++ b/src/rust/uwb_core/src/uci/pcapng_block.rs
@@ -143,7 +143,7 @@ pub struct InterfaceDescriptionBlockBuilder {
impl Default for InterfaceDescriptionBlockBuilder {
fn default() -> Self {
Self {
- link_type: 293, // USB 2.0 Low Speed
+ link_type: 299, // FiRa UCI
snap_len: 0, // unlimited
block_options: vec![],
}
@@ -422,7 +422,7 @@ mod tests {
#[test]
fn test_interface_description_block_with_options_build() {
let comment_opt = BlockOption::new(0x1, "ABCDEF".to_owned().into_bytes());
- let link_type: u16 = 293; // 0x125
+ let link_type: u16 = 299; // 0x12b
let snap_len: u32 = 0;
let interface_description_block = InterfaceDescriptionBlockBuilder::new()
.link_type(link_type)
@@ -433,7 +433,7 @@ mod tests {
let expected_block: Vec<u8> = vec![
0x01, 0x00, 0x00, 0x00, // block type
0x24, 0x00, 0x00, 0x00, // block length
- 0x25, 0x01, 0x00, 0x00, // link type, reserved
+ 0x2b, 0x01, 0x00, 0x00, // link type, reserved
0x00, 0x00, 0x00, 0x00, // SnapLen
0x01, 0x00, 0x06, 0x00, // option code, padded length
0x41, 0x42, 0x43, 0x44, // option (ABCD)
diff --git a/src/rust/uwb_core/src/uci/pcapng_uci_logger_factory.rs b/src/rust/uwb_core/src/uci/pcapng_uci_logger_factory.rs
index a00018b..04e1ef4 100644
--- a/src/rust/uwb_core/src/uci/pcapng_uci_logger_factory.rs
+++ b/src/rust/uwb_core/src/uci/pcapng_uci_logger_factory.rs
@@ -331,7 +331,7 @@ impl FileFactory {
fn build_empty_file(&mut self) -> Option<BufferedFile> {
self.rotate_file()?;
let file_path = self.get_file_path(0);
- BufferedFile::new(&file_path, self.buffer_size)
+ BufferedFile::new(&self.log_directory, &file_path, self.buffer_size)
}
/// get file path for log files of given index.
@@ -376,12 +376,21 @@ struct BufferedFile {
impl BufferedFile {
/// Constructor.
- pub fn new(file_path: &Path, buffer_size: usize) -> Option<Self> {
+ pub fn new(log_dir: &Path, file_path: &Path, buffer_size: usize) -> Option<Self> {
if file_path.is_file() {
if let Err(e) = fs::remove_file(file_path) {
error!("UCI Log: failed to remove {}: {:?}", file_path.display(), e);
};
}
+ if !log_dir.is_dir() {
+ if let Err(e) = fs::create_dir_all(log_dir) {
+ error!(
+ "UCI Log: failed to create log directory {}. Error: {:?}",
+ log_dir.display(),
+ e
+ );
+ }
+ }
let file = match fs::OpenOptions::new().write(true).create_new(true).open(file_path) {
Ok(f) => f,
Err(e) => {
@@ -486,7 +495,35 @@ mod tests {
}
// Expect no log file created as no packet is received.
let log_path = dir.as_ref().to_owned().join("log.pcapng");
- assert!(fs::read(&log_path).is_err());
+ assert!(fs::read(log_path).is_err());
+ }
+
+ #[test]
+ fn test_no_preexisting_dir_created() {
+ let dir_root = Path::new("./uwb_test_dir_123");
+ let dir = dir_root.join("this/path/doesnt/exist");
+ {
+ let runtime = Builder::new_multi_thread().enable_all().build().unwrap();
+ let mut file_manager = PcapngUciLoggerFactoryBuilder::new()
+ .buffer_size(1024)
+ .filename_prefix("log".to_owned())
+ .log_path(dir.clone())
+ .runtime_handle(runtime.handle().to_owned())
+ .build()
+ .unwrap();
+ let mut logger_0 = file_manager.build_logger("logger 0").unwrap();
+ let packet_0 = UciVendor_A_NotificationBuilder { opcode: 0, payload: None }.build();
+ logger_0.log_uci_control_packet(packet_0.into());
+ // Sleep needed to guarantee handling pending logs before runtime goes out of scope.
+ thread::sleep(time::Duration::from_millis(10));
+ }
+ // Expect the dir was created.
+ assert!(dir.is_dir());
+ // Expect the log file exists.
+ let log_path = dir.join("log.pcapng");
+ assert!(log_path.is_file());
+ // Clear test dir
+ let _ = fs::remove_dir_all(dir_root);
}
#[test]
@@ -503,19 +540,19 @@ mod tests {
.unwrap();
let mut logger_0 = file_manager.build_logger("logger 0").unwrap();
let packet_0 = UciVendor_A_NotificationBuilder { opcode: 0, payload: None }.build();
- logger_0.log_uci_packet(packet_0.into());
+ logger_0.log_uci_control_packet(packet_0.into());
let mut logger_1 = file_manager.build_logger("logger 1").unwrap();
let packet_1 = UciVendor_A_NotificationBuilder { opcode: 1, payload: None }.build();
- logger_1.log_uci_packet(packet_1.into());
+ logger_1.log_uci_control_packet(packet_1.into());
let packet_2 = UciVendor_A_NotificationBuilder { opcode: 2, payload: None }.build();
- logger_0.log_uci_packet(packet_2.into());
+ logger_0.log_uci_control_packet(packet_2.into());
// Sleep needed to guarantee handling pending logs before runtime goes out of scope.
thread::sleep(time::Duration::from_millis(10));
}
// Expect file log.pcapng consist of SHB->IDB(logger 0)->EPB(packet 0)->IDB(logger 1)
// ->EPB(packet 1)->EPB(packet 2)
let log_path = dir.as_ref().to_owned().join("log.pcapng");
- let log_content = fs::read(&log_path).unwrap();
+ let log_content = fs::read(log_path).unwrap();
let block_info = get_block_info(log_content).unwrap();
assert_eq!(block_info.len(), 6);
assert_eq!(block_info[0].0, 0x0A0D_0D0A); // SHB
@@ -541,12 +578,12 @@ mod tests {
.unwrap();
let mut logger_0 = file_manager_140.build_logger("logger 0").unwrap();
let packet_0 = UciVendor_A_NotificationBuilder { opcode: 0, payload: None }.build();
- logger_0.log_uci_packet(packet_0.into());
+ logger_0.log_uci_control_packet(packet_0.into());
let mut logger_1 = file_manager_140.build_logger("logger 1").unwrap();
let packet_1 = UciVendor_A_NotificationBuilder { opcode: 1, payload: None }.build();
- logger_1.log_uci_packet(packet_1.into());
+ logger_1.log_uci_control_packet(packet_1.into());
let packet_2 = UciVendor_A_NotificationBuilder { opcode: 2, payload: None }.build();
- logger_0.log_uci_packet(packet_2.into());
+ logger_0.log_uci_control_packet(packet_2.into());
// Sleep needed to guarantee handling pending logs before runtime goes out of scope.
thread::sleep(time::Duration::from_millis(10));
}
@@ -555,7 +592,7 @@ mod tests {
// File 1: SHB->IDB->IDB->EPB (cannot fit next)
// File 0: SHB->IDB->IDB->EPB
let log_path = dir.as_ref().to_owned().join("log_2.pcapng");
- let log_content = fs::read(&log_path).unwrap();
+ let log_content = fs::read(log_path).unwrap();
let block_info = get_block_info(log_content).unwrap();
assert_eq!(block_info.len(), 4);
assert_eq!(block_info[0].0, 0x0A0D_0D0A); // SHB
@@ -563,7 +600,7 @@ mod tests {
assert_eq!(block_info[2].0, 0x6); // EPB
assert_eq!(block_info[3].0, 0x1); // IDB
let log_path = dir.as_ref().to_owned().join("log_1.pcapng");
- let log_content = fs::read(&log_path).unwrap();
+ let log_content = fs::read(log_path).unwrap();
let block_info = get_block_info(log_content).unwrap();
assert_eq!(block_info.len(), 4);
assert_eq!(block_info[0].0, 0x0A0D_0D0A); // SHB
@@ -571,7 +608,7 @@ mod tests {
assert_eq!(block_info[2].0, 0x1); // IDB
assert_eq!(block_info[3].0, 0x6); // EPB
let log_path = dir.as_ref().to_owned().join("log.pcapng");
- let log_content = fs::read(&log_path).unwrap();
+ let log_content = fs::read(log_path).unwrap();
let block_info = get_block_info(log_content).unwrap();
assert_eq!(block_info.len(), 4);
assert_eq!(block_info[0].0, 0x0A0D_0D0A); // SHB
@@ -595,12 +632,12 @@ mod tests {
.unwrap();
let mut logger_0 = file_manager_144.build_logger("logger 0").unwrap();
let packet_0 = UciVendor_A_NotificationBuilder { opcode: 0, payload: None }.build();
- logger_0.log_uci_packet(packet_0.into());
+ logger_0.log_uci_control_packet(packet_0.into());
let packet_2 = UciVendor_A_NotificationBuilder { opcode: 2, payload: None }.build();
- logger_0.log_uci_packet(packet_2.into());
+ logger_0.log_uci_control_packet(packet_2.into());
let mut logger_1 = file_manager_144.build_logger("logger 1").unwrap();
let packet_1 = UciVendor_A_NotificationBuilder { opcode: 1, payload: None }.build();
- logger_1.log_uci_packet(packet_1.into());
+ logger_1.log_uci_control_packet(packet_1.into());
// Sleep needed to guarantee handling pending logs before runtime goes out of scope.
thread::sleep(time::Duration::from_millis(10));
}
@@ -608,7 +645,7 @@ mod tests {
// File 1: SHB->IDB->EPB->EPB (cannot fit next)
// File 0: SHB->IDB->IDB->EPB
let log_path = dir.as_ref().to_owned().join("log_1.pcapng");
- let log_content = fs::read(&log_path).unwrap();
+ let log_content = fs::read(log_path).unwrap();
let block_info = get_block_info(log_content).unwrap();
assert_eq!(block_info.len(), 4);
assert_eq!(block_info[0].0, 0x0A0D_0D0A); // SHB
@@ -616,7 +653,7 @@ mod tests {
assert_eq!(block_info[2].0, 0x6); // EPB
assert_eq!(block_info[3].0, 0x6); // EPB
let log_path = dir.as_ref().to_owned().join("log.pcapng");
- let log_content = fs::read(&log_path).unwrap();
+ let log_content = fs::read(log_path).unwrap();
let block_info = get_block_info(log_content).unwrap();
assert_eq!(block_info.len(), 4);
assert_eq!(block_info[0].0, 0x0A0D_0D0A); // SHB
@@ -641,12 +678,12 @@ mod tests {
.unwrap();
let mut logger_0 = file_manager_96.build_logger("logger 0").unwrap();
let packet_0 = UciVendor_A_NotificationBuilder { opcode: 0, payload: None }.build();
- logger_0.log_uci_packet(packet_0.into());
+ logger_0.log_uci_control_packet(packet_0.into());
let packet_2 = UciVendor_A_NotificationBuilder { opcode: 2, payload: None }.build();
- logger_0.log_uci_packet(packet_2.into());
+ logger_0.log_uci_control_packet(packet_2.into());
let mut logger_1 = file_manager_96.build_logger("logger 1").unwrap();
let packet_1 = UciVendor_A_NotificationBuilder { opcode: 1, payload: None }.build();
- logger_1.log_uci_packet(packet_1.into());
+ logger_1.log_uci_control_packet(packet_1.into());
}
}
}
diff --git a/src/rust/uwb_core/src/uci/response.rs b/src/rust/uwb_core/src/uci/response.rs
index 50ba610..b0d5b2b 100644
--- a/src/rust/uwb_core/src/uci/response.rs
+++ b/src/rust/uwb_core/src/uci/response.rs
@@ -14,13 +14,11 @@
use std::convert::{TryFrom, TryInto};
-use log::error;
-use num_traits::ToPrimitive;
-
use crate::error::{Error, Result};
use crate::params::uci_packets::{
AppConfigTlv, CapTlv, CoreSetConfigResponse, DeviceConfigTlv, GetDeviceInfoResponse,
- PowerStats, RawVendorMessage, SessionState, SetAppConfigResponse, StatusCode,
+ PowerStats, RawUciMessage, SessionState, SessionUpdateDtTagRangingRoundsResponse,
+ SetAppConfigResponse, StatusCode, UciControlPacket,
};
use crate::uci::error::status_code_to_result;
@@ -42,12 +40,15 @@ pub(super) enum UciResponse {
SessionGetCount(Result<u8>),
SessionGetState(Result<SessionState>),
SessionUpdateControllerMulticastList(Result<()>),
- RangeStart(Result<()>),
- RangeStop(Result<()>),
- RangeGetRangingCount(Result<usize>),
+ SessionUpdateDtTagRangingRounds(Result<SessionUpdateDtTagRangingRoundsResponse>),
+ SessionQueryMaxDataSize(Result<u16>),
+ SessionStart(Result<()>),
+ SessionStop(Result<()>),
+ SessionGetRangingCount(Result<usize>),
AndroidSetCountryCode(Result<()>),
AndroidGetPowerStats(Result<PowerStats>),
- RawVendorCmd(Result<RawVendorMessage>),
+ RawUciCmd(Result<RawUciMessage>),
+ SendUciData(Result<()>),
}
impl UciResponse {
@@ -66,15 +67,20 @@ impl UciResponse {
Self::SessionUpdateControllerMulticastList(result) => {
Self::matches_result_retry(result)
}
- Self::RangeStart(result) => Self::matches_result_retry(result),
- Self::RangeStop(result) => Self::matches_result_retry(result),
- Self::RangeGetRangingCount(result) => Self::matches_result_retry(result),
+ Self::SessionUpdateDtTagRangingRounds(result) => Self::matches_result_retry(result),
+ Self::SessionStart(result) => Self::matches_result_retry(result),
+ Self::SessionStop(result) => Self::matches_result_retry(result),
+ Self::SessionGetRangingCount(result) => Self::matches_result_retry(result),
Self::AndroidSetCountryCode(result) => Self::matches_result_retry(result),
Self::AndroidGetPowerStats(result) => Self::matches_result_retry(result),
- Self::RawVendorCmd(result) => Self::matches_result_retry(result),
+ Self::RawUciCmd(result) => Self::matches_result_retry(result),
Self::CoreSetConfig(resp) => Self::matches_status_retry(&resp.status),
Self::SessionSetAppConfig(resp) => Self::matches_status_retry(&resp.status),
+
+ Self::SessionQueryMaxDataSize(result) => Self::matches_result_retry(result),
+ // TODO(b/273376343): Implement retry logic for Data packet send.
+ Self::SendUciData(_result) => false,
}
}
@@ -86,30 +92,28 @@ impl UciResponse {
}
}
-impl TryFrom<uwb_uci_packets::UciResponsePacket> for UciResponse {
+impl TryFrom<uwb_uci_packets::UciResponse> for UciResponse {
type Error = Error;
- fn try_from(evt: uwb_uci_packets::UciResponsePacket) -> std::result::Result<Self, Self::Error> {
+ fn try_from(evt: uwb_uci_packets::UciResponse) -> std::result::Result<Self, Self::Error> {
use uwb_uci_packets::UciResponseChild;
match evt.specialize() {
UciResponseChild::CoreResponse(evt) => evt.try_into(),
- UciResponseChild::SessionResponse(evt) => evt.try_into(),
- UciResponseChild::RangingResponse(evt) => evt.try_into(),
+ UciResponseChild::SessionConfigResponse(evt) => evt.try_into(),
+ UciResponseChild::SessionControlResponse(evt) => evt.try_into(),
UciResponseChild::AndroidResponse(evt) => evt.try_into(),
- UciResponseChild::UciVendor_9_Response(evt) => vendor_response(evt.into()),
- UciResponseChild::UciVendor_A_Response(evt) => vendor_response(evt.into()),
- UciResponseChild::UciVendor_B_Response(evt) => vendor_response(evt.into()),
- UciResponseChild::UciVendor_E_Response(evt) => vendor_response(evt.into()),
- UciResponseChild::UciVendor_F_Response(evt) => vendor_response(evt.into()),
+ UciResponseChild::UciVendor_9_Response(evt) => raw_response(evt.into()),
+ UciResponseChild::UciVendor_A_Response(evt) => raw_response(evt.into()),
+ UciResponseChild::UciVendor_B_Response(evt) => raw_response(evt.into()),
+ UciResponseChild::UciVendor_E_Response(evt) => raw_response(evt.into()),
+ UciResponseChild::UciVendor_F_Response(evt) => raw_response(evt.into()),
_ => Err(Error::Unknown),
}
}
}
-impl TryFrom<uwb_uci_packets::CoreResponsePacket> for UciResponse {
+impl TryFrom<uwb_uci_packets::CoreResponse> for UciResponse {
type Error = Error;
- fn try_from(
- evt: uwb_uci_packets::CoreResponsePacket,
- ) -> std::result::Result<Self, Self::Error> {
+ fn try_from(evt: uwb_uci_packets::CoreResponse) -> std::result::Result<Self, Self::Error> {
use uwb_uci_packets::CoreResponseChild;
match evt.specialize() {
CoreResponseChild::GetDeviceInfoRsp(evt) => Ok(UciResponse::CoreGetDeviceInfo(
@@ -142,63 +146,78 @@ impl TryFrom<uwb_uci_packets::CoreResponsePacket> for UciResponse {
}
}
-impl TryFrom<uwb_uci_packets::SessionResponsePacket> for UciResponse {
+impl TryFrom<uwb_uci_packets::SessionConfigResponse> for UciResponse {
type Error = Error;
fn try_from(
- evt: uwb_uci_packets::SessionResponsePacket,
+ evt: uwb_uci_packets::SessionConfigResponse,
) -> std::result::Result<Self, Self::Error> {
- use uwb_uci_packets::SessionResponseChild;
+ use uwb_uci_packets::SessionConfigResponseChild;
match evt.specialize() {
- SessionResponseChild::SessionInitRsp(evt) => {
+ SessionConfigResponseChild::SessionInitRsp(evt) => {
Ok(UciResponse::SessionInit(status_code_to_result(evt.get_status())))
}
- SessionResponseChild::SessionDeinitRsp(evt) => {
+ SessionConfigResponseChild::SessionDeinitRsp(evt) => {
Ok(UciResponse::SessionDeinit(status_code_to_result(evt.get_status())))
}
- SessionResponseChild::SessionGetCountRsp(evt) => Ok(UciResponse::SessionGetCount(
- status_code_to_result(evt.get_status()).map(|_| evt.get_session_count()),
- )),
- SessionResponseChild::SessionGetStateRsp(evt) => Ok(UciResponse::SessionGetState(
- status_code_to_result(evt.get_status()).map(|_| evt.get_session_state()),
- )),
- SessionResponseChild::SessionUpdateControllerMulticastListRsp(evt) => {
+ SessionConfigResponseChild::SessionGetCountRsp(evt) => {
+ Ok(UciResponse::SessionGetCount(
+ status_code_to_result(evt.get_status()).map(|_| evt.get_session_count()),
+ ))
+ }
+ SessionConfigResponseChild::SessionGetStateRsp(evt) => {
+ Ok(UciResponse::SessionGetState(
+ status_code_to_result(evt.get_status()).map(|_| evt.get_session_state()),
+ ))
+ }
+ SessionConfigResponseChild::SessionUpdateControllerMulticastListRsp(evt) => {
Ok(UciResponse::SessionUpdateControllerMulticastList(status_code_to_result(
evt.get_status(),
)))
}
- SessionResponseChild::SessionSetAppConfigRsp(evt) => {
+ SessionConfigResponseChild::SessionUpdateDtTagRangingRoundsRsp(evt) => {
+ Ok(UciResponse::SessionUpdateDtTagRangingRounds(Ok(
+ SessionUpdateDtTagRangingRoundsResponse {
+ status: evt.get_status(),
+ ranging_round_indexes: evt.get_ranging_round_indexes().to_vec(),
+ },
+ )))
+ }
+ SessionConfigResponseChild::SessionSetAppConfigRsp(evt) => {
Ok(UciResponse::SessionSetAppConfig(SetAppConfigResponse {
status: evt.get_status(),
config_status: evt.get_cfg_status().clone(),
}))
}
- SessionResponseChild::SessionGetAppConfigRsp(evt) => {
+ SessionConfigResponseChild::SessionGetAppConfigRsp(evt) => {
Ok(UciResponse::SessionGetAppConfig(
status_code_to_result(evt.get_status()).map(|_| {
evt.get_tlvs().clone().into_iter().map(|tlv| tlv.into()).collect()
}),
))
}
+ SessionConfigResponseChild::SessionQueryMaxDataSizeRsp(evt) => {
+ Ok(UciResponse::SessionQueryMaxDataSize(Ok(evt.get_max_data_size())))
+ }
_ => Err(Error::Unknown),
}
}
}
-impl TryFrom<uwb_uci_packets::RangingResponsePacket> for UciResponse {
+impl TryFrom<uwb_uci_packets::SessionControlResponse> for UciResponse {
type Error = Error;
fn try_from(
- evt: uwb_uci_packets::RangingResponsePacket,
+ evt: uwb_uci_packets::SessionControlResponse,
) -> std::result::Result<Self, Self::Error> {
- use uwb_uci_packets::RangingResponseChild;
+ use uwb_uci_packets::SessionControlResponseChild;
match evt.specialize() {
- RangingResponseChild::RangeStartRsp(evt) => {
- Ok(UciResponse::RangeStart(status_code_to_result(evt.get_status())))
+ SessionControlResponseChild::SessionStartRsp(evt) => {
+ Ok(UciResponse::SessionStart(status_code_to_result(evt.get_status())))
}
- RangingResponseChild::RangeStopRsp(evt) => {
- Ok(UciResponse::RangeStop(status_code_to_result(evt.get_status())))
+ SessionControlResponseChild::SessionStopRsp(evt) => {
+ Ok(UciResponse::SessionStop(status_code_to_result(evt.get_status())))
}
- RangingResponseChild::RangeGetRangingCountRsp(evt) => {
- Ok(UciResponse::RangeGetRangingCount(
+ SessionControlResponseChild::SessionGetRangingCountRsp(evt) => {
+ Ok(UciResponse::SessionGetRangingCount(
status_code_to_result(evt.get_status()).map(|_| evt.get_count() as usize),
))
}
@@ -207,11 +226,9 @@ impl TryFrom<uwb_uci_packets::RangingResponsePacket> for UciResponse {
}
}
-impl TryFrom<uwb_uci_packets::AndroidResponsePacket> for UciResponse {
+impl TryFrom<uwb_uci_packets::AndroidResponse> for UciResponse {
type Error = Error;
- fn try_from(
- evt: uwb_uci_packets::AndroidResponsePacket,
- ) -> std::result::Result<Self, Self::Error> {
+ fn try_from(evt: uwb_uci_packets::AndroidResponse) -> std::result::Result<Self, Self::Error> {
use uwb_uci_packets::AndroidResponseChild;
match evt.specialize() {
AndroidResponseChild::AndroidSetCountryCodeRsp(evt) => {
@@ -227,39 +244,9 @@ impl TryFrom<uwb_uci_packets::AndroidResponsePacket> for UciResponse {
}
}
-fn vendor_response(evt: uwb_uci_packets::UciResponsePacket) -> Result<UciResponse> {
- Ok(UciResponse::RawVendorCmd(Ok(RawVendorMessage {
- gid: evt.get_group_id().to_u32().ok_or(Error::Unknown)?,
- oid: evt.get_opcode().to_u32().ok_or(Error::Unknown)?,
- payload: get_vendor_uci_payload(evt)?,
- })))
-}
-
-fn get_vendor_uci_payload(data: uwb_uci_packets::UciResponsePacket) -> Result<Vec<u8>> {
- match data.specialize() {
- uwb_uci_packets::UciResponseChild::UciVendor_9_Response(evt) => match evt.specialize() {
- uwb_uci_packets::UciVendor_9_ResponseChild::Payload(payload) => Ok(payload.to_vec()),
- uwb_uci_packets::UciVendor_9_ResponseChild::None => Ok(Vec::new()),
- },
- uwb_uci_packets::UciResponseChild::UciVendor_A_Response(evt) => match evt.specialize() {
- uwb_uci_packets::UciVendor_A_ResponseChild::Payload(payload) => Ok(payload.to_vec()),
- uwb_uci_packets::UciVendor_A_ResponseChild::None => Ok(Vec::new()),
- },
- uwb_uci_packets::UciResponseChild::UciVendor_B_Response(evt) => match evt.specialize() {
- uwb_uci_packets::UciVendor_B_ResponseChild::Payload(payload) => Ok(payload.to_vec()),
- uwb_uci_packets::UciVendor_B_ResponseChild::None => Ok(Vec::new()),
- },
- uwb_uci_packets::UciResponseChild::UciVendor_E_Response(evt) => match evt.specialize() {
- uwb_uci_packets::UciVendor_E_ResponseChild::Payload(payload) => Ok(payload.to_vec()),
- uwb_uci_packets::UciVendor_E_ResponseChild::None => Ok(Vec::new()),
- },
- uwb_uci_packets::UciResponseChild::UciVendor_F_Response(evt) => match evt.specialize() {
- uwb_uci_packets::UciVendor_F_ResponseChild::Payload(payload) => Ok(payload.to_vec()),
- uwb_uci_packets::UciVendor_F_ResponseChild::None => Ok(Vec::new()),
- },
- _ => {
- error!("Invalid vendor response with gid {:?}", data.get_group_id());
- Err(Error::Unknown)
- }
- }
+fn raw_response(evt: uwb_uci_packets::UciResponse) -> Result<UciResponse> {
+ let gid: u32 = evt.get_group_id().into();
+ let oid: u32 = evt.get_opcode().into();
+ let packet: UciControlPacket = evt.into();
+ Ok(UciResponse::RawUciCmd(Ok(RawUciMessage { gid, oid, payload: packet.to_raw_payload() })))
}
diff --git a/src/rust/uwb_core/src/uci/timeout_uci_hal.rs b/src/rust/uwb_core/src/uci/timeout_uci_hal.rs
index 9a660ff..53c1bcb 100644
--- a/src/rust/uwb_core/src/uci/timeout_uci_hal.rs
+++ b/src/rust/uwb_core/src/uci/timeout_uci_hal.rs
@@ -24,7 +24,9 @@ use crate::params::uci_packets::SessionId;
use crate::uci::command::UciCommand;
use crate::uci::uci_hal::{UciHal, UciHalPacket};
-const HAL_API_TIMEOUT_MS: u64 = 800;
+const HAL_API_TIMEOUT_MS: u64 = 1000;
+// TODO(b/279175027): Reduce this once vendor fixes their initialization sequence.
+const HAL_OPEN_TIMEOUT_MS: u64 = 20000; // Extra time may be needed for starting UWB stack.
pub(crate) struct TimeoutUciHal<T: UciHal>(T);
@@ -33,8 +35,11 @@ impl<T: UciHal> TimeoutUciHal<T> {
Self(hal)
}
- async fn call_with_timeout(future: impl Future<Output = Result<()>>) -> Result<()> {
- match timeout(Duration::from_millis(HAL_API_TIMEOUT_MS), future).await {
+ async fn call_with_timeout(
+ future: impl Future<Output = Result<()>>,
+ duration: u64,
+ ) -> Result<()> {
+ match timeout(Duration::from_millis(duration), future).await {
Ok(result) => result,
Err(_) => Err(Error::Timeout),
}
@@ -44,23 +49,24 @@ impl<T: UciHal> TimeoutUciHal<T> {
#[async_trait]
impl<T: UciHal> UciHal for TimeoutUciHal<T> {
async fn open(&mut self, packet_sender: mpsc::UnboundedSender<UciHalPacket>) -> Result<()> {
- Self::call_with_timeout(self.0.open(packet_sender)).await
+ Self::call_with_timeout(self.0.open(packet_sender), HAL_OPEN_TIMEOUT_MS).await
}
async fn close(&mut self) -> Result<()> {
- Self::call_with_timeout(self.0.close()).await
+ Self::call_with_timeout(self.0.close(), HAL_API_TIMEOUT_MS).await
}
async fn notify_session_initialized(&mut self, session_id: SessionId) -> Result<()> {
- Self::call_with_timeout(self.0.notify_session_initialized(session_id)).await
+ Self::call_with_timeout(self.0.notify_session_initialized(session_id), HAL_API_TIMEOUT_MS)
+ .await
}
async fn send_command(&mut self, cmd: UciCommand) -> Result<()> {
- Self::call_with_timeout(self.0.send_command(cmd)).await
+ Self::call_with_timeout(self.0.send_command(cmd), HAL_API_TIMEOUT_MS).await
}
async fn send_packet(&mut self, packet: UciHalPacket) -> Result<()> {
- Self::call_with_timeout(self.0.send_packet(packet)).await
+ Self::call_with_timeout(self.0.send_packet(packet), HAL_API_TIMEOUT_MS).await
}
}
diff --git a/src/rust/uwb_core/src/uci/uci_hal.rs b/src/rust/uwb_core/src/uci/uci_hal.rs
index aaf6d22..1153872 100644
--- a/src/rust/uwb_core/src/uci/uci_hal.rs
+++ b/src/rust/uwb_core/src/uci/uci_hal.rs
@@ -18,7 +18,7 @@ use std::convert::TryInto;
use async_trait::async_trait;
use tokio::sync::mpsc;
-use uwb_uci_packets::{Packet, UciCommandPacket, UciPacketHalPacket, UciPacketPacket};
+use uwb_uci_packets::{Packet, UciControlPacket, UciControlPacketHal};
use crate::error::Result;
use crate::params::uci_packets::SessionId;
@@ -37,7 +37,7 @@ pub trait UciHal: 'static + Send {
///
/// All the other API should be called after the open() completes successfully. Once the method
/// completes successfully, the UciHal instance should store |packet_sender| and send the UCI
- /// packets (responses or notifications) back to the caller via the |packet_sender|.
+ /// packets (responses, notifications, data) back to the caller via the |packet_sender|.
async fn open(&mut self, packet_sender: mpsc::UnboundedSender<UciHalPacket>) -> Result<()>;
/// Close the UCI HAL.
@@ -54,9 +54,8 @@ pub trait UciHal: 'static + Send {
// A UCI command message may consist of multiple UCI packets when the payload is over the
// maximum packet size. We convert the command into list of UciHalPacket, then send the
// packets via send_packet().
- let packet: UciCommandPacket = cmd.try_into()?;
- let packet: UciPacketPacket = packet.into();
- let fragmented_packets: Vec<UciPacketHalPacket> = packet.into();
+ let packet: UciControlPacket = cmd.try_into()?;
+ let fragmented_packets: Vec<UciControlPacketHal> = packet.into();
for packet in fragmented_packets.into_iter() {
self.send_packet(packet.to_vec()).await?;
}
@@ -72,6 +71,21 @@ pub trait UciHal: 'static + Send {
}
}
+/// A placeholder implementation for UciHal that do nothing.
+pub struct NopUciHal {}
+#[async_trait]
+impl UciHal for NopUciHal {
+ async fn open(&mut self, _packet_sender: mpsc::UnboundedSender<UciHalPacket>) -> Result<()> {
+ Ok(())
+ }
+ async fn close(&mut self) -> Result<()> {
+ Ok(())
+ }
+ async fn send_packet(&mut self, _packet: UciHalPacket) -> Result<()> {
+ Ok(())
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/rust/uwb_core/src/uci/uci_logger.rs b/src/rust/uwb_core/src/uci/uci_logger.rs
index d29b047..5023d7a 100644
--- a/src/rust/uwb_core/src/uci/uci_logger.rs
+++ b/src/rust/uwb_core/src/uci/uci_logger.rs
@@ -16,9 +16,10 @@
use std::convert::TryFrom;
use uwb_uci_packets::{
- AppConfigTlv, AppConfigTlvType, SessionCommandChild, SessionGetAppConfigRspBuilder,
- SessionResponseChild, SessionSetAppConfigCmdBuilder, UciCommandChild, UciCommandPacket,
- UciPacketPacket, UciResponseChild, UciResponsePacket,
+ AppConfigTlv, AppConfigTlvType, Packet, SessionConfigCommandChild, SessionConfigResponseChild,
+ SessionGetAppConfigRspBuilder, SessionSetAppConfigCmdBuilder, UciCommandChild,
+ UciControlPacket, UciControlPacketChild, UciDataPacket, UciResponse, UciResponseChild,
+ UCI_PACKET_HAL_HEADER_LEN,
};
use crate::error::{Error, Result};
@@ -50,8 +51,11 @@ impl TryFrom<String> for UciLoggerMode {
/// Trait definition for the thread-safe uci logger
pub trait UciLogger: 'static + Send + Sync {
- /// Logs Uci Packet.
- fn log_uci_packet(&mut self, packet: UciPacketPacket);
+ /// Logs Uci Control Packet.
+ fn log_uci_control_packet(&mut self, packet: UciControlPacket);
+ /// Logs Uci Data Packet. This is being passed as a reference since most of the time logging is
+ /// disabled, and so this will avoid copying the data payload.
+ fn log_uci_data_packet(&mut self, packet: &UciDataPacket);
/// Logs hal open event.
fn log_hal_open(&mut self, result: Result<()>);
/// Logs hal close event.
@@ -65,25 +69,28 @@ fn filter_tlv(mut tlv: AppConfigTlv) -> AppConfigTlv {
tlv
}
-fn filter_uci_command(cmd: UciCommandPacket) -> UciCommandPacket {
+fn filter_uci_command(cmd: UciControlPacket) -> UciControlPacket {
match cmd.specialize() {
- UciCommandChild::SessionCommand(session_cmd) => match session_cmd.specialize() {
- SessionCommandChild::SessionSetAppConfigCmd(set_config_cmd) => {
- let session_id = set_config_cmd.get_session_id();
- let tlvs = set_config_cmd.get_tlvs().to_owned();
- let filtered_tlvs = tlvs.into_iter().map(filter_tlv).collect();
- SessionSetAppConfigCmdBuilder { session_id, tlvs: filtered_tlvs }.build().into()
- }
- _ => session_cmd.into(),
+ UciControlPacketChild::UciCommand(control_cmd) => match control_cmd.specialize() {
+ UciCommandChild::SessionConfigCommand(session_cmd) => match session_cmd.specialize() {
+ SessionConfigCommandChild::SessionSetAppConfigCmd(set_config_cmd) => {
+ let session_id = set_config_cmd.get_session_id();
+ let tlvs = set_config_cmd.get_tlvs().to_owned();
+ let filtered_tlvs = tlvs.into_iter().map(filter_tlv).collect();
+ SessionSetAppConfigCmdBuilder { session_id, tlvs: filtered_tlvs }.build().into()
+ }
+ _ => session_cmd.into(),
+ },
+ _ => cmd,
},
_ => cmd,
}
}
-fn filter_uci_response(rsp: UciResponsePacket) -> UciResponsePacket {
+fn filter_uci_response(rsp: UciResponse) -> UciResponse {
match rsp.specialize() {
- UciResponseChild::SessionResponse(session_rsp) => match session_rsp.specialize() {
- SessionResponseChild::SessionGetAppConfigRsp(rsp) => {
+ UciResponseChild::SessionConfigResponse(session_rsp) => match session_rsp.specialize() {
+ SessionConfigResponseChild::SessionGetAppConfigRsp(rsp) => {
let status = rsp.get_status();
let tlvs = rsp.get_tlvs().to_owned();
let filtered_tlvs = tlvs.into_iter().map(filter_tlv).collect();
@@ -95,6 +102,20 @@ fn filter_uci_response(rsp: UciResponsePacket) -> UciResponsePacket {
}
}
+// Log only the Data Packet header bytes, so that we don't log any PII (payload bytes).
+fn filter_uci_data(
+ packet: &UciDataPacket,
+) -> std::result::Result<UciDataPacket, uwb_uci_packets::Error> {
+ // Initialize a (zeroed out) Vec to the same length as the data packet, and then copy over
+ // only the Data Packet header bytes into it. This masks out all the payload bytes to 0.
+ let data_packet_bytes: Vec<u8> = packet.clone().to_vec();
+ let mut filtered_data_packet_bytes: Vec<u8> = vec![0; data_packet_bytes.len()];
+ for (i, &b) in data_packet_bytes[..UCI_PACKET_HAL_HEADER_LEN].iter().enumerate() {
+ filtered_data_packet_bytes[i] = b;
+ }
+ UciDataPacket::parse(&filtered_data_packet_bytes)
+}
+
/// Wrapper struct that filters messages feeded to UciLogger.
pub(crate) struct UciLoggerWrapper<T: UciLogger> {
mode: UciLoggerMode,
@@ -127,41 +148,52 @@ impl<T: UciLogger> UciLoggerWrapper<T> {
match self.mode {
UciLoggerMode::Disabled => (),
UciLoggerMode::Unfiltered => {
- if let Ok(packet) = UciCommandPacket::try_from(cmd.clone()) {
- self.logger.log_uci_packet(packet.into());
+ if let Ok(packet) = UciControlPacket::try_from(cmd.clone()) {
+ self.logger.log_uci_control_packet(packet);
};
}
UciLoggerMode::Filtered => {
- if let Ok(packet) = UciCommandPacket::try_from(cmd.clone()) {
- self.logger.log_uci_packet(filter_uci_command(packet).into());
+ if let Ok(packet) = UciControlPacket::try_from(cmd.clone()) {
+ self.logger.log_uci_control_packet(filter_uci_command(packet));
};
}
}
}
- pub fn log_uci_response_or_notification(&mut self, packet: &UciPacketPacket) {
+ pub fn log_uci_response_or_notification(&mut self, packet: &UciControlPacket) {
match self.mode {
UciLoggerMode::Disabled => (),
- UciLoggerMode::Unfiltered => self.logger.log_uci_packet(packet.clone()),
+ UciLoggerMode::Unfiltered => self.logger.log_uci_control_packet(packet.clone()),
UciLoggerMode::Filtered => match packet.clone().specialize() {
- uwb_uci_packets::UciPacketChild::UciResponse(packet) => {
- self.logger.log_uci_packet(filter_uci_response(packet).into())
+ uwb_uci_packets::UciControlPacketChild::UciResponse(packet) => {
+ self.logger.log_uci_control_packet(filter_uci_response(packet).into())
}
- uwb_uci_packets::UciPacketChild::UciNotification(packet) => {
- self.logger.log_uci_packet(packet.into())
+ uwb_uci_packets::UciControlPacketChild::UciNotification(packet) => {
+ self.logger.log_uci_control_packet(packet.into())
}
_ => (),
},
}
}
+
+ pub fn log_uci_data(&mut self, packet: &UciDataPacket) {
+ if self.mode == UciLoggerMode::Disabled {
+ return;
+ }
+ if let Ok(filtered_packet) = filter_uci_data(packet) {
+ self.logger.log_uci_data_packet(&filtered_packet);
+ }
+ }
}
-/// A null UciLogger implementation that does nothing.
+/// A placeholder UciLogger implementation that does nothing.
#[derive(Default)]
-pub struct UciLoggerNull {}
+pub struct NopUciLogger {}
+
+impl UciLogger for NopUciLogger {
+ fn log_uci_control_packet(&mut self, _packet: UciControlPacket) {}
-impl UciLogger for UciLoggerNull {
- fn log_uci_packet(&mut self, _packet: UciPacketPacket) {}
+ fn log_uci_data_packet(&mut self, _packet: &UciDataPacket) {}
fn log_hal_open(&mut self, _result: Result<()>) {}
@@ -207,7 +239,7 @@ mod tests {
#[test]
fn test_log_response_filter() -> Result<()> {
- let unfiltered_rsp: UciPacketPacket = SessionGetAppConfigRspBuilder {
+ let unfiltered_rsp: UciControlPacket = SessionGetAppConfigRspBuilder {
status: StatusCode::UciStatusOk,
tlvs: vec![
AppConfigTlv { cfg_id: AppConfigTlvType::StaticStsIv, v: vec![0, 1, 2] },
diff --git a/src/rust/uwb_core/src/uci/uci_logger_factory.rs b/src/rust/uwb_core/src/uci/uci_logger_factory.rs
index aa8d408..7938c77 100644
--- a/src/rust/uwb_core/src/uci/uci_logger_factory.rs
+++ b/src/rust/uwb_core/src/uci/uci_logger_factory.rs
@@ -15,7 +15,7 @@
//! This file defines UciLoggerFactory, which manages the shared log file for multiple UciManager
//! instances.
-use crate::uci::uci_logger::{UciLogger, UciLoggerNull};
+use crate::uci::uci_logger::{NopUciLogger, UciLogger};
/// Trait definition for UciLoggerFactory, which builds UciLoggers that shares a single log file
/// created by this struct.
@@ -31,14 +31,13 @@ pub trait UciLoggerFactory {
fn build_logger(&mut self, chip_id: &str) -> Option<Self::Logger>;
}
-/// The null implementation for UciLoggerFactory.
+/// The UciLoggerFactory implementation that always builds NopUciLogger.
#[derive(Default)]
-pub struct UciLoggerFactoryNull {}
-//UciLoggerFactoryNull builds UciLoggerNull.
-impl UciLoggerFactory for UciLoggerFactoryNull {
- type Logger = UciLoggerNull;
+pub struct NopUciLoggerFactory {}
+impl UciLoggerFactory for NopUciLoggerFactory {
+ type Logger = NopUciLogger;
- fn build_logger(&mut self, _chip_id: &str) -> Option<UciLoggerNull> {
- Some(UciLoggerNull::default())
+ fn build_logger(&mut self, _chip_id: &str) -> Option<NopUciLogger> {
+ Some(NopUciLogger::default())
}
}
diff --git a/src/rust/uwb_core/src/uci/uci_logger_pcapng.rs b/src/rust/uwb_core/src/uci/uci_logger_pcapng.rs
index 9cbdeab..279713b 100644
--- a/src/rust/uwb_core/src/uci/uci_logger_pcapng.rs
+++ b/src/rust/uwb_core/src/uci/uci_logger_pcapng.rs
@@ -15,7 +15,7 @@
//! Implements UciLoggerPcapng, a UciLogger with PCAPNG format log.
use log::warn;
-use uwb_uci_packets::UciPacketPacket;
+use uwb_uci_packets::{UciControlPacket, UciDataPacket};
use crate::uci::pcapng_block::{BlockBuilder, BlockOption, EnhancedPacketBlockBuilder};
use crate::uci::pcapng_uci_logger_factory::LogWriter;
@@ -42,7 +42,7 @@ impl UciLoggerPcapng {
}
impl UciLogger for UciLoggerPcapng {
- fn log_uci_packet(&mut self, packet: UciPacketPacket) {
+ fn log_uci_control_packet(&mut self, packet: UciControlPacket) {
let block_bytes = match EnhancedPacketBlockBuilder::new()
.interface_id(self.interface_id)
.packet(packet.into())
@@ -54,6 +54,18 @@ impl UciLogger for UciLoggerPcapng {
self.send_block_bytes(block_bytes);
}
+ fn log_uci_data_packet(&mut self, packet: &UciDataPacket) {
+ let packet_header_bytes = match EnhancedPacketBlockBuilder::new()
+ .interface_id(self.interface_id)
+ .packet(packet.clone().into())
+ .into_le_bytes()
+ {
+ Some(b) => b,
+ None => return,
+ };
+ self.send_block_bytes(packet_header_bytes);
+ }
+
fn log_hal_open(&mut self, result: crate::error::Result<()>) {
let block_option = match result {
Ok(_) => BlockOption::new(0x1, "HAL OPEN: OKAY".to_owned().into_bytes()),
diff --git a/src/rust/uwb_core/src/uci/uci_manager.rs b/src/rust/uwb_core/src/uci/uci_manager.rs
index f03e9ce..9d05224 100644
--- a/src/rust/uwb_core/src/uci/uci_manager.rs
+++ b/src/rust/uwb_core/src/uci/uci_manager.rs
@@ -23,18 +23,24 @@ use crate::uci::command::UciCommand;
//use crate::uci::error::{Error, Result};
use crate::error::{Error, Result};
use crate::params::uci_packets::{
- AppConfigTlv, AppConfigTlvType, CapTlv, Controlee, ControleesV2, CoreSetConfigResponse,
- CountryCode, DeviceConfigId, DeviceConfigTlv, DeviceState, GetDeviceInfoResponse, PowerStats,
- RawVendorMessage, ResetConfig, SessionId, SessionState, SessionType, SetAppConfigResponse,
- UpdateMulticastListAction,
+ AppConfigTlv, AppConfigTlvType, CapTlv, Controlees, CoreSetConfigResponse, CountryCode,
+ CreditAvailability, DeviceConfigId, DeviceConfigTlv, DeviceState, FiraComponent,
+ GetDeviceInfoResponse, GroupId, MessageType, PowerStats, RawUciMessage, ResetConfig, SessionId,
+ SessionState, SessionType, SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse,
+ UciDataPacket, UciDataPacketHal, UpdateMulticastListAction,
};
+use crate::params::utils::bytes_to_u64;
use crate::uci::message::UciMessage;
-use crate::uci::notification::{CoreNotification, SessionNotification, UciNotification};
+use crate::uci::notification::{
+ CoreNotification, DataRcvNotification, SessionNotification, UciNotification,
+};
use crate::uci::response::UciResponse;
use crate::uci::timeout_uci_hal::TimeoutUciHal;
use crate::uci::uci_hal::{UciHal, UciHalPacket};
use crate::uci::uci_logger::{UciLogger, UciLoggerMode, UciLoggerWrapper};
use crate::utils::{clean_mpsc_receiver, PinSleep};
+use std::collections::{HashMap, VecDeque};
+use uwb_uci_packets::{Packet, RawUciControlPacket, UciDataSnd, UciDefragPacket};
const UCI_TIMEOUT_MS: u64 = 800;
const MAX_RETRY_COUNT: usize = 3;
@@ -42,8 +48,8 @@ const MAX_RETRY_COUNT: usize = 3;
/// The UciManager organizes the state machine of the UWB HAL, and provides the interface which
/// abstracts the UCI commands, responses, and notifications.
#[async_trait]
-pub(crate) trait UciManager: 'static + Send + Clone {
- async fn set_logger_mode(&mut self, logger_mode: UciLoggerMode) -> Result<()>;
+pub trait UciManager: 'static + Send + Sync + Clone {
+ async fn set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()>;
// Set the sendor of the UCI notificaions.
async fn set_core_notification_sender(
&mut self,
@@ -55,84 +61,104 @@ pub(crate) trait UciManager: 'static + Send + Clone {
);
async fn set_vendor_notification_sender(
&mut self,
- vendor_notf_sender: mpsc::UnboundedSender<RawVendorMessage>,
+ vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>,
+ );
+ async fn set_data_rcv_notification_sender(
+ &mut self,
+ data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>,
);
// Open the UCI HAL.
// All the UCI commands should be called after the open_hal() completes successfully.
- async fn open_hal(&mut self) -> Result<()>;
+ async fn open_hal(&self) -> Result<()>;
// Close the UCI HAL.
- async fn close_hal(&mut self, force: bool) -> Result<()>;
+ async fn close_hal(&self, force: bool) -> Result<()>;
// Send the standard UCI Commands.
- async fn device_reset(&mut self, reset_config: ResetConfig) -> Result<()>;
- async fn core_get_device_info(&mut self) -> Result<GetDeviceInfoResponse>;
- async fn core_get_caps_info(&mut self) -> Result<Vec<CapTlv>>;
+ async fn device_reset(&self, reset_config: ResetConfig) -> Result<()>;
+ async fn core_get_device_info(&self) -> Result<GetDeviceInfoResponse>;
+ async fn core_get_caps_info(&self) -> Result<Vec<CapTlv>>;
async fn core_set_config(
- &mut self,
+ &self,
config_tlvs: Vec<DeviceConfigTlv>,
) -> Result<CoreSetConfigResponse>;
async fn core_get_config(
- &mut self,
+ &self,
config_ids: Vec<DeviceConfigId>,
) -> Result<Vec<DeviceConfigTlv>>;
- async fn session_init(
- &mut self,
- session_id: SessionId,
- session_type: SessionType,
- ) -> Result<()>;
- async fn session_deinit(&mut self, session_id: SessionId) -> Result<()>;
+ async fn session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()>;
+ async fn session_deinit(&self, session_id: SessionId) -> Result<()>;
async fn session_set_app_config(
- &mut self,
+ &self,
session_id: SessionId,
config_tlvs: Vec<AppConfigTlv>,
) -> Result<SetAppConfigResponse>;
async fn session_get_app_config(
- &mut self,
+ &self,
session_id: SessionId,
config_ids: Vec<AppConfigTlvType>,
) -> Result<Vec<AppConfigTlv>>;
- async fn session_get_count(&mut self) -> Result<u8>;
- async fn session_get_state(&mut self, session_id: SessionId) -> Result<SessionState>;
+ async fn session_get_count(&self) -> Result<u8>;
+ async fn session_get_state(&self, session_id: SessionId) -> Result<SessionState>;
async fn session_update_controller_multicast_list(
- &mut self,
- session_id: SessionId,
- action: UpdateMulticastListAction,
- controlees: Vec<Controlee>,
- ) -> Result<()>;
- async fn session_update_controller_multicast_list_v2(
- &mut self,
+ &self,
session_id: SessionId,
action: UpdateMulticastListAction,
- controlees: ControleesV2,
+ controlees: Controlees,
) -> Result<()>;
- async fn range_start(&mut self, session_id: SessionId) -> Result<()>;
- async fn range_stop(&mut self, session_id: SessionId) -> Result<()>;
- async fn range_get_ranging_count(&mut self, session_id: SessionId) -> Result<usize>;
+
+ // Update ranging rounds for DT Tag
+ async fn session_update_dt_tag_ranging_rounds(
+ &self,
+ session_id: u32,
+ ranging_round_indexes: Vec<u8>,
+ ) -> Result<SessionUpdateDtTagRangingRoundsResponse>;
+
+ async fn session_query_max_data_size(&self, session_id: SessionId) -> Result<u16>;
+
+ async fn range_start(&self, session_id: SessionId) -> Result<()>;
+ async fn range_stop(&self, session_id: SessionId) -> Result<()>;
+ async fn range_get_ranging_count(&self, session_id: SessionId) -> Result<usize>;
// Send the Android-specific UCI commands
- async fn android_set_country_code(&mut self, country_code: CountryCode) -> Result<()>;
- async fn android_get_power_stats(&mut self) -> Result<PowerStats>;
+ async fn android_set_country_code(&self, country_code: CountryCode) -> Result<()>;
+ async fn android_get_power_stats(&self) -> Result<PowerStats>;
- // Send a raw vendor command.
- async fn raw_vendor_cmd(
- &mut self,
+ // Send a raw uci command.
+ async fn raw_uci_cmd(
+ &self,
+ mt: u32,
gid: u32,
oid: u32,
payload: Vec<u8>,
- ) -> Result<RawVendorMessage>;
+ ) -> Result<RawUciMessage>;
+
+ // Send a Data packet.
+ async fn send_data_packet(
+ &self,
+ session_id: SessionId,
+ address: Vec<u8>,
+ dest_end_point: FiraComponent,
+ uci_sequence_number: u8,
+ app_payload_data: Vec<u8>,
+ ) -> Result<()>;
}
/// UciManagerImpl is the main implementation of UciManager. Using the actor model, UciManagerImpl
/// delegates the requests to UciManagerActor.
#[derive(Clone)]
-pub(crate) struct UciManagerImpl {
+pub struct UciManagerImpl {
cmd_sender: mpsc::UnboundedSender<(UciManagerCmd, oneshot::Sender<Result<UciResponse>>)>,
}
impl UciManagerImpl {
- pub fn new<T: UciHal, U: UciLogger>(hal: T, logger: U, logger_mode: UciLoggerMode) -> Self {
+ /// Constructor. Need to be called in an async context.
+ pub(crate) fn new<T: UciHal, U: UciLogger>(
+ hal: T,
+ logger: U,
+ logger_mode: UciLoggerMode,
+ ) -> Self {
let (cmd_sender, cmd_receiver) = mpsc::unbounded_channel();
let mut actor = UciManagerActor::new(hal, logger, logger_mode, cmd_receiver);
tokio::spawn(async move { actor.run().await });
@@ -155,7 +181,7 @@ impl UciManagerImpl {
#[async_trait]
impl UciManager for UciManagerImpl {
- async fn set_logger_mode(&mut self, logger_mode: UciLoggerMode) -> Result<()> {
+ async fn set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()> {
match self.send_cmd(UciManagerCmd::SetLoggerMode { logger_mode }).await {
Ok(UciResponse::SetLoggerMode) => Ok(()),
Ok(_) => Err(Error::Unknown),
@@ -178,13 +204,21 @@ impl UciManager for UciManagerImpl {
}
async fn set_vendor_notification_sender(
&mut self,
- vendor_notf_sender: mpsc::UnboundedSender<RawVendorMessage>,
+ vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>,
) {
let _ =
self.send_cmd(UciManagerCmd::SetVendorNotificationSender { vendor_notf_sender }).await;
}
+ async fn set_data_rcv_notification_sender(
+ &mut self,
+ data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>,
+ ) {
+ let _ = self
+ .send_cmd(UciManagerCmd::SetDataRcvNotificationSender { data_rcv_notf_sender })
+ .await;
+ }
- async fn open_hal(&mut self) -> Result<()> {
+ async fn open_hal(&self) -> Result<()> {
match self.send_cmd(UciManagerCmd::OpenHal).await {
Ok(UciResponse::OpenHal) => {
// According to the UCI spec: "The Host shall send CORE_GET_DEVICE_INFO_CMD to
@@ -200,7 +234,7 @@ impl UciManager for UciManagerImpl {
}
}
- async fn close_hal(&mut self, force: bool) -> Result<()> {
+ async fn close_hal(&self, force: bool) -> Result<()> {
match self.send_cmd(UciManagerCmd::CloseHal { force }).await {
Ok(UciResponse::CloseHal) => Ok(()),
Ok(_) => Err(Error::Unknown),
@@ -208,7 +242,7 @@ impl UciManager for UciManagerImpl {
}
}
- async fn device_reset(&mut self, reset_config: ResetConfig) -> Result<()> {
+ async fn device_reset(&self, reset_config: ResetConfig) -> Result<()> {
let cmd = UciCommand::DeviceReset { reset_config };
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
Ok(UciResponse::DeviceReset(resp)) => resp,
@@ -217,7 +251,7 @@ impl UciManager for UciManagerImpl {
}
}
- async fn core_get_device_info(&mut self) -> Result<GetDeviceInfoResponse> {
+ async fn core_get_device_info(&self) -> Result<GetDeviceInfoResponse> {
let cmd = UciCommand::CoreGetDeviceInfo;
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
Ok(UciResponse::CoreGetDeviceInfo(resp)) => resp,
@@ -226,7 +260,7 @@ impl UciManager for UciManagerImpl {
}
}
- async fn core_get_caps_info(&mut self) -> Result<Vec<CapTlv>> {
+ async fn core_get_caps_info(&self) -> Result<Vec<CapTlv>> {
let cmd = UciCommand::CoreGetCapsInfo;
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
Ok(UciResponse::CoreGetCapsInfo(resp)) => resp,
@@ -236,7 +270,7 @@ impl UciManager for UciManagerImpl {
}
async fn core_set_config(
- &mut self,
+ &self,
config_tlvs: Vec<DeviceConfigTlv>,
) -> Result<CoreSetConfigResponse> {
let cmd = UciCommand::CoreSetConfig { config_tlvs };
@@ -247,10 +281,7 @@ impl UciManager for UciManagerImpl {
}
}
- async fn core_get_config(
- &mut self,
- cfg_id: Vec<DeviceConfigId>,
- ) -> Result<Vec<DeviceConfigTlv>> {
+ async fn core_get_config(&self, cfg_id: Vec<DeviceConfigId>) -> Result<Vec<DeviceConfigTlv>> {
let cmd = UciCommand::CoreGetConfig { cfg_id };
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
Ok(UciResponse::CoreGetConfig(resp)) => resp,
@@ -259,11 +290,7 @@ impl UciManager for UciManagerImpl {
}
}
- async fn session_init(
- &mut self,
- session_id: SessionId,
- session_type: SessionType,
- ) -> Result<()> {
+ async fn session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()> {
let cmd = UciCommand::SessionInit { session_id, session_type };
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
Ok(UciResponse::SessionInit(resp)) => resp,
@@ -272,7 +299,7 @@ impl UciManager for UciManagerImpl {
}
}
- async fn session_deinit(&mut self, session_id: SessionId) -> Result<()> {
+ async fn session_deinit(&self, session_id: SessionId) -> Result<()> {
let cmd = UciCommand::SessionDeinit { session_id };
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
Ok(UciResponse::SessionDeinit(resp)) => resp,
@@ -282,7 +309,7 @@ impl UciManager for UciManagerImpl {
}
async fn session_set_app_config(
- &mut self,
+ &self,
session_id: SessionId,
config_tlvs: Vec<AppConfigTlv>,
) -> Result<SetAppConfigResponse> {
@@ -295,7 +322,7 @@ impl UciManager for UciManagerImpl {
}
async fn session_get_app_config(
- &mut self,
+ &self,
session_id: SessionId,
app_cfg: Vec<AppConfigTlvType>,
) -> Result<Vec<AppConfigTlv>> {
@@ -307,7 +334,7 @@ impl UciManager for UciManagerImpl {
}
}
- async fn session_get_count(&mut self) -> Result<u8> {
+ async fn session_get_count(&self) -> Result<u8> {
let cmd = UciCommand::SessionGetCount;
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
Ok(UciResponse::SessionGetCount(resp)) => resp,
@@ -316,7 +343,7 @@ impl UciManager for UciManagerImpl {
}
}
- async fn session_get_state(&mut self, session_id: SessionId) -> Result<SessionState> {
+ async fn session_get_state(&self, session_id: SessionId) -> Result<SessionState> {
let cmd = UciCommand::SessionGetState { session_id };
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
Ok(UciResponse::SessionGetState(resp)) => resp,
@@ -326,12 +353,17 @@ impl UciManager for UciManagerImpl {
}
async fn session_update_controller_multicast_list(
- &mut self,
+ &self,
session_id: SessionId,
action: UpdateMulticastListAction,
- controlees: Vec<Controlee>,
+ controlees: Controlees,
) -> Result<()> {
- if !(1..=8).contains(&controlees.len()) {
+ let controlees_len = match controlees {
+ Controlees::NoSessionKey(ref controlee_vec) => controlee_vec.len(),
+ Controlees::ShortSessionKey(ref controlee_vec) => controlee_vec.len(),
+ Controlees::LongSessionKey(ref controlee_vec) => controlee_vec.len(),
+ };
+ if !(1..=8).contains(&controlees_len) {
warn!("Number of controlees should be between 1 to 8");
return Err(Error::BadParameters);
}
@@ -344,58 +376,56 @@ impl UciManager for UciManagerImpl {
}
}
- async fn session_update_controller_multicast_list_v2(
- &mut self,
- session_id: SessionId,
- action: UpdateMulticastListAction,
- controlees: ControleesV2,
- ) -> Result<()> {
- let controlees_len = match controlees {
- ControleesV2::NoSessionKey(ref controlee_vec) => controlee_vec.len(),
- ControleesV2::ShortSessionKey(ref controlee_vec) => controlee_vec.len(),
- ControleesV2::LongSessionKey(ref controlee_vec) => controlee_vec.len(),
- };
- if !(1..=8).contains(&controlees_len) {
- warn!("Number of controlees should be between 1 to 8");
- return Err(Error::BadParameters);
+ async fn session_update_dt_tag_ranging_rounds(
+ &self,
+ session_id: u32,
+ ranging_round_indexes: Vec<u8>,
+ ) -> Result<SessionUpdateDtTagRangingRoundsResponse> {
+ let cmd = UciCommand::SessionUpdateDtTagRangingRounds { session_id, ranging_round_indexes };
+ match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
+ Ok(UciResponse::SessionUpdateDtTagRangingRounds(resp)) => resp,
+ Ok(_) => Err(Error::Unknown),
+ Err(e) => Err(e),
}
- let cmd =
- UciCommand::SessionUpdateControllerMulticastListV2 { session_id, action, controlees };
+ }
+
+ async fn session_query_max_data_size(&self, session_id: SessionId) -> Result<u16> {
+ let cmd = UciCommand::SessionQueryMaxDataSize { session_id };
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
- Ok(UciResponse::SessionUpdateControllerMulticastList(resp)) => resp,
+ Ok(UciResponse::SessionQueryMaxDataSize(resp)) => resp,
Ok(_) => Err(Error::Unknown),
Err(e) => Err(e),
}
}
- async fn range_start(&mut self, session_id: SessionId) -> Result<()> {
- let cmd = UciCommand::RangeStart { session_id };
+ async fn range_start(&self, session_id: SessionId) -> Result<()> {
+ let cmd = UciCommand::SessionStart { session_id };
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
- Ok(UciResponse::RangeStart(resp)) => resp,
+ Ok(UciResponse::SessionStart(resp)) => resp,
Ok(_) => Err(Error::Unknown),
Err(e) => Err(e),
}
}
- async fn range_stop(&mut self, session_id: SessionId) -> Result<()> {
- let cmd = UciCommand::RangeStop { session_id };
+ async fn range_stop(&self, session_id: SessionId) -> Result<()> {
+ let cmd = UciCommand::SessionStop { session_id };
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
- Ok(UciResponse::RangeStop(resp)) => resp,
+ Ok(UciResponse::SessionStop(resp)) => resp,
Ok(_) => Err(Error::Unknown),
Err(e) => Err(e),
}
}
- async fn range_get_ranging_count(&mut self, session_id: SessionId) -> Result<usize> {
- let cmd = UciCommand::RangeGetRangingCount { session_id };
+ async fn range_get_ranging_count(&self, session_id: SessionId) -> Result<usize> {
+ let cmd = UciCommand::SessionGetRangingCount { session_id };
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
- Ok(UciResponse::RangeGetRangingCount(resp)) => resp,
+ Ok(UciResponse::SessionGetRangingCount(resp)) => resp,
Ok(_) => Err(Error::Unknown),
Err(e) => Err(e),
}
}
- async fn android_set_country_code(&mut self, country_code: CountryCode) -> Result<()> {
+ async fn android_set_country_code(&self, country_code: CountryCode) -> Result<()> {
let cmd = UciCommand::AndroidSetCountryCode { country_code };
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
Ok(UciResponse::AndroidSetCountryCode(resp)) => resp,
@@ -404,7 +434,7 @@ impl UciManager for UciManagerImpl {
}
}
- async fn android_get_power_stats(&mut self) -> Result<PowerStats> {
+ async fn android_get_power_stats(&self) -> Result<PowerStats> {
let cmd = UciCommand::AndroidGetPowerStats;
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
Ok(UciResponse::AndroidGetPowerStats(resp)) => resp,
@@ -413,15 +443,47 @@ impl UciManager for UciManagerImpl {
}
}
- async fn raw_vendor_cmd(
- &mut self,
+ async fn raw_uci_cmd(
+ &self,
+ mt: u32,
gid: u32,
oid: u32,
payload: Vec<u8>,
- ) -> Result<RawVendorMessage> {
- let cmd = UciCommand::RawVendorCmd { gid, oid, payload };
+ ) -> Result<RawUciMessage> {
+ let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload };
match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
- Ok(UciResponse::RawVendorCmd(resp)) => resp,
+ Ok(UciResponse::RawUciCmd(resp)) => resp,
+ Ok(_) => Err(Error::Unknown),
+ Err(e) => Err(e),
+ }
+ }
+
+ // Send a data packet to the UWBS (use the UciManagerActor).
+ async fn send_data_packet(
+ &self,
+ session_id: SessionId,
+ dest_mac_address_bytes: Vec<u8>,
+ dest_fira_component: FiraComponent,
+ uci_sequence_number: u8,
+ data: Vec<u8>,
+ ) -> Result<()> {
+ debug!(
+ "send_data_packet(): will Tx a data packet, session_id {}, sequence_number {}",
+ session_id, uci_sequence_number
+ );
+ let dest_mac_address =
+ bytes_to_u64(dest_mac_address_bytes).ok_or(Error::BadParameters).unwrap();
+ let data_snd_packet = uwb_uci_packets::UciDataSndBuilder {
+ session_id,
+ dest_mac_address,
+ dest_fira_component,
+ uci_sequence_number,
+ data,
+ }
+ .build();
+
+ match self.send_cmd(UciManagerCmd::SendUciData { data_snd_packet }).await {
+ Ok(UciResponse::SendUciData(resp)) => resp,
Ok(_) => Err(Error::Unknown),
Err(e) => Err(e),
}
@@ -438,7 +500,7 @@ struct UciManagerActor<T: UciHal, U: UciLogger> {
// Set to true when |hal| is opened successfully.
is_hal_opened: bool,
- // Receive the response and the notification from |hal|. Only used when |hal| is opened
+ // Receive response, notification and data packets from |hal|. Only used when |hal| is opened
// successfully.
packet_receiver: mpsc::UnboundedReceiver<UciHalPacket>,
// Defrag the UCI packets.
@@ -447,20 +509,38 @@ struct UciManagerActor<T: UciHal, U: UciLogger> {
// The response sender of UciManager's open_hal() method. Used to wait for the device ready
// notification.
open_hal_result_sender: Option<oneshot::Sender<Result<UciResponse>>>,
+
+ // Store per-session CreditAvailability. This should be initialized when a UWB session becomes
+ // ACTIVE, and updated every time a Data packet fragment is sent or a DataCreditNtf is received.
+ data_credit_map: HashMap<SessionId, CreditAvailability>,
+
+ // Store the Uci Data packet fragments to be sent to the UWBS, keyed by the SessionId. This
+ // helps to retrieve the next packet fragment to be sent, when the UWBS is ready to accept it.
+ data_packet_fragments_map: HashMap<SessionId, VecDeque<UciDataPacketHal>>,
+
// The timeout of waiting for the notification of device ready notification.
wait_device_status_timeout: PinSleep,
// Used for the logic of retrying the command. Only valid when waiting for the response of a
// UCI command.
- retryer: Option<Retryer>,
+ uci_cmd_retryer: Option<UciCmdRetryer>,
// The timeout of waiting for the response. Only used when waiting for the response of a UCI
// command.
wait_resp_timeout: PinSleep,
+ // Used for the logic of retrying the DataSnd packet. Only valid when waiting for the
+ // DATA_TRANSFER_STATUS_NTF.
+ uci_data_snd_retryer: Option<UciDataSndRetryer>,
+
+ // Used to identify if response corresponds to the last vendor command, if so return
+ // a raw packet as a response to the sender.
+ last_raw_cmd: Option<RawUciControlPacket>,
+
// Send the notifications to the caller of UciManager.
core_notf_sender: mpsc::UnboundedSender<CoreNotification>,
session_notf_sender: mpsc::UnboundedSender<SessionNotification>,
- vendor_notf_sender: mpsc::UnboundedSender<RawVendorMessage>,
+ vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>,
+ data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>,
}
impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> {
@@ -481,12 +561,17 @@ impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> {
packet_receiver: mpsc::unbounded_channel().1,
defrager: Default::default(),
open_hal_result_sender: None,
+ data_credit_map: HashMap::new(),
+ data_packet_fragments_map: HashMap::new(),
wait_device_status_timeout: PinSleep::new(Duration::MAX),
- retryer: None,
+ uci_cmd_retryer: None,
+ uci_data_snd_retryer: None,
wait_resp_timeout: PinSleep::new(Duration::MAX),
+ last_raw_cmd: None,
core_notf_sender: mpsc::unbounded_channel().0,
session_notf_sender: mpsc::unbounded_channel().0,
vendor_notf_sender: mpsc::unbounded_channel().0,
+ data_rcv_notf_sender: mpsc::unbounded_channel().0,
}
}
@@ -507,35 +592,15 @@ impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> {
}
}
- // Handle the UCI response or notification from HAL. Only when HAL is opened.
+ // Handle the UCI response, notification or data packet from HAL. Only when HAL
+ // is opened.
packet = self.packet_receiver.recv(), if self.is_hal_opened => {
- match packet {
- None => {
- warn!("UciHal dropped the packet_sender unexpectedly.");
- self.on_hal_closed();
- },
- Some(packet) => {
- if let Some(packet) = self.defrager.defragment_packet(&packet) {
- self.logger.log_uci_response_or_notification(&packet);
- match packet.try_into() {
- Ok(UciMessage::Response(resp)) => {
- self.handle_response(resp).await;
- }
- Ok(UciMessage::Notification(notf)) => {
- self.handle_notification(notf).await;
- }
- Err(e)=> {
- error!("Failed to parse received message: {:?}", e);
- }
- }
- }
- },
- }
+ self.handle_hal_packet(packet).await;
}
// Timeout waiting for the response of the UCI command.
_ = &mut self.wait_resp_timeout, if self.is_waiting_resp() => {
- self.retryer.take().unwrap().send_result(Err(Error::Timeout));
+ self.uci_cmd_retryer.take().unwrap().send_result(Err(Error::Timeout));
}
// Timeout waiting for the notification of the device status.
@@ -578,6 +643,10 @@ impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> {
self.vendor_notf_sender = vendor_notf_sender;
let _ = result_sender.send(Ok(UciResponse::SetNotification));
}
+ UciManagerCmd::SetDataRcvNotificationSender { data_rcv_notf_sender } => {
+ self.data_rcv_notf_sender = data_rcv_notf_sender;
+ let _ = result_sender.send(Ok(UciResponse::SetNotification));
+ }
UciManagerCmd::OpenHal => {
if self.is_hal_opened {
warn!("The UCI HAL is already opened, skip.");
@@ -626,27 +695,85 @@ impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> {
}
UciManagerCmd::SendUciCommand { cmd } => {
- debug_assert!(self.retryer.is_none());
- self.retryer = Some(Retryer { cmd, result_sender, retry_count: MAX_RETRY_COUNT });
- self.retry_command().await;
+ debug_assert!(self.uci_cmd_retryer.is_none());
+
+ // Remember that this command is a raw UCI command, we'll use this later
+ // to send a raw UCI response.
+ if let UciCommand::RawUciCmd { mt: _, gid, oid, payload: _ } = cmd.clone() {
+ let gid_u8 = u8::try_from(gid);
+ if gid_u8.is_err() || GroupId::try_from(gid_u8.unwrap()).is_err() {
+ error!("Received an invalid GID={} for RawUciCmd", gid);
+ let _ = result_sender.send(Err(Error::BadParameters));
+ return;
+ }
+
+ let oid_u8 = u8::try_from(oid);
+ if oid_u8.is_err() {
+ error!("Received an invalid OID={} for RawUciCmd", oid);
+ let _ = result_sender.send(Err(Error::BadParameters));
+ return;
+ }
+ self.last_raw_cmd = Some(RawUciControlPacket {
+ mt: u8::from(MessageType::Command),
+ gid: gid_u8.unwrap(),
+ oid: oid_u8.unwrap(),
+ payload: Vec::new(), // There's no need to store the Raw UCI CMD's payload.
+ });
+ }
+
+ self.uci_cmd_retryer =
+ Some(UciCmdRetryer { cmd, result_sender, retry_count: MAX_RETRY_COUNT });
+ self.retry_uci_cmd().await;
+ }
+
+ UciManagerCmd::SendUciData { data_snd_packet } => {
+ let result = self.handle_data_snd_packet(data_snd_packet).await;
+ let _ = result_sender.send(result);
}
}
}
- async fn retry_command(&mut self) {
- if let Some(mut retryer) = self.retryer.take() {
- if !retryer.could_retry() {
- retryer.send_result(Err(Error::Timeout));
+ async fn retry_uci_cmd(&mut self) {
+ if let Some(mut uci_cmd_retryer) = self.uci_cmd_retryer.take() {
+ if !uci_cmd_retryer.could_retry() {
+ error!("Out of retries for Uci Cmd packet");
+ uci_cmd_retryer.send_result(Err(Error::Timeout));
return;
}
- match self.send_uci_command(retryer.cmd.clone()).await {
+ match self.send_uci_command(uci_cmd_retryer.cmd.clone()).await {
Ok(_) => {
self.wait_resp_timeout = PinSleep::new(Duration::from_millis(UCI_TIMEOUT_MS));
- self.retryer = Some(retryer);
+ self.uci_cmd_retryer = Some(uci_cmd_retryer);
+ }
+ Err(e) => {
+ error!("Uci Cmd send resulted in error:{}", e);
+ uci_cmd_retryer.send_result(Err(e));
+ }
+ }
+ }
+ }
+
+ async fn retry_uci_data_snd(&mut self) {
+ if let Some(mut uci_data_snd_retryer) = self.uci_data_snd_retryer.take() {
+ let data_packet_session_id = uci_data_snd_retryer.data_packet_session_id;
+ if !uci_data_snd_retryer.could_retry() {
+ error!(
+ "Out of retries for Uci DataSnd packet, last DataSnd packet session_id:{}",
+ data_packet_session_id
+ );
+ return;
+ }
+
+ match self.hal.send_packet(uci_data_snd_retryer.data_packet.clone().to_vec()).await {
+ Ok(_) => {
+ self.uci_data_snd_retryer = Some(uci_data_snd_retryer);
}
Err(e) => {
- retryer.send_result(Err(e));
+ error!(
+ "DataSnd packet fragment session_id:{} retry failed with error:{}",
+ data_packet_session_id, e
+ );
}
}
}
@@ -664,14 +791,172 @@ impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> {
result
}
+ async fn handle_data_snd_packet(&mut self, data_snd_packet: UciDataSnd) -> Result<UciResponse> {
+ // Verify that there's an entry for the Session in the CreditAvailability map.
+ let data_packet_session_id = data_snd_packet.get_session_id();
+ let data_packet_sequence_number = data_snd_packet.get_uci_sequence_number();
+
+ if !self.data_credit_map.contains_key(&data_packet_session_id) {
+ error!(
+ "DataSnd packet session_id:{}, sequence_number:{} cannot be sent as unknown \
+ credit availability for the session",
+ data_packet_session_id, data_packet_sequence_number
+ );
+ return Err(Error::PacketTxError);
+ }
+
+ // Enqueue the data packet fragments, from the data packet to be sent to UWBS.
+ let mut packet_fragments: Vec<UciDataPacketHal> = data_snd_packet.into();
+ if packet_fragments.is_empty() {
+ error!(
+ "DataSnd packet session_id:{}, sequence number:{} could not be split into fragments",
+ data_packet_session_id, data_packet_sequence_number
+ );
+ return Err(Error::PacketTxError);
+ }
+
+ match self.data_packet_fragments_map.get_mut(&data_packet_session_id) {
+ Some(q) => {
+ for p in packet_fragments.drain(..) {
+ q.push_back(p);
+ }
+ }
+ None => {
+ error!(
+ "DataSnd packet fragments map not found for session_id:{}",
+ data_packet_session_id
+ );
+ return Err(Error::PacketTxError);
+ }
+ }
+
+ self.send_data_packet_fragment(data_packet_session_id).await
+ }
+
+ async fn send_data_packet_fragment(
+ &mut self,
+ data_packet_session_id: SessionId,
+ ) -> Result<UciResponse> {
+ // Check if a credit is available before sending this data packet fragment. If not, return
+ // for now, and send this packet later when the credit becomes available (indicated by
+ // receiving a DataCreditNtf).
+ let credit = self.data_credit_map.get(&data_packet_session_id);
+ if credit.is_none() {
+ error!(
+ "DataSnd packet fragment cannot be sent for session_id:{} as unknown \
+ credit availability for the session",
+ data_packet_session_id
+ );
+ return Err(Error::PacketTxError);
+ }
+ if credit == Some(&CreditAvailability::CreditNotAvailable) {
+ return Ok(UciResponse::SendUciData(Ok(())));
+ }
+
+ // We have credit available, let's send the packet to UWBS.
+ let hal_data_packet_fragment =
+ match self.data_packet_fragments_map.get_mut(&data_packet_session_id) {
+ Some(q) => {
+ match q.pop_front() {
+ Some(p) => p,
+ None => {
+ // No more packets left to send.
+ return Ok(UciResponse::SendUciData(Ok(())));
+ }
+ }
+ }
+ None => {
+ return Err(Error::PacketTxError);
+ }
+ };
+
+ // Create and save a retryer for sending this data packet fragment.
+ self.uci_data_snd_retryer = Some(UciDataSndRetryer {
+ data_packet: hal_data_packet_fragment.clone(),
+ data_packet_session_id,
+ retry_count: MAX_RETRY_COUNT,
+ });
+
+ let result = self.hal.send_packet(hal_data_packet_fragment.to_vec()).await;
+ if result.is_err() {
+ error!(
+ "Result {:?} of sending data packet fragment SessionId: {} to HAL",
+ result, data_packet_session_id
+ );
+ return Err(Error::PacketTxError);
+ }
+
+ // Update the map after the successful write.
+ self.data_credit_map.insert(data_packet_session_id, CreditAvailability::CreditNotAvailable);
+ Ok(UciResponse::SendUciData(Ok(())))
+ }
+
+ async fn handle_hal_packet(&mut self, packet: Option<UciHalPacket>) {
+ let defrag_packet = match packet {
+ Some(rx_packet) => {
+ self.defrager.defragment_packet(&rx_packet, self.last_raw_cmd.clone())
+ }
+ None => {
+ warn!("UciHal dropped the packet_sender unexpectedly.");
+ self.on_hal_closed();
+ return;
+ }
+ };
+ let defrag_packet = match defrag_packet {
+ Some(p) => p,
+ None => return,
+ };
+
+ match defrag_packet {
+ UciDefragPacket::Control(packet) => {
+ self.logger.log_uci_response_or_notification(&packet);
+
+ match packet.try_into() {
+ Ok(UciMessage::Response(resp)) => {
+ self.handle_response(resp).await;
+ }
+ Ok(UciMessage::Notification(notf)) => {
+ self.handle_notification(notf).await;
+ }
+ Err(e) => {
+ error!("Failed to parse received message: {:?}", e);
+ }
+ }
+ }
+ UciDefragPacket::Data(packet) => {
+ self.logger.log_uci_data(&packet);
+ self.handle_data_rcv(packet);
+ }
+ UciDefragPacket::Raw(result, raw_uci_control_packet) => {
+ // Handle response to raw UCI cmd. We want to send it back as
+ // raw UCI message instead of standard response message.
+ let resp = match result {
+ Ok(()) => {
+ // We should receive only a valid UCI response packet here.
+ UciResponse::RawUciCmd(Ok(RawUciMessage {
+ gid: raw_uci_control_packet.gid.into(),
+ oid: raw_uci_control_packet.oid.into(),
+ payload: raw_uci_control_packet.payload,
+ }))
+ }
+ // TODO: Implement conversion between Error::InvalidPacketError (returned by
+ // lib.rs and defined in the PDL uci_packets.rs) and the uwb_core::Error enums.
+ Err(_) => UciResponse::RawUciCmd(Err(Error::Unknown)),
+ };
+ self.handle_response(resp).await;
+ self.last_raw_cmd = None;
+ }
+ }
+ }
+
async fn handle_response(&mut self, resp: UciResponse) {
if resp.need_retry() {
- self.retry_command().await;
+ self.retry_uci_cmd().await;
return;
}
- if let Some(retryer) = self.retryer.take() {
- retryer.send_result(Ok(resp));
+ if let Some(uci_cmd_retryer) = self.uci_cmd_retryer.take() {
+ uci_cmd_retryer.send_result(Ok(resp));
} else {
warn!("Received an UCI response unexpectedly: {:?}", resp);
}
@@ -679,7 +964,10 @@ impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> {
async fn handle_notification(&mut self, notf: UciNotification) {
if notf.need_retry() {
- self.retry_command().await;
+ // Retry sending both last sent UCI CMD and UCI DataSnd packet since the notification
+ // could be for either of them.
+ self.retry_uci_cmd().await;
+ self.retry_uci_data_snd().await;
return;
}
@@ -699,15 +987,48 @@ impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> {
let _ = self.core_notf_sender.send(core_notf);
}
UciNotification::Session(session_notf) => {
- if let SessionNotification::Status {
- session_id,
- session_state: SessionState::SessionStateInit,
- reason_code: _,
- } = session_notf
+ if let SessionNotification::Status { session_id, session_state, reason_code: _ } =
+ session_notf
+ {
+ self.handle_session_state_notification(session_id, session_state).await;
+ }
+ if let SessionNotification::DataCredit { session_id, credit_availability } =
+ session_notf
{
- if let Err(e) = self.hal.notify_session_initialized(session_id).await {
- warn!("notify_session_initialized() failed: {:?}", e);
+ if !self.data_credit_map.contains_key(&session_id) {
+ // Currently just log, as this is unexpected (the entry should exist once
+ // the ranging session is Active and be removed once it is Idle).
+ debug!(
+ "Received a DataCreditNtf for non-existent session_id: {}",
+ session_id
+ );
}
+ self.data_credit_map.insert(session_id, credit_availability);
+ if credit_availability == CreditAvailability::CreditAvailable {
+ if let Err(e) = self.send_data_packet_fragment(session_id).await {
+ error!(
+ "Sending data packet fragment failed with Err:{}, after a\
+ DataCreditNtf is received, for sessionId:{}",
+ e, session_id
+ );
+ }
+ } else {
+ // Log as this should usually not happen (it's not an error).
+ debug!(
+ "Received a DataCreditNtf with no credit available for session_id:{}",
+ session_id
+ );
+ }
+ return; // We consume these here and don't need to send to upper layer.
+ }
+ if let SessionNotification::DataTransferStatus {
+ session_id: _,
+ uci_sequence_number: _,
+ status: _,
+ } = session_notf
+ {
+ // Reset the UciDataSnd Retryer since we received a DataTransferStatusNtf.
+ let _ = self.uci_data_snd_retryer.take();
}
let _ = self.session_notf_sender.send(session_notf);
}
@@ -717,6 +1038,40 @@ impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> {
}
}
+ async fn handle_session_state_notification(
+ &mut self,
+ session_id: SessionId,
+ session_state: SessionState,
+ ) {
+ match session_state {
+ SessionState::SessionStateInit => {
+ if let Err(e) = self.hal.notify_session_initialized(session_id).await {
+ warn!("notify_session_initialized() failed: {:?}", e);
+ }
+ }
+ SessionState::SessionStateActive => {
+ self.data_credit_map.insert(session_id, CreditAvailability::CreditAvailable);
+ self.data_packet_fragments_map.insert(session_id, VecDeque::new());
+ }
+ SessionState::SessionStateIdle => {
+ self.data_credit_map.remove(&session_id);
+ self.data_packet_fragments_map.remove(&session_id);
+ }
+ _ => {}
+ }
+ }
+
+ fn handle_data_rcv(&mut self, packet: UciDataPacket) {
+ match packet.try_into() {
+ Ok(data_rcv) => {
+ let _ = self.data_rcv_notf_sender.send(data_rcv);
+ }
+ Err(e) => {
+ error!("Unable to parse incoming Data packet, error {:?}", e);
+ }
+ }
+ }
+
fn on_hal_open(&mut self, packet_receiver: mpsc::UnboundedReceiver<UciHalPacket>) {
self.is_hal_opened = true;
self.packet_receiver = packet_receiver;
@@ -725,10 +1080,11 @@ impl<T: UciHal, U: UciLogger> UciManagerActor<T, U> {
fn on_hal_closed(&mut self) {
self.is_hal_opened = false;
self.packet_receiver = mpsc::unbounded_channel().1;
+ self.last_raw_cmd = None;
}
fn is_waiting_resp(&self) -> bool {
- self.retryer.is_some()
+ self.uci_cmd_retryer.is_some()
}
fn is_waiting_device_status(&self) -> bool {
self.open_hal_result_sender.is_some()
@@ -742,13 +1098,13 @@ impl<T: UciHal, U: UciLogger> Drop for UciManagerActor<T, U> {
}
}
-struct Retryer {
+struct UciCmdRetryer {
cmd: UciCommand,
result_sender: oneshot::Sender<Result<UciResponse>>,
retry_count: usize,
}
-impl Retryer {
+impl UciCmdRetryer {
fn could_retry(&mut self) -> bool {
if self.retry_count == 0 {
return false;
@@ -762,15 +1118,55 @@ impl Retryer {
}
}
+struct UciDataSndRetryer {
+ // Store the last-sent DataSnd packet fragment across all the active UWB session, as the UCI
+ // spec states that the "last UCI packet should be re-transmitted from Host".
+ //
+ // TODO(b/273376343): The spec is open to a race condition in the scenario of multiple active
+ // sessions, as there can be outstanding DataSnd packet fragments across them. We could do an
+ // alternative implementation of sending all of them.
+ data_packet: UciDataPacketHal,
+ data_packet_session_id: u32,
+ retry_count: usize,
+}
+
+impl UciDataSndRetryer {
+ fn could_retry(&mut self) -> bool {
+ if self.retry_count == 0 {
+ return false;
+ }
+ self.retry_count -= 1;
+ true
+ }
+}
+
#[derive(Debug)]
enum UciManagerCmd {
- SetLoggerMode { logger_mode: UciLoggerMode },
- SetCoreNotificationSender { core_notf_sender: mpsc::UnboundedSender<CoreNotification> },
- SetSessionNotificationSender { session_notf_sender: mpsc::UnboundedSender<SessionNotification> },
- SetVendorNotificationSender { vendor_notf_sender: mpsc::UnboundedSender<RawVendorMessage> },
+ SetLoggerMode {
+ logger_mode: UciLoggerMode,
+ },
+ SetCoreNotificationSender {
+ core_notf_sender: mpsc::UnboundedSender<CoreNotification>,
+ },
+ SetSessionNotificationSender {
+ session_notf_sender: mpsc::UnboundedSender<SessionNotification>,
+ },
+ SetVendorNotificationSender {
+ vendor_notf_sender: mpsc::UnboundedSender<RawUciMessage>,
+ },
+ SetDataRcvNotificationSender {
+ data_rcv_notf_sender: mpsc::UnboundedSender<DataRcvNotification>,
+ },
OpenHal,
- CloseHal { force: bool },
- SendUciCommand { cmd: UciCommand },
+ CloseHal {
+ force: bool,
+ },
+ SendUciCommand {
+ cmd: UciCommand,
+ },
+ SendUciData {
+ data_snd_packet: UciDataSnd,
+ },
}
#[cfg(test)]
@@ -778,24 +1174,42 @@ mod tests {
use super::*;
use bytes::Bytes;
- use uwb_uci_packets::{
- Controlee_V2_0_0_Byte_Version, MessageControl, SessionGetCountCmdBuilder,
- SessionGetCountRspBuilder,
- };
+ use uwb_uci_packets::{SessionGetCountCmdBuilder, SessionGetCountRspBuilder};
- use crate::params::uci_packets::{CapTlvType, StatusCode};
+ use crate::params::uci_packets::{
+ AppConfigStatus, AppConfigTlvType, CapTlvType, Controlee, DataTransferNtfStatusCode,
+ StatusCode,
+ };
use crate::uci::mock_uci_hal::MockUciHal;
use crate::uci::mock_uci_logger::{MockUciLogger, UciLogEvent};
- use crate::uci::uci_logger::UciLoggerNull;
+ use crate::uci::uci_logger::NopUciLogger;
use crate::utils::init_test_logging;
- fn into_uci_hal_packets<T: Into<uwb_uci_packets::UciPacketPacket>>(
+ fn into_uci_hal_packets<T: Into<uwb_uci_packets::UciControlPacket>>(
builder: T,
) -> Vec<UciHalPacket> {
- let packets: Vec<uwb_uci_packets::UciPacketHalPacket> = builder.into().into();
+ let packets: Vec<uwb_uci_packets::UciControlPacketHal> = builder.into().into();
packets.into_iter().map(|packet| packet.into()).collect()
}
+ // Construct a UCI packet, with the header fields and payload bytes.
+ fn build_uci_packet(mt: u8, pbf: u8, gid: u8, oid: u8, mut payload: Vec<u8>) -> Vec<u8> {
+ let len: u16 = payload.len() as u16;
+ let mut bytes: Vec<u8> = vec![(mt & 0x7) << 5 | (pbf & 0x1) << 4 | (gid & 0xF), oid & 0x3F];
+ if mt == 0 {
+ // UCI Data packet
+ // Store 16-bit payload length in LSB format.
+ bytes.push((len & 0xFF).try_into().unwrap());
+ bytes.push((len >> 8).try_into().unwrap());
+ } else {
+ // One byte RFU, followed by one-byte payload length.
+ bytes.push(0);
+ bytes.push((len & 0xFF).try_into().unwrap());
+ }
+ bytes.append(&mut payload);
+ bytes
+ }
+
async fn setup_uci_manager_with_open_hal<F>(
setup_hal_fn: F,
uci_logger_mode: UciLoggerMode,
@@ -828,7 +1242,7 @@ mod tests {
setup_hal_fn(&mut hal);
// Verify open_hal() is working.
- let mut uci_manager =
+ let uci_manager =
UciManagerImpl::new(hal.clone(), MockUciLogger::new(log_sender), uci_logger_mode);
let result = uci_manager.open_hal().await;
assert!(result.is_ok());
@@ -842,8 +1256,8 @@ mod tests {
let mut hal = MockUciHal::new();
hal.expected_open(None, Ok(()));
- let mut uci_manager =
- UciManagerImpl::new(hal.clone(), UciLoggerNull::default(), UciLoggerMode::Disabled);
+ let uci_manager =
+ UciManagerImpl::new(hal.clone(), NopUciLogger::default(), UciLoggerMode::Disabled);
let result = uci_manager.open_hal().await;
assert!(matches!(result, Err(Error::Timeout)));
@@ -852,7 +1266,7 @@ mod tests {
#[tokio::test]
async fn test_close_hal_explicitly() {
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
|hal| {
hal.expected_close(Ok(()));
},
@@ -887,8 +1301,8 @@ mod tests {
init_test_logging();
let mut hal = MockUciHal::new();
- let mut uci_manager =
- UciManagerImpl::new(hal.clone(), UciLoggerNull::default(), UciLoggerMode::Disabled);
+ let uci_manager =
+ UciManagerImpl::new(hal.clone(), NopUciLogger::default(), UciLoggerMode::Disabled);
let result = uci_manager.close_hal(false).await;
assert!(matches!(result, Err(Error::BadParameters)));
@@ -897,7 +1311,7 @@ mod tests {
#[tokio::test]
async fn test_device_reset_ok() {
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
|hal| {
let cmd = UciCommand::DeviceReset { reset_config: ResetConfig::UwbsReset };
let resp = into_uci_hal_packets(uwb_uci_packets::DeviceResetRspBuilder {
@@ -926,7 +1340,7 @@ mod tests {
let vendor_spec_info = vec![0x1, 0x2];
let vendor_spec_info_clone = vendor_spec_info.clone();
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
let cmd = UciCommand::CoreGetDeviceInfo;
let resp = into_uci_hal_packets(uwb_uci_packets::GetDeviceInfoRspBuilder {
@@ -962,7 +1376,7 @@ mod tests {
let tlv = CapTlv { t: CapTlvType::SupportedFiraPhyVersionRange, v: vec![0x12, 0x34, 0x56] };
let tlv_clone = tlv.clone();
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
let cmd = UciCommand::CoreGetCapsInfo;
let resp = into_uci_hal_packets(uwb_uci_packets::GetCapsInfoRspBuilder {
@@ -993,7 +1407,7 @@ mod tests {
let config_status = vec![];
let config_status_clone = config_status.clone();
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
let cmd = UciCommand::CoreSetConfig { config_tlvs: vec![tlv_clone] };
let resp = into_uci_hal_packets(uwb_uci_packets::SetConfigRspBuilder {
@@ -1020,7 +1434,7 @@ mod tests {
let tlv = DeviceConfigTlv { cfg_id, v: vec![0x12, 0x34, 0x56] };
let tlv_clone = tlv.clone();
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
let cmd = UciCommand::CoreGetConfig { cfg_id: vec![cfg_id] };
let resp = into_uci_hal_packets(uwb_uci_packets::GetConfigRspBuilder {
@@ -1046,27 +1460,29 @@ mod tests {
let session_id = 0x123;
let session_type = SessionType::FiraRangingSession;
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
- move |hal| {
- let cmd = UciCommand::SessionInit { session_id, session_type };
- let mut resp = into_uci_hal_packets(uwb_uci_packets::SessionInitRspBuilder {
- status: uwb_uci_packets::StatusCode::UciStatusOk,
- });
- let mut notf = into_uci_hal_packets(uwb_uci_packets::SessionStatusNtfBuilder {
- session_id,
- session_state: uwb_uci_packets::SessionState::SessionStateInit,
- reason_code:
- uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands,
- });
- resp.append(&mut notf);
-
- hal.expected_send_command(cmd, resp, Ok(()));
- hal.expected_notify_session_initialized(session_id, Ok(()));
- },
- UciLoggerMode::Disabled,
- mpsc::unbounded_channel::<UciLogEvent>().0,
- )
- .await;
+ let (uci_manager, mut mock_hal) =
+ setup_uci_manager_with_open_hal(
+ move |hal| {
+ let cmd = UciCommand::SessionInit { session_id, session_type };
+ let mut resp = into_uci_hal_packets(uwb_uci_packets::SessionInitRspBuilder {
+ status: uwb_uci_packets::StatusCode::UciStatusOk,
+ });
+ let mut notf = into_uci_hal_packets(uwb_uci_packets::SessionStatusNtfBuilder {
+ session_id,
+ session_state: uwb_uci_packets::SessionState::SessionStateInit,
+ reason_code:
+ uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands
+ .into(),
+ });
+ resp.append(&mut notf);
+
+ hal.expected_send_command(cmd, resp, Ok(()));
+ hal.expected_notify_session_initialized(session_id, Ok(()));
+ },
+ UciLoggerMode::Disabled,
+ mpsc::unbounded_channel::<UciLogEvent>().0,
+ )
+ .await;
let result = uci_manager.session_init(session_id, session_type).await;
assert!(result.is_ok());
@@ -1077,7 +1493,7 @@ mod tests {
async fn test_session_deinit_ok() {
let session_id = 0x123;
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
let cmd = UciCommand::SessionDeinit { session_id };
let resp = into_uci_hal_packets(uwb_uci_packets::SessionDeinitRspBuilder {
@@ -1102,7 +1518,7 @@ mod tests {
let config_tlv = AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![0x12, 0x34, 0x56]);
let config_tlv_clone = config_tlv.clone();
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
|hal| {
let cmd = UciCommand::SessionSetAppConfig {
session_id,
@@ -1135,7 +1551,7 @@ mod tests {
let tlv = AppConfigTlv::new(AppConfigTlvType::DeviceType, vec![0x12, 0x34, 0x56]);
let tlv_clone = tlv.clone();
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
let cmd = UciCommand::SessionGetAppConfig { session_id, app_cfg: vec![config_id] };
let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetAppConfigRspBuilder {
@@ -1160,7 +1576,7 @@ mod tests {
async fn test_session_get_count_ok() {
let session_count = 5;
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
let cmd = UciCommand::SessionGetCount;
let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder {
@@ -1185,7 +1601,7 @@ mod tests {
let session_id = 0x123;
let session_state = SessionState::SessionStateActive;
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
let cmd = UciCommand::SessionGetState { session_id };
let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetStateRspBuilder {
@@ -1212,12 +1628,12 @@ mod tests {
let controlee = Controlee { short_address: 0x4567, subsession_id: 0x90ab };
let controlee_clone = controlee.clone();
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
let cmd = UciCommand::SessionUpdateControllerMulticastList {
session_id,
action,
- controlees: vec![controlee_clone],
+ controlees: Controlees::NoSessionKey(vec![controlee_clone]),
};
let resp = into_uci_hal_packets(
uwb_uci_packets::SessionUpdateControllerMulticastListRspBuilder {
@@ -1233,33 +1649,33 @@ mod tests {
.await;
let result = uci_manager
- .session_update_controller_multicast_list(session_id, action, vec![controlee])
+ .session_update_controller_multicast_list(
+ session_id,
+ action,
+ uwb_uci_packets::Controlees::NoSessionKey(vec![controlee]),
+ )
.await;
assert!(result.is_ok());
assert!(mock_hal.wait_expected_calls_done().await);
}
#[tokio::test]
- async fn test_session_update_controller_multicast_list_v2_ok() {
- let session_id = 0x123;
- let action = UpdateMulticastListAction::AddControlee;
- let controlee = Controlee_V2_0_0_Byte_Version {
- short_address: 0x4567,
- subsession_id: 0x90ab,
- message_control: MessageControl::SubSessionKeyNotConfigured,
+ async fn test_set_active_dt_tag_ranging_rounds() {
+ let ranging_rounds = SessionUpdateDtTagRangingRoundsResponse {
+ status: StatusCode::UciStatusErrorRoundIndexNotActivated,
+ ranging_round_indexes: vec![3],
};
- let controlee_clone = controlee.clone();
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
- let cmd = UciCommand::SessionUpdateControllerMulticastListV2 {
- session_id,
- action,
- controlees: ControleesV2::NoSessionKey(vec![controlee_clone]),
+ let cmd = UciCommand::SessionUpdateDtTagRangingRounds {
+ session_id: 1,
+ ranging_round_indexes: vec![3, 5],
};
let resp = into_uci_hal_packets(
- uwb_uci_packets::SessionUpdateControllerMulticastListRspBuilder {
- status: uwb_uci_packets::StatusCode::UciStatusOk,
+ uwb_uci_packets::SessionUpdateDtTagRangingRoundsRspBuilder {
+ status: StatusCode::UciStatusErrorRoundIndexNotActivated,
+ ranging_round_indexes: vec![3],
},
);
@@ -1270,14 +1686,9 @@ mod tests {
)
.await;
- let result = uci_manager
- .session_update_controller_multicast_list_v2(
- session_id,
- action,
- ControleesV2::NoSessionKey(vec![controlee]),
- )
- .await;
- assert!(result.is_ok());
+ let result = uci_manager.session_update_dt_tag_ranging_rounds(1, vec![3, 5]).await.unwrap();
+
+ assert_eq!(result, ranging_rounds);
assert!(mock_hal.wait_expected_calls_done().await);
}
@@ -1285,10 +1696,10 @@ mod tests {
async fn test_range_start_ok() {
let session_id = 0x123;
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
- let cmd = UciCommand::RangeStart { session_id };
- let resp = into_uci_hal_packets(uwb_uci_packets::RangeStartRspBuilder {
+ let cmd = UciCommand::SessionStart { session_id };
+ let resp = into_uci_hal_packets(uwb_uci_packets::SessionStartRspBuilder {
status: uwb_uci_packets::StatusCode::UciStatusOk,
});
@@ -1308,10 +1719,10 @@ mod tests {
async fn test_range_stop_ok() {
let session_id = 0x123;
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
- let cmd = UciCommand::RangeStop { session_id };
- let resp = into_uci_hal_packets(uwb_uci_packets::RangeStopRspBuilder {
+ let cmd = UciCommand::SessionStop { session_id };
+ let resp = into_uci_hal_packets(uwb_uci_packets::SessionStopRspBuilder {
status: uwb_uci_packets::StatusCode::UciStatusOk,
});
@@ -1332,13 +1743,14 @@ mod tests {
let session_id = 0x123;
let count = 3;
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
- let cmd = UciCommand::RangeGetRangingCount { session_id };
- let resp = into_uci_hal_packets(uwb_uci_packets::RangeGetRangingCountRspBuilder {
- status: uwb_uci_packets::StatusCode::UciStatusOk,
- count,
- });
+ let cmd = UciCommand::SessionGetRangingCount { session_id };
+ let resp =
+ into_uci_hal_packets(uwb_uci_packets::SessionGetRangingCountRspBuilder {
+ status: uwb_uci_packets::StatusCode::UciStatusOk,
+ count,
+ });
hal.expected_send_command(cmd, resp, Ok(()));
},
@@ -1357,7 +1769,7 @@ mod tests {
let country_code = CountryCode::new(b"US").unwrap();
let country_code_clone = country_code.clone();
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
let cmd = UciCommand::AndroidSetCountryCode { country_code: country_code_clone };
let resp = into_uci_hal_packets(uwb_uci_packets::AndroidSetCountryCodeRspBuilder {
@@ -1387,7 +1799,7 @@ mod tests {
};
let power_stats_clone = power_stats.clone();
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
let cmd = UciCommand::AndroidGetPowerStats;
let resp = into_uci_hal_packets(uwb_uci_packets::AndroidGetPowerStatsRspBuilder {
@@ -1407,17 +1819,18 @@ mod tests {
}
#[tokio::test]
- async fn test_raw_vendor_cmd_ok() {
- let gid = 0xF;
+ async fn test_raw_uci_cmd_vendor_gid_ok() {
+ let mt = 0x1;
+ let gid = 0xF; // Vendor reserved GID.
let oid = 0x3;
let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
let cmd_payload_clone = cmd_payload.clone();
let resp_payload = vec![0x55, 0x66, 0x77, 0x88];
let resp_payload_clone = resp_payload.clone();
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
- let cmd = UciCommand::RawVendorCmd { gid, oid, payload: cmd_payload_clone };
+ let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone };
let resp = into_uci_hal_packets(uwb_uci_packets::UciVendor_F_ResponseBuilder {
opcode: oid as u8,
payload: Some(Bytes::from(resp_payload_clone)),
@@ -1430,15 +1843,632 @@ mod tests {
)
.await;
- let expected_result = RawVendorMessage { gid, oid, payload: resp_payload };
- let result = uci_manager.raw_vendor_cmd(gid, oid, cmd_payload).await.unwrap();
+ let expected_result = RawUciMessage { gid, oid, payload: resp_payload };
+ let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await.unwrap();
+ assert_eq!(result, expected_result);
+ assert!(mock_hal.wait_expected_calls_done().await);
+ }
+
+ #[tokio::test]
+ async fn test_raw_uci_cmd_fira_gid_ok() {
+ let mt = 0x1;
+ let gid = 0x1; // SESSION_CONFIG GID.
+ let oid = 0x3;
+ let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
+ let cmd_payload_clone = cmd_payload.clone();
+ let resp_payload = vec![0x00, 0x01, 0x07, 0x00];
+ let status = StatusCode::UciStatusOk;
+ let cfg_id = AppConfigTlvType::DstMacAddress;
+ let app_config = AppConfigStatus { cfg_id, status };
+ let cfg_status = vec![app_config];
+
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ move |hal| {
+ let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone };
+ let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder {
+ status,
+ cfg_status,
+ });
+
+ hal.expected_send_command(cmd, resp, Ok(()));
+ },
+ UciLoggerMode::Disabled,
+ mpsc::unbounded_channel::<UciLogEvent>().0,
+ )
+ .await;
+
+ let expected_result = RawUciMessage { gid, oid, payload: resp_payload };
+ let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await.unwrap();
+ assert_eq!(result, expected_result);
+ assert!(mock_hal.wait_expected_calls_done().await);
+ }
+
+ #[tokio::test]
+ async fn test_raw_uci_cmd_undefined_mt_ok() {
+ let mt = 0x4;
+ let gid = 0x1; // SESSION_CONFIG GID.
+ let oid = 0x3;
+ let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
+ let cmd_payload_clone = cmd_payload.clone();
+ let resp_payload = vec![0x00, 0x01, 0x07, 0x00];
+ let status = StatusCode::UciStatusOk;
+ let cfg_id = AppConfigTlvType::DstMacAddress;
+ let app_config = AppConfigStatus { cfg_id, status };
+ let cfg_status = vec![app_config];
+
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ move |hal| {
+ let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone };
+ let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder {
+ status,
+ cfg_status,
+ });
+
+ hal.expected_send_command(cmd, resp, Ok(()));
+ },
+ UciLoggerMode::Disabled,
+ mpsc::unbounded_channel::<UciLogEvent>().0,
+ )
+ .await;
+
+ let expected_result = RawUciMessage { gid, oid, payload: resp_payload };
+ let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await.unwrap();
+ assert_eq!(result, expected_result);
+ assert!(mock_hal.wait_expected_calls_done().await);
+ }
+
+ #[tokio::test]
+ async fn test_raw_uci_cmd_custom_payload_format() {
+ // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the
+ // UCI HAL returns a UCI response with a custom payload format. The UCI response packet
+ // should still be successfully parsed and returned, since it's a Raw UCI RSP.
+ let cmd_mt: u8 = 0x1;
+ let gid: u8 = 0x1; // Session Config.
+ let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG
+ let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
+ let cmd_payload_clone = cmd_payload.clone();
+ let resp_mt: u8 = 0x2;
+ let resp_payload = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
+ let resp_payload_clone = resp_payload.clone();
+
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ move |hal| {
+ let cmd = UciCommand::RawUciCmd {
+ mt: cmd_mt.into(),
+ gid: gid.into(),
+ oid: oid.into(),
+ payload: cmd_payload_clone,
+ };
+ let resp = build_uci_packet(resp_mt, 0, gid, oid, resp_payload_clone);
+ hal.expected_send_command(cmd, vec![resp], Ok(()));
+ },
+ UciLoggerMode::Disabled,
+ mpsc::unbounded_channel::<UciLogEvent>().0,
+ )
+ .await;
+
+ let expected_result =
+ Ok(RawUciMessage { gid: gid.into(), oid: oid.into(), payload: resp_payload });
+ let result =
+ uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await;
+ assert_eq!(result, expected_result);
+ assert!(mock_hal.wait_expected_calls_done().await);
+ }
+
+ #[tokio::test]
+ async fn test_raw_uci_cmd_fragmented_responses() {
+ // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the
+ // UCI HAL returns a UCI response with a custom payload format, in 2 UCI packet fragments.
+ let cmd_mt: u8 = 0x1;
+ let gid: u8 = 0x1; // Session Config.
+ let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG
+ let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
+ let cmd_payload_clone = cmd_payload.clone();
+ let resp_mt: u8 = 0x2;
+ let resp_payload_fragment_1 = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
+ let resp_payload_fragment_2 = vec![0x09, 0x0a, 0x0b];
+ let mut resp_payload_expected = resp_payload_fragment_1.clone();
+ resp_payload_expected.extend(resp_payload_fragment_2.clone().into_iter());
+
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ move |hal| {
+ let cmd = UciCommand::RawUciCmd {
+ mt: cmd_mt.into(),
+ gid: gid.into(),
+ oid: oid.into(),
+ payload: cmd_payload_clone,
+ };
+ let resp_fragment_1 = build_uci_packet(
+ resp_mt,
+ /* pbf = */ 1,
+ gid,
+ oid,
+ resp_payload_fragment_1,
+ );
+ let resp_fragment_2 = build_uci_packet(
+ resp_mt,
+ /* pbf = */ 0,
+ gid,
+ oid,
+ resp_payload_fragment_2,
+ );
+ hal.expected_send_command(cmd, vec![resp_fragment_1, resp_fragment_2], Ok(()));
+ },
+ UciLoggerMode::Disabled,
+ mpsc::unbounded_channel::<UciLogEvent>().0,
+ )
+ .await;
+
+ let expected_result =
+ Ok(RawUciMessage { gid: gid.into(), oid: oid.into(), payload: resp_payload_expected });
+ let result =
+ uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await;
+ assert_eq!(result, expected_result);
+ assert!(mock_hal.wait_expected_calls_done().await);
+ }
+
+ #[tokio::test]
+ async fn test_raw_uci_cmd_wrong_gid() {
+ // Send a raw UCI command with CORE GID, but UCI HAL returns a UCI response with
+ // SESSION_CONFIG GID. In this case, UciManager should return Error::Unknown, as the
+ // RawUciSignature fields (GID, OID) of the CMD and RSP packets don't match.
+
+ let mt = 0x1;
+ let gid = 0x0; // CORE GID.
+ let oid = 0x1;
+ let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
+ let cmd_payload_clone = cmd_payload.clone();
+ let status = StatusCode::UciStatusOk;
+ let cfg_id = AppConfigTlvType::DstMacAddress;
+ let app_config = AppConfigStatus { cfg_id, status };
+ let cfg_status = vec![app_config];
+
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ move |hal| {
+ let cmd = UciCommand::RawUciCmd { mt, gid, oid, payload: cmd_payload_clone };
+ let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder {
+ status,
+ cfg_status,
+ });
+
+ hal.expected_send_command(cmd, resp, Ok(()));
+ },
+ UciLoggerMode::Disabled,
+ mpsc::unbounded_channel::<UciLogEvent>().0,
+ )
+ .await;
+
+ let expected_result = Err(Error::Unknown);
+ let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await;
+ assert_eq!(result, expected_result);
+ assert!(mock_hal.wait_expected_calls_done().await);
+ }
+
+ #[tokio::test]
+ async fn test_raw_uci_cmd_out_of_range_gid() {
+ // Send a raw UCI command with a GID value outside it's 8-bit size. This should result in
+ // an error since the input GID value cannot be encoded into the UCI packet.
+ let mt = 0x1;
+ let gid = 0x1FF;
+ let oid = 0x1;
+ let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
+
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ move |_hal| {},
+ UciLoggerMode::Disabled,
+ mpsc::unbounded_channel::<UciLogEvent>().0,
+ )
+ .await;
+
+ let expected_result = Err(Error::BadParameters);
+ let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await;
+ assert_eq!(result, expected_result);
+ assert!(mock_hal.wait_expected_calls_done().await);
+ }
+
+ #[tokio::test]
+ async fn test_raw_uci_cmd_out_of_range_oid() {
+ // Send a raw UCI command with a valid GID (CORE), but an OID value outside it's 8-bit
+ // size. This should result in an error since the input OID value cannot be encoded into
+ // the UCI packet.
+ let mt = 0x1;
+ let gid = 0x0; // CORE GID.
+ let oid = 0x1FF;
+ let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
+
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ move |_hal| {},
+ UciLoggerMode::Disabled,
+ mpsc::unbounded_channel::<UciLogEvent>().0,
+ )
+ .await;
+
+ let expected_result = Err(Error::BadParameters);
+ let result = uci_manager.raw_uci_cmd(mt, gid, oid, cmd_payload).await;
+ assert_eq!(result, expected_result);
+ assert!(mock_hal.wait_expected_calls_done().await);
+ }
+
+ #[tokio::test]
+ async fn test_raw_uci_cmd_uwbs_response_notification() {
+ // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the
+ // UCI HAL returns a valid UCI Notification packet before the raw UCI response.
+ let cmd_mt: u8 = 0x1;
+ let gid: u8 = 0x1; // Session Config.
+ let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG
+ let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
+ let cmd_payload_clone = cmd_payload.clone();
+ let session_id = 0x123;
+ let resp_mt: u8 = 0x2;
+ let resp_payload = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
+ let resp_payload_clone = resp_payload.clone();
+
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ move |hal| {
+ let cmd = UciCommand::RawUciCmd {
+ mt: cmd_mt.into(),
+ gid: gid.into(),
+ oid: oid.into(),
+ payload: cmd_payload_clone,
+ };
+ let raw_resp = build_uci_packet(resp_mt, 0, gid, oid, resp_payload_clone);
+ let mut responses =
+ into_uci_hal_packets(uwb_uci_packets::SessionStatusNtfBuilder {
+ session_id,
+ session_state: uwb_uci_packets::SessionState::SessionStateInit,
+ reason_code:
+ uwb_uci_packets::ReasonCode::StateChangeWithSessionManagementCommands
+ .into(),
+ });
+ responses.push(raw_resp);
+ hal.expected_send_command(cmd, responses, Ok(()));
+ },
+ UciLoggerMode::Disabled,
+ mpsc::unbounded_channel::<UciLogEvent>().0,
+ )
+ .await;
+
+ let expected_result =
+ Ok(RawUciMessage { gid: gid.into(), oid: oid.into(), payload: resp_payload });
+ let result =
+ uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await;
+ assert_eq!(result, expected_result);
+ assert!(mock_hal.wait_expected_calls_done().await);
+ }
+
+ #[tokio::test]
+ async fn test_raw_uci_cmd_uwbs_response_undefined_mt() {
+ // Send a raw UCI command with a FiRa defined GID, OID (SESSION_SET_APP_CONFIG), and the
+ // UCI HAL returns a UCI packet with an undefined MessageType in response.
+ let cmd_mt: u8 = 0x1;
+ let gid: u8 = 0x1; // Session Config.
+ let oid: u8 = 0x3; // SESSION_SET_APP_CONFIG
+ let cmd_payload = vec![0x11, 0x22, 0x33, 0x44];
+ let cmd_payload_clone = cmd_payload.clone();
+ let resp_mt: u8 = 0x7; // Undefined MessageType
+ let resp_payload = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
+
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ move |hal| {
+ let cmd = UciCommand::RawUciCmd {
+ mt: cmd_mt.into(),
+ gid: gid.into(),
+ oid: oid.into(),
+ payload: cmd_payload_clone,
+ };
+ let resp = build_uci_packet(resp_mt, /* pbf = */ 0, gid, oid, resp_payload);
+ hal.expected_send_command(cmd, vec![resp], Ok(()));
+ },
+ UciLoggerMode::Disabled,
+ mpsc::unbounded_channel::<UciLogEvent>().0,
+ )
+ .await;
+
+ let expected_result = Err(Error::Unknown);
+ let result =
+ uci_manager.raw_uci_cmd(cmd_mt.into(), gid.into(), oid.into(), cmd_payload).await;
assert_eq!(result, expected_result);
assert!(mock_hal.wait_expected_calls_done().await);
}
+ fn setup_active_session(hal: &mut MockUciHal, session_id: u32) {
+ // First setup the Session to be in Active state.
+ let cmd = UciCommand::SessionStart { session_id };
+ let mut responses = into_uci_hal_packets(uwb_uci_packets::SessionStartRspBuilder {
+ status: uwb_uci_packets::StatusCode::UciStatusOk,
+ });
+ responses.append(&mut into_uci_hal_packets(uwb_uci_packets::SessionStatusNtfBuilder {
+ session_id,
+ session_state: SessionState::SessionStateActive,
+ reason_code: 0, /* ReasonCode::StateChangeWithSessionManagementCommands */
+ }));
+ hal.expected_send_command(cmd, responses, Ok(()));
+ }
+
+ // TODO(b/276320369): Listing down the Data Packet Rx scenarios below, will add unit tests
+ // for them in subsequent CLs.
+ #[tokio::test]
+ async fn test_data_packet_recv_ok() {}
+
+ #[tokio::test]
+ async fn test_data_packet_recv_fragmented_packet_ok() {}
+
+ #[tokio::test]
+ async fn test_data_packet_send_ok() {
+ // Test Data packet send for a single packet (on a UWB session).
+ let mt_data = 0x0;
+ let pbf = 0x0;
+ let dpf = 0x1;
+ let oid = 0x0;
+ let session_id = 0x5;
+ let dest_mac_address = vec![0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1];
+ let dest_fira_component = FiraComponent::Host;
+ let uci_sequence_number = 0xa;
+ let app_data = vec![0x01, 0x02, 0x03];
+ let expected_data_snd_payload = vec![
+ 0x05, 0x00, 0x00, 0x00, // SessionID
+ 0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress
+ 0x01, // FiraComponent
+ 0x0a, // UciSequenceNumber
+ 0x03, 0x00, // AppDataLen
+ 0x01, 0x02, 0x03, // AppData
+ ];
+ let status = DataTransferNtfStatusCode::UciDataTransferStatusRepetitionOk;
+
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ move |hal| {
+ setup_active_session(hal, session_id);
+
+ // Now setup the notifications that should be received after a Data packet send.
+ let data_packet_snd =
+ build_uci_packet(mt_data, pbf, dpf, oid, expected_data_snd_payload);
+ let mut ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder {
+ session_id,
+ credit_availability: CreditAvailability::CreditAvailable,
+ });
+ ntfs.append(&mut into_uci_hal_packets(
+ uwb_uci_packets::DataTransferStatusNtfBuilder {
+ session_id,
+ uci_sequence_number,
+ status,
+ },
+ ));
+ hal.expected_send_packet(data_packet_snd, ntfs, Ok(()));
+ },
+ UciLoggerMode::Disabled,
+ mpsc::unbounded_channel::<UciLogEvent>().0,
+ )
+ .await;
+
+ let result = uci_manager.range_start(session_id).await;
+ assert!(result.is_ok());
+
+ let result = uci_manager
+ .send_data_packet(
+ session_id,
+ dest_mac_address,
+ dest_fira_component,
+ uci_sequence_number,
+ app_data,
+ )
+ .await;
+ assert!(result.is_ok());
+ assert!(mock_hal.wait_expected_calls_done().await);
+
+ // TODO(b/276320369): Verify that session_notf_sender is called (once implemented), as a
+ // DataTransferStatusNtf is received in this test scenario.
+ }
+
+ #[tokio::test]
+ async fn test_data_packet_send_fragmented_packet_ok() {
+ // Test Data packet send for a set of data packet fragments (on a UWB session).
+ let mt_data = 0x0;
+ let pbf_fragment_1 = 0x1;
+ let pbf_fragment_2 = 0x0;
+ let dpf = 0x1;
+ let oid = 0x0;
+ let session_id = 0x5;
+ let dest_mac_address = vec![0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1];
+ let dest_fira_component = FiraComponent::Host;
+ let uci_sequence_number = 0xa;
+ let app_data_len = 300; // Larger than MAX_PAYLOAD_LEN=255, so fragmentation occurs.
+ let mut app_data = Vec::new();
+ let mut expected_data_snd_payload_fragment_1 = vec![
+ 0x05, 0x00, 0x00, 0x00, // SessionID
+ 0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress
+ 0x01, // FiraComponent
+ 0x0a, // UciSequenceNumber
+ 0x2c, 0x01, // AppDataLen = 300
+ ];
+ let mut expected_data_snd_payload_fragment_2 = Vec::new();
+ let status = DataTransferNtfStatusCode::UciDataTransferStatusRepetitionOk;
+
+ // Setup the app data for both the Tx data packet and expected packet fragments.
+ let app_data_len_fragment_1 = 255 - expected_data_snd_payload_fragment_1.len();
+ for i in 0..app_data_len {
+ app_data.push((i & 0xff).try_into().unwrap());
+ if i < app_data_len_fragment_1 {
+ expected_data_snd_payload_fragment_1.push((i & 0xff).try_into().unwrap());
+ } else {
+ expected_data_snd_payload_fragment_2.push((i & 0xff).try_into().unwrap());
+ }
+ }
+
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ move |hal| {
+ setup_active_session(hal, session_id);
+
+ // Expected data packet fragment #1 (UCI Header + Initial App data bytes).
+ let data_packet_snd_fragment_1 = build_uci_packet(
+ mt_data,
+ pbf_fragment_1,
+ dpf,
+ oid,
+ expected_data_snd_payload_fragment_1,
+ );
+ let ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder {
+ session_id,
+ credit_availability: CreditAvailability::CreditAvailable,
+ });
+ hal.expected_send_packet(data_packet_snd_fragment_1, ntfs, Ok(()));
+
+ // Expected data packet fragment #2 (UCI Header + Remaining App data bytes).
+ let data_packet_snd_fragment_2 = build_uci_packet(
+ mt_data,
+ pbf_fragment_2,
+ dpf,
+ oid,
+ expected_data_snd_payload_fragment_2,
+ );
+ let mut ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder {
+ session_id,
+ credit_availability: CreditAvailability::CreditAvailable,
+ });
+ ntfs.append(&mut into_uci_hal_packets(
+ uwb_uci_packets::DataTransferStatusNtfBuilder {
+ session_id,
+ uci_sequence_number,
+ status,
+ },
+ ));
+ hal.expected_send_packet(data_packet_snd_fragment_2, ntfs, Ok(()));
+ },
+ UciLoggerMode::Disabled,
+ mpsc::unbounded_channel::<UciLogEvent>().0,
+ )
+ .await;
+
+ let result = uci_manager.range_start(session_id).await;
+ assert!(result.is_ok());
+
+ let result = uci_manager
+ .send_data_packet(
+ session_id,
+ dest_mac_address,
+ dest_fira_component,
+ uci_sequence_number,
+ app_data,
+ )
+ .await;
+ assert!(result.is_ok());
+ assert!(mock_hal.wait_expected_calls_done().await);
+ }
+
+ #[tokio::test]
+ async fn test_data_packet_send_retry_ok() {
+ // Test Data packet send for a single packet (on a UWB session).
+ let mt_data = 0x0;
+ let pbf = 0x0;
+ let dpf = 0x1;
+ let oid = 0x0;
+ let session_id = 0x5;
+ let dest_mac_address = vec![0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1];
+ let dest_fira_component = FiraComponent::Host;
+ let uci_sequence_number = 0xa;
+ let app_data = vec![0x01, 0x02, 0x03];
+ let expected_data_snd_payload = vec![
+ 0x05, 0x00, 0x00, 0x00, // SessionID
+ 0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress
+ 0x01, // FiraComponent
+ 0x0a, // UciSequenceNumber
+ 0x03, 0x00, // AppDataLen
+ 0x01, 0x02, 0x03, // AppData
+ ];
+ let status = DataTransferNtfStatusCode::UciDataTransferStatusRepetitionOk;
+
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ move |hal| {
+ setup_active_session(hal, session_id);
+
+ // Setup receiving a CORE_GENERIC_ERROR_NTF with STATUS_COMMAND_RETRY after a
+ // failed Data packet send attempt.
+ let data_packet_snd =
+ build_uci_packet(mt_data, pbf, dpf, oid, expected_data_snd_payload);
+ let error_ntf = into_uci_hal_packets(uwb_uci_packets::GenericErrorBuilder {
+ status: StatusCode::UciStatusCommandRetry,
+ });
+ hal.expected_send_packet(data_packet_snd.clone(), error_ntf, Ok(()));
+
+ // Setup the notifications that should be received after the Data packet send
+ // is successfully retried.
+ let mut ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder {
+ session_id,
+ credit_availability: CreditAvailability::CreditAvailable,
+ });
+ ntfs.append(&mut into_uci_hal_packets(
+ uwb_uci_packets::DataTransferStatusNtfBuilder {
+ session_id,
+ uci_sequence_number,
+ status,
+ },
+ ));
+ hal.expected_send_packet(data_packet_snd, ntfs, Ok(()));
+ },
+ UciLoggerMode::Disabled,
+ mpsc::unbounded_channel::<UciLogEvent>().0,
+ )
+ .await;
+
+ let result = uci_manager.range_start(session_id).await;
+ assert!(result.is_ok());
+
+ let result = uci_manager
+ .send_data_packet(
+ session_id,
+ dest_mac_address,
+ dest_fira_component,
+ uci_sequence_number,
+ app_data,
+ )
+ .await;
+ assert!(result.is_ok());
+ assert!(mock_hal.wait_expected_calls_done().await);
+
+ // TODO(b/276320369): Verify that session_notf_sender is called (once implemented), as a
+ // DataTransferStatusNtf is received in this test scenario.
+ }
+
+ // TODO(b/276320369): Listing down the Data Packet Tx scenarios below, will add unit tests
+ // for them in subsequent CLs.
+
+ // Sending one data packet should succeed, when no DataCreditNtf is received.
+ #[tokio::test]
+ async fn test_data_packet_send_missing_data_credit_ntf_success() {}
+
+ // Sending the second data packet should fail, when no DataCreditNtf is received after
+ // sending the first data packet.
+ #[tokio::test]
+ async fn test_data_packet_send_missing_data_credit_ntf_subsequent_send_failure() {}
+
+ #[tokio::test]
+ async fn test_data_packet_send_data_credit_ntf_bad_session_id() {}
+
+ #[tokio::test]
+ async fn test_data_packet_send_data_credit_ntf_no_credit_available() {}
+
+ #[tokio::test]
+ async fn test_data_packet_send_missing_data_transfer_status_ntf() {}
+
+ #[tokio::test]
+ async fn test_data_packet_send_data_transfer_status_ntf_bad_session_id() {}
+
+ #[tokio::test]
+ async fn test_data_packet_send_data_transfer_status_ntf_bad_uci_sequence_number() {}
+
+ // Tests for the multiple Status values that indicate success
+ #[tokio::test]
+ async fn test_data_packet_send_data_transfer_status_ntf_status_ok() {}
+
+ #[tokio::test]
+ async fn test_data_packet_send_data_transfer_status_ntf_status_repetition_ok() {}
+
+ // Tests for some of the multiple Status values that indicate error.
+ #[tokio::test]
+ async fn test_data_packet_send_data_transfer_status_ntf_status_error() {}
+
#[tokio::test]
async fn test_session_get_count_retry_no_response() {
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
|hal| {
let cmd = UciCommand::SessionGetCount;
hal.expected_send_command(cmd, vec![], Ok(()));
@@ -1455,7 +2485,7 @@ mod tests {
#[tokio::test]
async fn test_session_get_count_timeout() {
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
|hal| {
let cmd = UciCommand::SessionGetCount;
hal.expected_send_command(cmd, vec![], Err(Error::Timeout));
@@ -1472,7 +2502,7 @@ mod tests {
#[tokio::test]
async fn test_session_get_count_retry_too_many_times() {
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
|hal| {
let cmd = UciCommand::SessionGetCount;
let retry_resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder {
@@ -1498,7 +2528,7 @@ mod tests {
async fn test_session_get_count_retry_notification() {
let session_count = 5;
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
let cmd = UciCommand::SessionGetCount;
let retry_resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder {
@@ -1527,7 +2557,7 @@ mod tests {
#[tokio::test]
async fn test_log_manager_interaction() {
let (log_sender, mut log_receiver) = mpsc::unbounded_channel::<UciLogEvent>();
- let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+ let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
move |hal| {
let cmd = UciCommand::SessionGetCount;
let resp1 = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder {
diff --git a/src/rust/uwb_core/src/uci/uci_manager_sync.rs b/src/rust/uwb_core/src/uci/uci_manager_sync.rs
index c2cb59f..0c62959 100644
--- a/src/rust/uwb_core/src/uci/uci_manager_sync.rs
+++ b/src/rust/uwb_core/src/uci/uci_manager_sync.rs
@@ -15,8 +15,9 @@
//! This module offers a synchornized interface at UCI level.
//!
//! The module is designed with the replacement for Android UCI JNI adaptation in mind. The handling
-//! of UciNotifications is different in UciManager and UciManagerSync as the sync version has its
-//! behavior aligned with the Android JNI UCI, and routes the UciNotifications to NotificationManager.
+//! of UciNotifications is different in UciManager and UciManagerSyncImpl as the sync version has
+//! its behavior aligned with the Android JNI UCI, and routes the UciNotifications to
+//! NotificationManager.
use log::{debug, error};
use tokio::runtime::{Builder as RuntimeBuilder, Handle};
@@ -25,19 +26,20 @@ use tokio::task;
use crate::error::{Error, Result};
use crate::params::{
- AppConfigTlv, AppConfigTlvType, CapTlv, Controlee, CoreSetConfigResponse, CountryCode,
- DeviceConfigId, DeviceConfigTlv, GetDeviceInfoResponse, PowerStats, RawVendorMessage,
- ResetConfig, SessionId, SessionState, SessionType, SetAppConfigResponse,
- UpdateMulticastListAction,
+ AppConfigTlv, AppConfigTlvType, CapTlv, CoreSetConfigResponse, CountryCode, DeviceConfigId,
+ DeviceConfigTlv, FiraComponent, GetDeviceInfoResponse, PowerStats, RawUciMessage, ResetConfig,
+ SessionId, SessionState, SessionType, SessionUpdateDtTagRangingRoundsResponse,
+ SetAppConfigResponse, UpdateMulticastListAction,
};
-use crate::uci::notification::{CoreNotification, SessionNotification};
+#[cfg(any(test, feature = "mock-utils"))]
+use crate::uci::mock_uci_manager::MockUciManager;
+use crate::uci::notification::{CoreNotification, DataRcvNotification, SessionNotification};
use crate::uci::uci_hal::UciHal;
use crate::uci::uci_logger::{UciLogger, UciLoggerMode};
use crate::uci::uci_manager::{UciManager, UciManagerImpl};
-use uwb_uci_packets::ControleesV2;
+use uwb_uci_packets::Controlees;
-/// The NotificationManager trait is needed to process UciNotification relayed from UciManagerSync.
-///
+/// The NotificationManager processes UciNotification relayed from UciManagerSync in a sync fashion.
/// The UciManagerSync assumes the NotificationManager takes the responsibility to properly handle
/// the notifications, including tracking the state of HAL. UciManagerSync and lower levels only
/// redirect and categorize the notifications. The notifications are processed through callbacks.
@@ -49,33 +51,44 @@ pub trait NotificationManager: 'static {
/// Callback for SessionNotification.
fn on_session_notification(&mut self, session_notification: SessionNotification) -> Result<()>;
- /// Callback for RawVendorMessage.
- fn on_vendor_notification(&mut self, vendor_notification: RawVendorMessage) -> Result<()>;
+ /// Callback for RawUciMessage.
+ fn on_vendor_notification(&mut self, vendor_notification: RawUciMessage) -> Result<()>;
+
+ /// Callback for DataRcvNotification.
+ fn on_data_rcv_notification(
+ &mut self,
+ data_rcv_notification: DataRcvNotification,
+ ) -> Result<()>;
}
/// Builder for NotificationManager. Builder is sent between threads.
-pub trait NotificationManagerBuilder<T: NotificationManager>: 'static + Send + Sync {
+pub trait NotificationManagerBuilder: 'static + Send + Sync {
+ /// Type of NotificationManager built.
+ type NotificationManager: NotificationManager;
/// Builds NotificationManager. The build operation Consumes Builder.
- fn build(self) -> Option<T>;
+ fn build(self) -> Option<Self::NotificationManager>;
}
struct NotificationDriver<U: NotificationManager> {
core_notification_receiver: mpsc::UnboundedReceiver<CoreNotification>,
session_notification_receiver: mpsc::UnboundedReceiver<SessionNotification>,
- vendor_notification_receiver: mpsc::UnboundedReceiver<RawVendorMessage>,
+ vendor_notification_receiver: mpsc::UnboundedReceiver<RawUciMessage>,
+ data_rcv_notification_receiver: mpsc::UnboundedReceiver<DataRcvNotification>,
notification_manager: U,
}
impl<U: NotificationManager> NotificationDriver<U> {
fn new(
core_notification_receiver: mpsc::UnboundedReceiver<CoreNotification>,
session_notification_receiver: mpsc::UnboundedReceiver<SessionNotification>,
- vendor_notification_receiver: mpsc::UnboundedReceiver<RawVendorMessage>,
+ vendor_notification_receiver: mpsc::UnboundedReceiver<RawUciMessage>,
+ data_rcv_notification_receiver: mpsc::UnboundedReceiver<DataRcvNotification>,
notification_manager: U,
) -> Self {
Self {
core_notification_receiver,
session_notification_receiver,
vendor_notification_receiver,
+ data_rcv_notification_receiver,
notification_manager,
}
}
@@ -94,7 +107,12 @@ impl<U: NotificationManager> NotificationDriver<U> {
}
Some(ntf) = self.vendor_notification_receiver.recv() =>{
self.notification_manager.on_vendor_notification(ntf).unwrap_or_else(|e|{
- error!("NotificationDriver: RawVendorMessage callback error: {:?}",e);
+ error!("NotificationDriver: RawUciMessage callback error: {:?}",e);
+ });
+ }
+ Some(data) = self.data_rcv_notification_receiver.recv() =>{
+ self.notification_manager.on_data_rcv_notification(data).unwrap_or_else(|e|{
+ error!("NotificationDriver: OnDataRcv callback error: {:?}",e);
});
}
else =>{
@@ -105,44 +123,37 @@ impl<U: NotificationManager> NotificationDriver<U> {
}
}
}
-/// The UciManagerSync provides a synchornized version of UciManager using the runtime supplied
-/// at its initialization.
+
+/// The UciManagerSync provides a synchornized version of UciManager.
///
-/// Note the processing of UciNotification is different: they are handled by NotificationManager
-/// provided at construction, and the async version set_X_notification_sender methods are removed.
-pub struct UciManagerSync {
+/// Note the processing of UciNotification is different:
+/// set_X_notification_sender methods are removed. Instead, the method
+/// redirect_notification(NotificationManagerBuilder) is introduced to avoid the
+/// exposure of async tokio::mpsc.
+pub struct UciManagerSync<U: UciManager> {
runtime_handle: Handle,
- uci_manager_impl: UciManagerImpl,
+ uci_manager: U,
}
-impl UciManagerSync {
- /// UciHal and NotificationManagerBuilder required at construction as they are required before
- /// open_hal is called. runtime_handle must be a Handle to a multithread runtime that outlives
- /// UciManagerSync.
- pub fn new<T, U, V, W>(
- hal: T,
- notification_manager_builder: V,
- logger: W,
- runtime_handle: Handle,
- ) -> Result<Self>
- where
- T: UciHal,
- U: NotificationManager,
- V: NotificationManagerBuilder<U>,
- W: UciLogger,
- {
- // UciManagerImpl::new uses tokio::spawn, so it is called inside the runtime as async fn.
- let mut uci_manager_impl = runtime_handle
- .block_on(async { UciManagerImpl::new(hal, logger, UciLoggerMode::Disabled) });
+impl<U: UciManager> UciManagerSync<U> {
+ /// Redirects notification to a new NotificationManager using the notification_manager_builder.
+ /// The NotificationManager will live on a separate thread.
+ pub fn redirect_notification<T: NotificationManagerBuilder>(
+ &mut self,
+ notification_manager_builder: T,
+ ) -> Result<()> {
let (core_notification_sender, core_notification_receiver) =
mpsc::unbounded_channel::<CoreNotification>();
let (session_notification_sender, session_notification_receiver) =
mpsc::unbounded_channel::<SessionNotification>();
let (vendor_notification_sender, vendor_notification_receiver) =
- mpsc::unbounded_channel::<RawVendorMessage>();
- runtime_handle.block_on(async {
- uci_manager_impl.set_core_notification_sender(core_notification_sender).await;
- uci_manager_impl.set_session_notification_sender(session_notification_sender).await;
- uci_manager_impl.set_vendor_notification_sender(vendor_notification_sender).await;
+ mpsc::unbounded_channel::<RawUciMessage>();
+ let (data_rcv_notification_sender, data_rcv_notification_receiver) =
+ mpsc::unbounded_channel::<DataRcvNotification>();
+ self.runtime_handle.to_owned().block_on(async {
+ self.uci_manager.set_core_notification_sender(core_notification_sender).await;
+ self.uci_manager.set_session_notification_sender(session_notification_sender).await;
+ self.uci_manager.set_vendor_notification_sender(vendor_notification_sender).await;
+ self.uci_manager.set_data_rcv_notification_sender(data_rcv_notification_sender).await;
});
// The potentially !Send NotificationManager is created in a separate thread.
let (driver_status_sender, mut driver_status_receiver) = mpsc::unbounded_channel::<bool>();
@@ -174,6 +185,7 @@ impl UciManagerSync {
core_notification_receiver,
session_notification_receiver,
vendor_notification_receiver,
+ data_rcv_notification_receiver,
notification_manager,
);
local.spawn_local(async move {
@@ -182,156 +194,220 @@ impl UciManagerSync {
notification_runtime.block_on(local);
});
match driver_status_receiver.blocking_recv() {
- Some(true) => Ok(Self { runtime_handle, uci_manager_impl }),
+ Some(true) => Ok(()),
_ => Err(Error::Unknown),
}
}
- /// Set UCI logger mode
- pub fn set_logger_mode(&mut self, logger_mode: UciLoggerMode) -> Result<()> {
- self.runtime_handle.block_on(self.uci_manager_impl.set_logger_mode(logger_mode))
+ /// Set logger mode.
+ pub fn set_logger_mode(&self, logger_mode: UciLoggerMode) -> Result<()> {
+ self.runtime_handle.block_on(self.uci_manager.set_logger_mode(logger_mode))
}
/// Start UCI HAL and blocking until UCI commands can be sent.
- pub fn open_hal(&mut self) -> Result<()> {
- self.runtime_handle.block_on(self.uci_manager_impl.open_hal())
+ pub fn open_hal(&self) -> Result<()> {
+ self.runtime_handle.block_on(self.uci_manager.open_hal())
}
/// Stop the UCI HAL.
- pub fn close_hal(&mut self, force: bool) -> Result<()> {
- self.runtime_handle.block_on(self.uci_manager_impl.close_hal(force))
+ pub fn close_hal(&self, force: bool) -> Result<()> {
+ self.runtime_handle.block_on(self.uci_manager.close_hal(force))
}
// Methods for sending UCI commands. Functions are blocked until UCI response is received.
/// Send UCI command for device reset.
- pub fn device_reset(&mut self, reset_config: ResetConfig) -> Result<()> {
- self.runtime_handle.block_on(self.uci_manager_impl.device_reset(reset_config))
+ pub fn device_reset(&self, reset_config: ResetConfig) -> Result<()> {
+ self.runtime_handle.block_on(self.uci_manager.device_reset(reset_config))
}
/// Send UCI command for getting device info.
- pub fn core_get_device_info(&mut self) -> Result<GetDeviceInfoResponse> {
- self.runtime_handle.block_on(self.uci_manager_impl.core_get_device_info())
+ pub fn core_get_device_info(&self) -> Result<GetDeviceInfoResponse> {
+ self.runtime_handle.block_on(self.uci_manager.core_get_device_info())
}
/// Send UCI command for getting capability info
- pub fn core_get_caps_info(&mut self) -> Result<Vec<CapTlv>> {
- self.runtime_handle.block_on(self.uci_manager_impl.core_get_caps_info())
+ pub fn core_get_caps_info(&self) -> Result<Vec<CapTlv>> {
+ self.runtime_handle.block_on(self.uci_manager.core_get_caps_info())
}
/// Send UCI command for setting core configuration.
pub fn core_set_config(
- &mut self,
+ &self,
config_tlvs: Vec<DeviceConfigTlv>,
) -> Result<CoreSetConfigResponse> {
- self.runtime_handle.block_on(self.uci_manager_impl.core_set_config(config_tlvs))
+ self.runtime_handle.block_on(self.uci_manager.core_set_config(config_tlvs))
}
/// Send UCI command for getting core configuration.
- pub fn core_get_config(
- &mut self,
- config_ids: Vec<DeviceConfigId>,
- ) -> Result<Vec<DeviceConfigTlv>> {
- self.runtime_handle.block_on(self.uci_manager_impl.core_get_config(config_ids))
+ pub fn core_get_config(&self, config_ids: Vec<DeviceConfigId>) -> Result<Vec<DeviceConfigTlv>> {
+ self.runtime_handle.block_on(self.uci_manager.core_get_config(config_ids))
}
/// Send UCI command for initiating session.
- pub fn session_init(&mut self, session_id: SessionId, session_type: SessionType) -> Result<()> {
- self.runtime_handle.block_on(self.uci_manager_impl.session_init(session_id, session_type))
+ pub fn session_init(&self, session_id: SessionId, session_type: SessionType) -> Result<()> {
+ self.runtime_handle.block_on(self.uci_manager.session_init(session_id, session_type))
}
/// Send UCI command for deinitiating session.
- pub fn session_deinit(&mut self, session_id: SessionId) -> Result<()> {
- self.runtime_handle.block_on(self.uci_manager_impl.session_deinit(session_id))
+ pub fn session_deinit(&self, session_id: SessionId) -> Result<()> {
+ self.runtime_handle.block_on(self.uci_manager.session_deinit(session_id))
}
/// Send UCI command for setting app config.
pub fn session_set_app_config(
- &mut self,
+ &self,
session_id: SessionId,
config_tlvs: Vec<AppConfigTlv>,
) -> Result<SetAppConfigResponse> {
self.runtime_handle
- .block_on(self.uci_manager_impl.session_set_app_config(session_id, config_tlvs))
+ .block_on(self.uci_manager.session_set_app_config(session_id, config_tlvs))
}
/// Send UCI command for getting app config.
pub fn session_get_app_config(
- &mut self,
+ &self,
session_id: SessionId,
config_ids: Vec<AppConfigTlvType>,
) -> Result<Vec<AppConfigTlv>> {
self.runtime_handle
- .block_on(self.uci_manager_impl.session_get_app_config(session_id, config_ids))
+ .block_on(self.uci_manager.session_get_app_config(session_id, config_ids))
}
/// Send UCI command for getting count of sessions.
- pub fn session_get_count(&mut self) -> Result<u8> {
- self.runtime_handle.block_on(self.uci_manager_impl.session_get_count())
+ pub fn session_get_count(&self) -> Result<u8> {
+ self.runtime_handle.block_on(self.uci_manager.session_get_count())
}
/// Send UCI command for getting state of session.
- pub fn session_get_state(&mut self, session_id: SessionId) -> Result<SessionState> {
- self.runtime_handle.block_on(self.uci_manager_impl.session_get_state(session_id))
+ pub fn session_get_state(&self, session_id: SessionId) -> Result<SessionState> {
+ self.runtime_handle.block_on(self.uci_manager.session_get_state(session_id))
}
/// Send UCI command for updating multicast list for multicast session.
pub fn session_update_controller_multicast_list(
- &mut self,
+ &self,
session_id: SessionId,
action: UpdateMulticastListAction,
- controlees: Vec<Controlee>,
+ controlees: Controlees,
) -> Result<()> {
self.runtime_handle.block_on(
- self.uci_manager_impl
+ self.uci_manager
.session_update_controller_multicast_list(session_id, action, controlees),
)
}
- /// Send UCI command for updating multicast list for multicast session (Provisioned STS).
- pub fn session_update_controller_multicast_list_v2(
- &mut self,
- session_id: SessionId,
- action: UpdateMulticastListAction,
- controlees: ControleesV2,
- ) -> Result<()> {
+ /// Update ranging rounds for DT Tag
+ pub fn session_update_dt_tag_ranging_rounds(
+ &self,
+ session_id: u32,
+ ranging_round_indexes: Vec<u8>,
+ ) -> Result<SessionUpdateDtTagRangingRoundsResponse> {
self.runtime_handle.block_on(
- self.uci_manager_impl
- .session_update_controller_multicast_list_v2(session_id, action, controlees),
+ self.uci_manager
+ .session_update_dt_tag_ranging_rounds(session_id, ranging_round_indexes),
)
}
+ /// Send UCI command for getting max data size for session.
+ pub fn session_query_max_data_size(&self, session_id: SessionId) -> Result<u16> {
+ self.runtime_handle.block_on(self.uci_manager.session_query_max_data_size(session_id))
+ }
+
/// Send UCI command for starting ranging of the session.
- pub fn range_start(&mut self, session_id: SessionId) -> Result<()> {
- self.runtime_handle.block_on(self.uci_manager_impl.range_start(session_id))
+ pub fn range_start(&self, session_id: SessionId) -> Result<()> {
+ self.runtime_handle.block_on(self.uci_manager.range_start(session_id))
}
/// Send UCI command for stopping ranging of the session.
- pub fn range_stop(&mut self, session_id: SessionId) -> Result<()> {
- self.runtime_handle.block_on(self.uci_manager_impl.range_stop(session_id))
+ pub fn range_stop(&self, session_id: SessionId) -> Result<()> {
+ self.runtime_handle.block_on(self.uci_manager.range_stop(session_id))
}
/// Send UCI command for getting ranging count.
- pub fn range_get_ranging_count(&mut self, session_id: SessionId) -> Result<usize> {
- self.runtime_handle.block_on(self.uci_manager_impl.range_get_ranging_count(session_id))
+ pub fn range_get_ranging_count(&self, session_id: SessionId) -> Result<usize> {
+ self.runtime_handle.block_on(self.uci_manager.range_get_ranging_count(session_id))
}
/// Set the country code. Android-specific method.
- pub fn android_set_country_code(&mut self, country_code: CountryCode) -> Result<()> {
- self.runtime_handle.block_on(self.uci_manager_impl.android_set_country_code(country_code))
+ pub fn android_set_country_code(&self, country_code: CountryCode) -> Result<()> {
+ self.runtime_handle.block_on(self.uci_manager.android_set_country_code(country_code))
}
/// Get the power statistics. Android-specific method.
- pub fn android_get_power_stats(&mut self) -> Result<PowerStats> {
- self.runtime_handle.block_on(self.uci_manager_impl.android_get_power_stats())
+ pub fn android_get_power_stats(&self) -> Result<PowerStats> {
+ self.runtime_handle.block_on(self.uci_manager.android_get_power_stats())
}
- /// Send UCI command for a vendor-specific message.
- pub fn raw_vendor_cmd(
- &mut self,
+ /// Send a raw UCI command.
+ pub fn raw_uci_cmd(
+ &self,
+ mt: u32,
gid: u32,
oid: u32,
payload: Vec<u8>,
- ) -> Result<RawVendorMessage> {
- self.runtime_handle.block_on(self.uci_manager_impl.raw_vendor_cmd(gid, oid, payload))
+ ) -> Result<RawUciMessage> {
+ self.runtime_handle.block_on(self.uci_manager.raw_uci_cmd(mt, gid, oid, payload))
+ }
+
+ /// Send a data packet
+ pub fn send_data_packet(
+ &self,
+ session_id: SessionId,
+ address: Vec<u8>,
+ dest_end_point: FiraComponent,
+ uci_sequence_num: u8,
+ app_payload_data: Vec<u8>,
+ ) -> Result<()> {
+ self.runtime_handle.block_on(self.uci_manager.send_data_packet(
+ session_id,
+ address,
+ dest_end_point,
+ uci_sequence_num,
+ app_payload_data,
+ ))
+ }
+}
+
+impl UciManagerSync<UciManagerImpl> {
+ /// Constructor.
+ ///
+ /// UciHal and NotificationManagerBuilder required at construction as they are required before
+ /// open_hal is called. runtime_handle must be a Handle to a multithread runtime that outlives
+ /// UciManagerSyncImpl.
+ ///
+ /// Implementation note: An explicit decision is made to not use UciManagerImpl as a parameter.
+ /// UciManagerImpl::new() appears to be sync, but needs an async context to be called, but the
+ /// user is unlikely to be aware of this technicality.
+ pub fn new<H, B, L>(
+ hal: H,
+ notification_manager_builder: B,
+ logger: L,
+ runtime_handle: Handle,
+ ) -> Result<Self>
+ where
+ H: UciHal,
+ B: NotificationManagerBuilder,
+ L: UciLogger,
+ {
+ // UciManagerImpl::new uses tokio::spawn, so it is called inside the runtime as async fn.
+ let uci_manager = runtime_handle
+ .block_on(async { UciManagerImpl::new(hal, logger, UciLoggerMode::Disabled) });
+ let mut uci_manager_sync = UciManagerSync { runtime_handle, uci_manager };
+ uci_manager_sync.redirect_notification(notification_manager_builder)?;
+ Ok(uci_manager_sync)
+ }
+}
+
+#[cfg(any(test, feature = "mock-utils"))]
+impl UciManagerSync<MockUciManager> {
+ /// Constructor for mock version.
+ pub fn new_mock<T: NotificationManagerBuilder>(
+ uci_manager: MockUciManager,
+ runtime_handle: Handle,
+ notification_manager_builder: T,
+ ) -> Result<Self> {
+ let mut uci_manager_sync = UciManagerSync { uci_manager, runtime_handle };
+ uci_manager_sync.redirect_notification(notification_manager_builder)?;
+ Ok(uci_manager_sync)
}
}
@@ -343,80 +419,98 @@ mod tests {
use std::rc::Rc;
use tokio::runtime::Builder;
- use uwb_uci_packets::DeviceState;
+ use uwb_uci_packets::DeviceState::DeviceStateReady;
- use crate::error::Error;
- use crate::uci::mock_uci_hal::MockUciHal;
- use crate::uci::uci_hal::UciHalPacket;
- use crate::uci::uci_logger::UciLoggerNull;
+ use crate::params::uci_packets::GetDeviceInfoResponse;
+ use crate::uci::mock_uci_manager::MockUciManager;
+ use crate::uci::{CoreNotification, UciNotification};
+ /// Mock NotificationManager forwarding notifications received.
+ /// The nonsend_counter is deliberately !send to check UciManagerSync::redirect_notification.
struct MockNotificationManager {
- device_state_sender: mpsc::UnboundedSender<DeviceState>,
+ notf_sender: mpsc::UnboundedSender<UciNotification>,
// nonsend_counter is an example of a !Send property.
nonsend_counter: Rc<RefCell<usize>>,
}
+
impl NotificationManager for MockNotificationManager {
fn on_core_notification(&mut self, core_notification: CoreNotification) -> Result<()> {
- match core_notification {
- CoreNotification::DeviceStatus(device_state) => {
- self.nonsend_counter.replace_with(|&mut prev| prev + 1);
- self.device_state_sender.send(device_state).map_err(|_| Error::Unknown)?;
- }
- CoreNotification::GenericError(_) => {}
- };
- Ok(())
+ self.nonsend_counter.replace_with(|&mut prev| prev + 1);
+ self.notf_sender
+ .send(UciNotification::Core(core_notification))
+ .map_err(|_| Error::Unknown)
}
fn on_session_notification(
&mut self,
- _session_notification: SessionNotification,
+ session_notification: SessionNotification,
) -> Result<()> {
- Ok(())
+ self.nonsend_counter.replace_with(|&mut prev| prev + 1);
+ self.notf_sender
+ .send(UciNotification::Session(session_notification))
+ .map_err(|_| Error::Unknown)
}
- fn on_vendor_notification(&mut self, _vendor_notification: RawVendorMessage) -> Result<()> {
+ fn on_vendor_notification(&mut self, vendor_notification: RawUciMessage) -> Result<()> {
+ self.nonsend_counter.replace_with(|&mut prev| prev + 1);
+ self.notf_sender
+ .send(UciNotification::Vendor(vendor_notification))
+ .map_err(|_| Error::Unknown)
+ }
+ fn on_data_rcv_notification(&mut self, _data_rcv_notf: DataRcvNotification) -> Result<()> {
+ self.nonsend_counter.replace_with(|&mut prev| prev + 1);
Ok(())
}
}
+ /// Builder for MockNotificationManager.
struct MockNotificationManagerBuilder {
- device_state_sender: mpsc::UnboundedSender<DeviceState>,
+ notf_sender: mpsc::UnboundedSender<UciNotification>,
// initial_count is an example for a parameter undetermined at compile time.
- initial_count: usize,
}
- impl NotificationManagerBuilder<MockNotificationManager> for MockNotificationManagerBuilder {
- fn build(self) -> Option<MockNotificationManager> {
- Some(MockNotificationManager {
- device_state_sender: self.device_state_sender,
- nonsend_counter: Rc::new(RefCell::new(self.initial_count)),
- })
+
+ impl MockNotificationManagerBuilder {
+ /// Constructor for builder.
+ fn new(notf_sender: mpsc::UnboundedSender<UciNotification>) -> Self {
+ Self { notf_sender }
}
}
- fn into_raw_messages<T: Into<uwb_uci_packets::UciPacketPacket>>(
- builder: T,
- ) -> Vec<UciHalPacket> {
- let packets: Vec<uwb_uci_packets::UciPacketHalPacket> = builder.into().into();
- packets.into_iter().map(|packet| packet.into()).collect()
+ impl NotificationManagerBuilder for MockNotificationManagerBuilder {
+ type NotificationManager = MockNotificationManager;
+
+ fn build(self) -> Option<Self::NotificationManager> {
+ Some(MockNotificationManager {
+ notf_sender: self.notf_sender,
+ nonsend_counter: Rc::new(RefCell::new(0)),
+ })
+ }
}
#[test]
- fn test_sync_uci_open_hal() {
- let mut hal = MockUciHal::new();
- let notf = into_raw_messages(uwb_uci_packets::DeviceStatusNtfBuilder {
- device_state: uwb_uci_packets::DeviceState::DeviceStateReady,
- });
- hal.expected_open(Some(notf), Ok(()));
+ /// Tests that the Command, Response, and Notification pipeline are functional.
+ fn test_sync_uci_basic_sequence() {
let test_rt = Builder::new_multi_thread().enable_all().build().unwrap();
- let (device_state_sender, mut device_state_receiver) =
- mpsc::unbounded_channel::<DeviceState>();
- let mut uci_manager_sync = UciManagerSync::new(
- hal,
- MockNotificationManagerBuilder { device_state_sender, initial_count: 0 },
- UciLoggerNull::default(),
+ let (notf_sender, mut notf_receiver) = mpsc::unbounded_channel::<UciNotification>();
+ let mut uci_manager_impl = MockUciManager::new();
+ uci_manager_impl.expect_open_hal(
+ vec![UciNotification::Core(CoreNotification::DeviceStatus(DeviceStateReady))],
+ Ok(()),
+ );
+ uci_manager_impl.expect_core_get_device_info(Ok(GetDeviceInfoResponse {
+ uci_version: 0,
+ mac_version: 0,
+ phy_version: 0,
+ uci_test_version: 0,
+ vendor_spec_info: vec![],
+ }));
+ let uci_manager_sync = UciManagerSync::new_mock(
+ uci_manager_impl,
test_rt.handle().to_owned(),
+ MockNotificationManagerBuilder::new(notf_sender),
)
.unwrap();
assert!(uci_manager_sync.open_hal().is_ok());
- let device_state = test_rt.block_on(async { device_state_receiver.recv().await });
- assert_eq!(device_state, Some(DeviceState::DeviceStateReady));
+ let device_state = test_rt.block_on(async { notf_receiver.recv().await });
+ assert!(device_state.is_some());
+ assert!(uci_manager_sync.core_get_device_info().is_ok());
}
}
diff --git a/src/rust/uwb_uci_packets/build.rs b/src/rust/uwb_uci_packets/build.rs
index 10ea8f1..f001de5 100644
--- a/src/rust/uwb_uci_packets/build.rs
+++ b/src/rust/uwb_uci_packets/build.rs
@@ -18,26 +18,27 @@ use std::process::Command;
fn main() {
let out_dir = std::env::var_os("OUT_DIR").unwrap();
let generated_file = "uci_packets.rs";
+ let dst_path = Path::new(&out_dir).join(generated_file);
if Path::new(generated_file).exists() {
// Copy the rust code directly if the file exists.
- let dst_path = Path::new(&out_dir).join(generated_file);
let result = std::fs::copy(generated_file, &dst_path);
eprintln!("{} exists, copy to {:?}: {:?}", generated_file, dst_path, result);
return;
}
- // Generate the rust code by bluetooth_packetgen.
- // The binary should be compiled by `m bluetooth_packetgen -j32` before calling cargo.
+ // The binary should be compiled by `m pdl` before calling cargo.
let output = Command::new("env")
- .arg("bluetooth_packetgen")
- .arg("--out=".to_owned() + out_dir.to_str().unwrap())
- .arg("--include=.")
- .arg("--rust")
+ .arg("pdl")
+ .arg("--output-format")
+ .arg("rust")
.arg("uci_packets.pdl")
.output()
.unwrap();
+ std::fs::write(&dst_path, &output.stdout)
+ .expect(&format!("Could not write {}", dst_path.display()));
+
eprintln!(
"Status: {}, stdout: {}, stderr: {}",
output.status,
diff --git a/src/rust/uwb_uci_packets/src/lib.rs b/src/rust/uwb_uci_packets/src/lib.rs
index dda91c0..c5bb3f5 100644
--- a/src/rust/uwb_uci_packets/src/lib.rs
+++ b/src/rust/uwb_uci_packets/src/lib.rs
@@ -22,6 +22,8 @@
use std::cmp;
use log::error;
+use num_derive::FromPrimitive;
+use num_traits::FromPrimitive;
use zeroize::Zeroize;
include!(concat!(env!("OUT_DIR"), "/uci_packets.rs"));
@@ -30,54 +32,376 @@ const MAX_PAYLOAD_LEN: usize = 255;
// TODO: Use a PDL struct to represent the headers and avoid hardcoding
// lengths below.
// Real UCI packet header len.
-const UCI_PACKET_HAL_HEADER_LEN: usize = 4;
+pub const UCI_PACKET_HAL_HEADER_LEN: usize = 4;
// Unfragmented UCI packet header len.
-const UCI_PACKET_HEADER_LEN: usize = 7;
+pub const UCI_PACKET_HEADER_LEN: usize = 7;
+// Unfragmented UCI DATA_MESSAGE_SND packet header len.
+const UCI_DATA_SND_PACKET_HEADER_LEN: usize = 6;
+
+// Opcode field byte position (within UCI packet header) and mask (of bits to be used).
+const UCI_HEADER_MT_BYTE_POSITION: usize = 0;
+const UCI_HEADER_MT_BIT_SHIFT: u8 = 5;
+const UCI_HEADER_MT_MASK: u8 = 0x7;
+
+const UCI_HEADER_PBF_BYTE_POSITION: usize = 0;
+const UCI_HEADER_PBF_BIT_SHIFT: u8 = 4;
+const UCI_HEADER_PBF_MASK: u8 = 0x1;
+
+const UCI_CONTROL_HEADER_GID_BYTE_POSITION: usize = 0;
+const UCI_CONTROL_HEADER_GID_MASK: u8 = 0xF;
+
+const UCI_CONTROL_HEADER_OID_BYTE_POSITION: usize = 1;
+const UCI_CONTROL_HEADER_OID_MASK: u8 = 0x3F;
+
+#[derive(Debug, Clone, PartialEq, FromPrimitive)]
+pub enum TimeStampLength {
+ Timestamp40Bit = 0x0,
+ Timestamp64Bit = 0x1,
+}
+
+#[derive(Debug, Clone, PartialEq, FromPrimitive)]
+pub enum DTAnchorLocationType {
+ NotIncluded = 0x0,
+ Wgs84 = 0x1,
+ Relative = 0x2,
+}
+
+#[allow(dead_code)]
+#[derive(Debug, Clone, PartialEq)]
+pub struct DlTdoaRangingMeasurement {
+ pub status: u8,
+ pub message_type: u8,
+ pub message_control: u16,
+ pub block_index: u16,
+ pub round_index: u8,
+ pub nlos: u8,
+ pub aoa_azimuth: u16,
+ pub aoa_azimuth_fom: u8,
+ pub aoa_elevation: u16,
+ pub aoa_elevation_fom: u8,
+ pub rssi: u8,
+ pub tx_timestamp: u64,
+ pub rx_timestamp: u64,
+ pub anchor_cfo: u16,
+ pub cfo: u16,
+ pub initiator_reply_time: u32,
+ pub responder_reply_time: u32,
+ pub initiator_responder_tof: u16,
+ pub dt_anchor_location: Vec<u8>,
+ pub ranging_rounds: Vec<u8>,
+ total_size: usize,
+}
+
+impl DlTdoaRangingMeasurement {
+ pub fn parse_one(bytes: &[u8]) -> Option<Self> {
+ let mut ptr = 0;
+ let status = extract_u8(bytes, &mut ptr, 1)?;
+ let message_type = extract_u8(bytes, &mut ptr, 1)?;
+ let message_control = extract_u16(bytes, &mut ptr, 2)?;
+ let block_index = extract_u16(bytes, &mut ptr, 2)?;
+ let round_index = extract_u8(bytes, &mut ptr, 1)?;
+ let nlos = extract_u8(bytes, &mut ptr, 1)?;
+ let aoa_azimuth = extract_u16(bytes, &mut ptr, 2)?;
+ let aoa_azimuth_fom = extract_u8(bytes, &mut ptr, 1)?;
+ let aoa_elevation = extract_u16(bytes, &mut ptr, 2)?;
+ let aoa_elevation_fom = extract_u8(bytes, &mut ptr, 1)?;
+ let rssi = extract_u8(bytes, &mut ptr, 1)?;
+ let tx_timestamp_length = (message_control >> 1) & 0x1;
+ let tx_timestamp = match TimeStampLength::from_u16(tx_timestamp_length)? {
+ TimeStampLength::Timestamp40Bit => extract_u64(bytes, &mut ptr, 5)?,
+ TimeStampLength::Timestamp64Bit => extract_u64(bytes, &mut ptr, 8)?,
+ };
+ let rx_timestamp_length = (message_control >> 3) & 0x1;
+ let rx_timestamp = match TimeStampLength::from_u16(rx_timestamp_length)? {
+ TimeStampLength::Timestamp40Bit => extract_u64(bytes, &mut ptr, 5)?,
+ TimeStampLength::Timestamp64Bit => extract_u64(bytes, &mut ptr, 8)?,
+ };
+ let anchor_cfo = extract_u16(bytes, &mut ptr, 2)?;
+ let cfo = extract_u16(bytes, &mut ptr, 2)?;
+ let initiator_reply_time = extract_u32(bytes, &mut ptr, 4)?;
+ let responder_reply_time = extract_u32(bytes, &mut ptr, 4)?;
+ let initiator_responder_tof = extract_u16(bytes, &mut ptr, 2)?;
+ let dt_location_type = (message_control >> 5) & 0x3;
+ let dt_anchor_location = match DTAnchorLocationType::from_u16(dt_location_type)? {
+ DTAnchorLocationType::Wgs84 => extract_vec(bytes, &mut ptr, 10)?,
+ DTAnchorLocationType::Relative => extract_vec(bytes, &mut ptr, 12)?,
+ _ => vec![],
+ };
+ let active_ranging_rounds = ((message_control >> 7) & 0xf) as u8;
+ let ranging_round = extract_vec(bytes, &mut ptr, active_ranging_rounds as usize)?;
+
+ Some(DlTdoaRangingMeasurement {
+ status,
+ message_type,
+ message_control,
+ block_index,
+ round_index,
+ nlos,
+ aoa_azimuth,
+ aoa_azimuth_fom,
+ aoa_elevation,
+ aoa_elevation_fom,
+ rssi,
+ tx_timestamp,
+ rx_timestamp,
+ anchor_cfo,
+ cfo,
+ initiator_reply_time,
+ responder_reply_time,
+ initiator_responder_tof,
+ dt_anchor_location: dt_anchor_location.to_vec(),
+ ranging_rounds: ranging_round.to_vec(),
+ total_size: ptr,
+ })
+ }
+ pub fn get_total_size(&self) -> usize {
+ self.total_size
+ }
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub struct ShortAddressDlTdoaRangingMeasurement {
+ pub mac_address: u16,
+ pub measurement: DlTdoaRangingMeasurement,
+}
+
+impl ShortAddressDlTdoaRangingMeasurement {
+ /// Parse the `payload` byte buffer from PDL to the vector of measurement.
+ pub fn parse(bytes: &[u8], no_of_ranging_measurement: u8) -> Option<Vec<Self>> {
+ let mut ptr = 0;
+ let mut measurements = vec![];
+ let mut count = 0;
+ while (count < no_of_ranging_measurement) {
+ let mac_address = extract_u16(bytes, &mut ptr, 2)?;
+ let rem = &bytes[ptr..];
+ let measurement = DlTdoaRangingMeasurement::parse_one(rem);
+ match measurement {
+ Some(measurement) => {
+ ptr += measurement.get_total_size();
+ measurements
+ .push(ShortAddressDlTdoaRangingMeasurement { mac_address, measurement });
+ count = count + 1;
+ }
+ None => return None,
+ }
+ }
+ Some(measurements)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub struct ExtendedAddressDlTdoaRangingMeasurement {
+ pub mac_address: u64,
+ pub measurement: DlTdoaRangingMeasurement,
+}
+
+impl ExtendedAddressDlTdoaRangingMeasurement {
+ /// Parse the `payload` byte buffer from PDL to the vector of measurement.
+ pub fn parse(bytes: &[u8], no_of_ranging_measurement: u8) -> Option<Vec<Self>> {
+ let mut ptr = 0;
+ let mut measurements = vec![];
+ let mut count = 0;
+ while (count < no_of_ranging_measurement) {
+ let mac_address = extract_u64(bytes, &mut ptr, 8)?;
+ let rem = &bytes[ptr..];
+ let measurement = DlTdoaRangingMeasurement::parse_one(rem);
+ match measurement {
+ Some(measurement) => {
+ ptr += measurement.get_total_size();
+ measurements
+ .push(ExtendedAddressDlTdoaRangingMeasurement { mac_address, measurement });
+ count = count + 1;
+ }
+ None => return None,
+ }
+ }
+ Some(measurements)
+ }
+}
+
+pub fn extract_vec(bytes: &[u8], ptr: &mut usize, consumed_size: usize) -> Option<Vec<u8>> {
+ if bytes.len() < *ptr + consumed_size {
+ return None;
+ }
+
+ let res = bytes[*ptr..*ptr + consumed_size].to_vec();
+ *ptr += consumed_size;
+ Some(res)
+}
+
+/// Generate the function that extracts the value from byte buffers.
+macro_rules! generate_extract_func {
+ ($func_name:ident, $type:ty) => {
+ /// Extract the value from |byte[ptr..ptr + consumed_size]| in little endian.
+ fn $func_name(bytes: &[u8], ptr: &mut usize, consumed_size: usize) -> Option<$type> {
+ const type_size: usize = std::mem::size_of::<$type>();
+ if consumed_size > type_size {
+ return None;
+ }
+
+ let extracted_bytes = extract_vec(bytes, ptr, consumed_size)?;
+ let mut le_bytes = [0; type_size];
+ le_bytes[0..consumed_size].copy_from_slice(&extracted_bytes);
+ Some(<$type>::from_le_bytes(le_bytes))
+ }
+ };
+}
+
+generate_extract_func!(extract_u8, u8);
+generate_extract_func!(extract_u16, u16);
+generate_extract_func!(extract_u32, u32);
+generate_extract_func!(extract_u64, u64);
+
+// The GroupIdOrDataPacketFormat enum has all the values defined in both the GroupId and
+// DataPacketFormat enums. It represents the same bits in UCI packet header - the GID field in
+// a UCI control packet, and the DataPacketFormat field in a UCI data packet. Hence the unwrap()
+// calls in the conversions below should always succeed (as long as care is taken in future, to
+// keep the two enums in sync, for any additional values defined in the UCI spec).
+impl From<GroupId> for GroupIdOrDataPacketFormat {
+ fn from(gid: GroupId) -> Self {
+ GroupIdOrDataPacketFormat::try_from(u8::from(gid)).unwrap()
+ }
+}
+
+impl From<GroupIdOrDataPacketFormat> for GroupId {
+ fn from(gid_or_dpf: GroupIdOrDataPacketFormat) -> Self {
+ GroupId::try_from(u8::from(gid_or_dpf)).unwrap()
+ }
+}
+
+impl From<DataPacketFormat> for GroupIdOrDataPacketFormat {
+ fn from(dpf: DataPacketFormat) -> Self {
+ GroupIdOrDataPacketFormat::try_from(u8::from(dpf)).unwrap()
+ }
+}
+
+// The GroupIdOrDataPacketFormat enum has more values defined (for the GroupId bits) than the
+// DataPacketFormat enum. Hence this is implemented as TryFrom() instead of From().
+impl TryFrom<GroupIdOrDataPacketFormat> for DataPacketFormat {
+ type Error = Error;
+
+ fn try_from(gid_or_dpf: GroupIdOrDataPacketFormat) -> Result<Self> {
+ DataPacketFormat::try_from(u8::from(gid_or_dpf)).or(Err(Error::InvalidPacketError))
+ }
+}
// Container for UCI packet header fields.
-struct UciPacketHeader {
+struct UciControlPacketHeader {
message_type: MessageType,
group_id: GroupId,
opcode: u8,
}
+impl UciControlPacketHeader {
+ fn new(message_type: MessageType, group_id: GroupId, opcode: u8) -> Result<Self> {
+ if !is_uci_control_packet(message_type) {
+ return Err(Error::InvalidPacketError);
+ }
+
+ Ok(UciControlPacketHeader {
+ message_type: message_type,
+ group_id: group_id,
+ opcode: opcode,
+ })
+ }
+}
+
+// Helper methods to extract the UCI Packet header fields.
+fn get_mt_from_uci_packet(packet: &[u8]) -> u8 {
+ (packet[UCI_HEADER_MT_BYTE_POSITION] >> UCI_HEADER_MT_BIT_SHIFT) & UCI_HEADER_MT_MASK
+}
+
+fn get_pbf_from_uci_packet(packet: &[u8]) -> u8 {
+ (packet[UCI_HEADER_PBF_BYTE_POSITION] >> UCI_HEADER_PBF_BIT_SHIFT) & UCI_HEADER_PBF_MASK
+}
+
+fn get_gid_from_uci_control_packet(packet: &[u8]) -> u8 {
+ packet[UCI_CONTROL_HEADER_GID_BYTE_POSITION] & UCI_CONTROL_HEADER_GID_MASK
+}
+
+fn get_oid_from_uci_control_packet(packet: &[u8]) -> u8 {
+ packet[UCI_CONTROL_HEADER_OID_BYTE_POSITION] & UCI_CONTROL_HEADER_OID_MASK
+}
+
+// This function parses the packet bytes to return the Control Packet Opcode (OID) field. The
+// caller should check that the packet bytes represent a UCI control packet. The code will not
+// panic because UciPacketHal::to_bytes() should always be larger then the place we access.
+fn get_opcode_from_uci_control_packet(packet: &UciPacketHal) -> u8 {
+ get_oid_from_uci_control_packet(&packet.clone().to_bytes())
+}
+
+fn is_uci_control_packet(message_type: MessageType) -> bool {
+ match message_type {
+ MessageType::Command
+ | MessageType::Response
+ | MessageType::Notification
+ | MessageType::ReservedForTesting1
+ | MessageType::ReservedForTesting2 => true,
+ _ => false,
+ }
+}
+
+pub fn build_uci_control_packet(
+ message_type: MessageType,
+ group_id: GroupId,
+ opcode: u8,
+ payload: Option<Bytes>,
+) -> Option<UciControlPacket> {
+ if !is_uci_control_packet(message_type) {
+ error!("Only control packets are allowed, MessageType: {message_type:?}");
+ return None;
+ }
+ Some(UciControlPacketBuilder { group_id, message_type, opcode, payload }.build())
+}
+
// Ensure that the new packet fragment belong to the same packet.
-fn is_same_packet(header: &UciPacketHeader, packet: &UciPacketHalPacket) -> bool {
- header.message_type == packet.get_message_type()
- && header.group_id == packet.get_group_id()
- && header.opcode == packet.get_opcode()
+fn is_same_control_packet(header: &UciControlPacketHeader, packet: &UciPacketHal) -> bool {
+ is_uci_control_packet(header.message_type)
+ && header.message_type == packet.get_message_type()
+ && header.group_id == packet.get_group_id_or_data_packet_format().into()
+ && header.opcode == get_opcode_from_uci_control_packet(packet)
+}
+
+impl UciControlPacket {
+ // For some usage, we need to get the raw payload.
+ pub fn to_raw_payload(self) -> Vec<u8> {
+ self.to_bytes().slice(UCI_PACKET_HEADER_LEN..).to_vec()
+ }
}
-// Helper to convert from vector of |UciPacketHalPacket| to |UciPacketPacket|
-impl TryFrom<Vec<UciPacketHalPacket>> for UciPacketPacket {
+// Helper to convert from vector of |UciPacketHal| to |UciControlPacket|. An example
+// usage is to convert a list UciPacketHAL fragments to one UciPacket, during de-fragmentation.
+impl TryFrom<Vec<UciPacketHal>> for UciControlPacket {
type Error = Error;
- fn try_from(packets: Vec<UciPacketHalPacket>) -> Result<Self> {
+ fn try_from(packets: Vec<UciPacketHal>) -> Result<Self> {
if packets.is_empty() {
return Err(Error::InvalidPacketError);
}
+
// Store header info from the first packet.
- let header = UciPacketHeader {
- message_type: packets[0].get_message_type(),
- group_id: packets[0].get_group_id(),
- opcode: packets[0].get_opcode(),
- };
+ let header = UciControlPacketHeader::new(
+ packets[0].get_message_type(),
+ packets[0].get_group_id_or_data_packet_format().into(),
+ get_opcode_from_uci_control_packet(&packets[0]),
+ )?;
- let mut payload_buf = BytesMut::new();
// Create the reassembled payload.
+ let mut payload_buf = BytesMut::new();
for packet in packets {
// Ensure that the new fragment is part of the same packet.
- if !is_same_packet(&header, &packet) {
+ if !is_same_control_packet(&header, &packet) {
error!("Received unexpected fragment: {:?}", packet);
return Err(Error::InvalidPacketError);
}
// get payload by stripping the header.
payload_buf.extend_from_slice(&packet.to_bytes().slice(UCI_PACKET_HAL_HEADER_LEN..))
}
- // Create assembled |UciPacketPacket| and convert to bytes again since we need to
+
+ // Create assembled |UciControlPacket| and convert to bytes again since we need to
// reparse the packet after defragmentation to get the appropriate message.
- UciPacketPacket::parse(
- &UciPacketBuilder {
+ UciControlPacket::parse(
+ &UciControlPacketBuilder {
message_type: header.message_type,
group_id: header.group_id,
opcode: header.opcode,
@@ -89,23 +413,102 @@ impl TryFrom<Vec<UciPacketHalPacket>> for UciPacketPacket {
}
}
-// Helper to convert from |UciPacketPacket| to vector of |UciPacketHalPacket|s
-impl From<UciPacketPacket> for Vec<UciPacketHalPacket> {
- fn from(packet: UciPacketPacket) -> Self {
+#[derive(Debug, Clone)]
+pub struct RawUciControlPacket {
+ pub mt: u8,
+ pub gid: u8,
+ pub oid: u8,
+ pub payload: Vec<u8>,
+}
+
+impl RawUciControlPacket {
+ // Match the GID and OID to confirm the UCI packet (represented by header) is
+ // the same as the stored signature. We don't match the MT because they can be
+ // different (eg: CMD/RSP pair).
+ pub fn is_same_signature_bytes(&self, header: &[u8]) -> bool {
+ let gid = get_gid_from_uci_control_packet(header);
+ let oid = get_oid_from_uci_control_packet(header);
+ gid == self.gid && oid == self.oid
+ }
+}
+
+// UCI Data packet functions.
+fn is_uci_data_rcv_packet(message_type: MessageType, data_packet_format: DataPacketFormat) -> bool {
+ message_type == MessageType::Data && data_packet_format == DataPacketFormat::DataRcv
+}
+
+fn try_into_data_payload(packet: UciPacketHal) -> Result<Bytes> {
+ if is_uci_data_rcv_packet(
+ packet.get_message_type(),
+ packet.get_group_id_or_data_packet_format().try_into()?,
+ ) {
+ Ok(packet.to_bytes().slice(UCI_PACKET_HAL_HEADER_LEN..))
+ } else {
+ error!("Received unexpected data packet fragment: {:?}", packet);
+ Err(Error::InvalidPacketError)
+ }
+}
+
+// Helper to convert from vector of |UciPacketHal| to |UciDataPacket|. An example
+// usage is to convert a list UciPacketHAL fragments to one UciPacket, during de-fragmentation.
+impl TryFrom<Vec<UciPacketHal>> for UciDataPacket {
+ type Error = Error;
+
+ fn try_from(packets: Vec<UciPacketHal>) -> Result<Self> {
+ if packets.is_empty() {
+ return Err(Error::InvalidPacketError);
+ }
+
+ // Create the reassembled payload.
+ let mut payload_buf = Bytes::new();
+ for packet in packets {
+ // Ensure that the fragment is a Data Rcv packet.
+ // Get payload by stripping the header.
+ payload_buf = [payload_buf, try_into_data_payload(packet)?].concat().into();
+ }
+
+ // Create assembled |UciDataPacket| and convert to bytes again since we need to
+ // reparse the packet after defragmentation to get the appropriate message.
+ UciDataPacket::parse(
+ &UciDataPacketBuilder {
+ message_type: MessageType::Data,
+ data_packet_format: DataPacketFormat::DataRcv,
+ payload: Some(payload_buf.into()),
+ }
+ .build()
+ .to_bytes(),
+ )
+ }
+}
+
+// Helper to convert from |UciControlPacket| to vector of |UciControlPacketHal|s. An
+// example usage is to do this conversion for fragmentation (from Host to UWBS).
+impl From<UciControlPacket> for Vec<UciControlPacketHal> {
+ fn from(packet: UciControlPacket) -> Self {
// Store header info.
- let header = UciPacketHeader {
- message_type: packet.get_message_type(),
- group_id: packet.get_group_id(),
- opcode: packet.get_opcode(),
+ let header = match UciControlPacketHeader::new(
+ packet.get_message_type(),
+ packet.get_group_id(),
+ packet.get_opcode(),
+ ) {
+ Ok(hdr) => hdr,
+ _ => {
+ error!(
+ "Unable to parse UciControlPacketHeader from UciControlPacket: {:?}",
+ packet
+ );
+ return Vec::new();
+ }
};
- let mut fragments: Vec<UciPacketHalPacket> = Vec::new();
+
+ let mut fragments = Vec::new();
// get payload by stripping the header.
let payload = packet.to_bytes().slice(UCI_PACKET_HEADER_LEN..);
if payload.is_empty() {
fragments.push(
- UciPacketHalBuilder {
+ UciControlPacketHalBuilder {
message_type: header.message_type,
- group_id: header.group_id,
+ group_id_or_data_packet_format: header.group_id.into(),
opcode: header.opcode,
packet_boundary_flag: PacketBoundaryFlag::Complete,
payload: None,
@@ -122,9 +525,9 @@ impl From<UciPacketPacket> for Vec<UciPacketHalPacket> {
PacketBoundaryFlag::Complete
};
fragments.push(
- UciPacketHalBuilder {
+ UciControlPacketHalBuilder {
message_type: header.message_type,
- group_id: header.group_id,
+ group_id_or_data_packet_format: header.group_id.into(),
opcode: header.opcode,
packet_boundary_flag: pbf,
payload: Some(Bytes::from(fragment.to_owned())),
@@ -137,37 +540,175 @@ impl From<UciPacketPacket> for Vec<UciPacketHalPacket> {
}
}
+// Helper to convert From<UciDataSnd> into Vec<UciDataPacketHal>. An
+// example usage is for fragmentation in the Data Packet Tx flow.
+impl From<UciDataSnd> for Vec<UciDataPacketHal> {
+ fn from(packet: UciDataSnd) -> Self {
+ let mut fragments = Vec::new();
+ let dpf = packet.get_data_packet_format().into();
+
+ // get payload by stripping the header.
+ let payload = packet.to_bytes().slice(UCI_DATA_SND_PACKET_HEADER_LEN..);
+ if payload.is_empty() {
+ fragments.push(
+ UciDataPacketHalBuilder {
+ group_id_or_data_packet_format: dpf,
+ packet_boundary_flag: PacketBoundaryFlag::Complete,
+ payload: None,
+ }
+ .build(),
+ );
+ } else {
+ let mut fragments_iter = payload.chunks(MAX_PAYLOAD_LEN).peekable();
+ while let Some(fragment) = fragments_iter.next() {
+ // Set the last fragment complete if this is last fragment.
+ let pbf = if let Some(nxt_fragment) = fragments_iter.peek() {
+ PacketBoundaryFlag::NotComplete
+ } else {
+ PacketBoundaryFlag::Complete
+ };
+ fragments.push(
+ UciDataPacketHalBuilder {
+ group_id_or_data_packet_format: dpf,
+ packet_boundary_flag: pbf,
+ payload: Some(Bytes::from(fragment.to_owned())),
+ }
+ .build(),
+ );
+ }
+ }
+ fragments
+ }
+}
+
#[derive(Default, Debug)]
pub struct PacketDefrager {
// Cache to store incoming fragmented packets in the middle of reassembly.
// Will be empty if there is no reassembly in progress.
- fragment_cache: Vec<UciPacketHalPacket>,
+ // TODO(b/261762781): Prefer this to be UciControlPacketHal
+ control_fragment_cache: Vec<UciPacketHal>,
+ // TODO(b/261762781): Prefer this to be UciDataPacketHal
+ data_fragment_cache: Vec<UciPacketHal>,
+ // Raw packet payload bytes cache
+ raw_fragment_cache: Vec<u8>,
+}
+
+pub enum UciDefragPacket {
+ Control(UciControlPacket),
+ Data(UciDataPacket),
+ Raw(Result<()>, RawUciControlPacket),
}
impl PacketDefrager {
- pub fn defragment_packet(&mut self, msg: &[u8]) -> Option<UciPacketPacket> {
- match UciPacketHalPacket::parse(msg) {
- Ok(packet) => {
- let pbf = packet.get_packet_boundary_flag();
- // Add the incoming fragment to the packet cache.
- self.fragment_cache.push(packet);
- if pbf == PacketBoundaryFlag::NotComplete {
- // Wait for remaining fragments.
- return None;
- }
- // All fragments received, defragment the packet.
- match self.fragment_cache.drain(..).collect::<Vec<_>>().try_into() {
- Ok(packet) => Some(packet),
- Err(e) => {
- error!("Failed to defragment packet: {:?}", e);
- None
+ pub fn defragment_packet(
+ &mut self,
+ msg: &[u8],
+ last_raw_cmd: Option<RawUciControlPacket>,
+ ) -> Option<UciDefragPacket> {
+ if let Some(raw_cmd) = last_raw_cmd {
+ let mt_u8 = get_mt_from_uci_packet(msg);
+ match MessageType::try_from(u8::from(mt_u8)) {
+ Ok(mt) => match mt {
+ // Parse only a UCI response packet as a Raw packet.
+ MessageType::Response => {
+ return self.defragment_raw_uci_response_packet(msg, raw_cmd);
}
+ _ => { /* Fallthrough to de-frag as a normal UCI packet below */ }
+ },
+ Err(_) => {
+ error!("Rx packet from HAL has unrecognized MT={}", mt_u8);
+ return Some(UciDefragPacket::Raw(
+ Err(Error::InvalidPacketError),
+ RawUciControlPacket { mt: mt_u8, gid: 0, oid: 0, payload: Vec::new() },
+ ));
}
- }
- Err(e) => {
+ };
+ }
+
+ let packet = UciPacketHal::parse(msg)
+ .or_else(|e| {
error!("Failed to parse packet: {:?}", e);
- None
+ Err(e)
+ })
+ .ok()?;
+
+ let pbf = packet.get_packet_boundary_flag();
+
+ // TODO(b/261762781): The current implementation allows for the possibility that we receive
+ // interleaved Control/Data HAL packets, and so uses separate caches for them. In the
+ // future, if we determine that interleaving is not possible, this can be simplified.
+ if is_uci_control_packet(packet.get_message_type()) {
+ // Add the incoming fragment to the control packet cache.
+ self.control_fragment_cache.push(packet);
+ if pbf == PacketBoundaryFlag::NotComplete {
+ // Wait for remaining fragments.
+ return None;
+ }
+
+ // All fragments received, defragment the control packet.
+ match self.control_fragment_cache.drain(..).collect::<Vec<_>>().try_into() {
+ Ok(packet) => Some(UciDefragPacket::Control(packet)),
+ Err(e) => {
+ error!("Failed to defragment control packet: {:?}", e);
+ None
+ }
}
+ } else {
+ // Add the incoming fragment to the data packet cache.
+ self.data_fragment_cache.push(packet);
+ if pbf == PacketBoundaryFlag::NotComplete {
+ // Wait for remaining fragments.
+ return None;
+ }
+
+ // All fragments received, defragment the data packet.
+ match self.data_fragment_cache.drain(..).collect::<Vec<_>>().try_into() {
+ Ok(packet) => Some(UciDefragPacket::Data(packet)),
+ Err(e) => {
+ error!("Failed to defragment data packet: {:?}", e);
+ None
+ }
+ }
+ }
+ }
+
+ fn defragment_raw_uci_response_packet(
+ &mut self,
+ msg: &[u8],
+ raw_cmd: RawUciControlPacket,
+ ) -> Option<UciDefragPacket> {
+ let mt_u8 = get_mt_from_uci_packet(msg);
+ let pbf = get_pbf_from_uci_packet(msg);
+ let gid = get_gid_from_uci_control_packet(msg);
+ let oid = get_oid_from_uci_control_packet(msg);
+ if raw_cmd.is_same_signature_bytes(msg) {
+ // Store only the packet payload bytes (UCI header should not be stored).
+ self.raw_fragment_cache.extend_from_slice(&msg[UCI_PACKET_HAL_HEADER_LEN..]);
+
+ if pbf == u8::from(PacketBoundaryFlag::NotComplete) {
+ return None;
+ }
+
+ // All fragments received, defragment and return the Raw packet's payload bytes.
+ return Some(UciDefragPacket::Raw(
+ Ok(()),
+ RawUciControlPacket {
+ mt: mt_u8,
+ gid,
+ oid,
+ payload: self.raw_fragment_cache.drain(..).collect(),
+ },
+ ));
+ } else {
+ error!(
+ "Rx packet from HAL (MT={}, PBF={}, GID={}, OID={}) has non-matching\
+ RawCmd signature",
+ mt_u8, pbf, gid, oid
+ );
+ return Some(UciDefragPacket::Raw(
+ Err(Error::InvalidPacketError),
+ RawUciControlPacket { mt: mt_u8, gid, oid, payload: Vec::new() },
+ ));
}
}
}
@@ -191,9 +732,7 @@ pub struct ParsedFrameReport {
cir: Vec<CirValue>,
}
-pub fn parse_diagnostics_ntf(
- evt: AndroidRangeDiagnosticsNtfPacket,
-) -> Result<ParsedDiagnosticNtfPacket> {
+pub fn parse_diagnostics_ntf(evt: AndroidRangeDiagnosticsNtf) -> Result<ParsedDiagnosticNtfPacket> {
let session_id = evt.get_session_id();
let sequence_number = evt.get_sequence_number();
let mut parsed_frame_reports = Vec::new();
@@ -202,7 +741,7 @@ pub fn parse_diagnostics_ntf(
let mut aoa_vec = Vec::new();
let mut cir_vec = Vec::new();
for tlv in &report.frame_report_tlvs {
- match FrameReportTlvPacketPacket::parse(
+ match FrameReportTlvPacket::parse(
&[vec![tlv.t as u8, tlv.v.len() as u8, (tlv.v.len() >> 8) as u8], tlv.v.clone()]
.concat(),
) {
@@ -241,8 +780,8 @@ pub fn parse_diagnostics_ntf(
}
#[derive(Debug, Clone, PartialEq)]
-pub enum ControleesV2 {
- NoSessionKey(Vec<Controlee_V2_0_0_Byte_Version>),
+pub enum Controlees {
+ NoSessionKey(Vec<Controlee>),
ShortSessionKey(Vec<Controlee_V2_0_16_Byte_Version>),
LongSessionKey(Vec<Controlee_V2_0_32_Byte_Version>),
}
@@ -257,25 +796,12 @@ pub fn write_controlee(controlee: &Controlee) -> BytesMut {
buffer
}
-pub fn write_controlee_2_0_0byte(controlee: &Controlee_V2_0_0_Byte_Version) -> BytesMut {
- let mut buffer = BytesMut::new();
- let short_address = controlee.short_address;
- buffer.extend_from_slice(&short_address.to_le_bytes()[0..2]);
- let subsession_id = controlee.subsession_id;
- buffer.extend_from_slice(&subsession_id.to_le_bytes()[0..4]);
- let message_control = controlee.message_control.to_u8().unwrap();
- buffer.extend_from_slice(&message_control.to_le_bytes()[0..1]);
- buffer
-}
-
pub fn write_controlee_2_0_16byte(controlee: &Controlee_V2_0_16_Byte_Version) -> BytesMut {
let mut buffer = BytesMut::new();
let short_address = controlee.short_address;
buffer.extend_from_slice(&short_address.to_le_bytes()[0..2]);
let subsession_id = controlee.subsession_id;
buffer.extend_from_slice(&subsession_id.to_le_bytes()[0..4]);
- let message_control = controlee.message_control.to_u8().unwrap();
- buffer.extend_from_slice(&message_control.to_le_bytes()[0..1]);
buffer.extend_from_slice(&controlee.subsession_key);
buffer
}
@@ -286,70 +812,54 @@ pub fn write_controlee_2_0_32byte(controlee: &Controlee_V2_0_32_Byte_Version) ->
buffer.extend_from_slice(&short_address.to_le_bytes()[0..2]);
let subsession_id = controlee.subsession_id;
buffer.extend_from_slice(&subsession_id.to_le_bytes()[0..4]);
- let message_control = controlee.message_control.to_u8().unwrap();
- buffer.extend_from_slice(&message_control.to_le_bytes()[0..1]);
buffer.extend_from_slice(&controlee.subsession_key);
buffer
}
-/// Generate the V1 SessionUpdateControllerMulticastListCmd packet.
+/// Generate the SessionUpdateControllerMulticastListCmd packet.
///
-/// Workaround for handling the non-compatible command.
-/// Size check omitted and UCI spec compliancy is up to the caller of the method.
-pub fn build_session_update_controller_multicast_list_cmd_v1(
+/// This function can build the packet with/without message control, which
+/// is indicated by action parameter.
+pub fn build_session_update_controller_multicast_list_cmd(
session_id: u32,
action: UpdateMulticastListAction,
- controlees: Vec<Controlee>,
-) -> SessionUpdateControllerMulticastListCmdPacket {
- let mut controlees_buf = BytesMut::new();
- controlees_buf.extend_from_slice(&(controlees.len() as u8).to_le_bytes());
- for controlee in controlees {
- controlees_buf.extend_from_slice(&write_controlee(&controlee));
- }
- SessionUpdateControllerMulticastListCmdBuilder {
- session_id,
- action,
- payload: Some(controlees_buf.freeze()),
- }
- .build()
-}
-
-/// Generate the V2 SessionUpdateControllerMulticastListCmd packet.
-///
-/// Workaround for handling the non-compatible command.
-/// Size check omitted and UCI spec compliancy is up to the caller of the method.
-pub fn build_session_update_controller_multicast_list_cmd_v2(
- session_id: u32,
- action: UpdateMulticastListAction,
- controlees: ControleesV2,
-) -> SessionUpdateControllerMulticastListCmdPacket {
+ controlees: Controlees,
+) -> Result<SessionUpdateControllerMulticastListCmd> {
let mut controlees_buf = BytesMut::new();
match controlees {
- ControleesV2::NoSessionKey(controlee_v2) => {
- controlees_buf.extend_from_slice(&(controlee_v2.len() as u8).to_le_bytes());
- for controlee in controlee_v2 {
- controlees_buf.extend_from_slice(&write_controlee_2_0_0byte(&controlee));
+ Controlees::NoSessionKey(controlee_v1)
+ if action == UpdateMulticastListAction::AddControlee
+ || action == UpdateMulticastListAction::RemoveControlee =>
+ {
+ controlees_buf.extend_from_slice(&(controlee_v1.len() as u8).to_le_bytes());
+ for controlee in controlee_v1 {
+ controlees_buf.extend_from_slice(&write_controlee(&controlee));
}
}
- ControleesV2::ShortSessionKey(controlee_v2) => {
+ Controlees::ShortSessionKey(controlee_v2)
+ if action == UpdateMulticastListAction::AddControleeWithShortSubSessionKey =>
+ {
controlees_buf.extend_from_slice(&(controlee_v2.len() as u8).to_le_bytes());
for controlee in controlee_v2 {
controlees_buf.extend_from_slice(&write_controlee_2_0_16byte(&controlee));
}
}
- ControleesV2::LongSessionKey(controlee_v2) => {
+ Controlees::LongSessionKey(controlee_v2)
+ if action == UpdateMulticastListAction::AddControleeWithLongSubSessionKey =>
+ {
controlees_buf.extend_from_slice(&(controlee_v2.len() as u8).to_le_bytes());
for controlee in controlee_v2 {
controlees_buf.extend_from_slice(&write_controlee_2_0_32byte(&controlee));
}
}
+ _ => return Err(Error::InvalidPacketError),
}
- SessionUpdateControllerMulticastListCmdBuilder {
+ Ok(SessionUpdateControllerMulticastListCmdBuilder {
session_id,
action,
payload: Some(controlees_buf.freeze()),
}
- .build()
+ .build())
}
impl Drop for AppConfigTlv {
@@ -413,15 +923,16 @@ mod tests {
}
#[test]
- fn test_build_multicast_update_v1_packet() {
+ fn test_build_multicast_update_packet() {
let controlee = Controlee { short_address: 0x1234, subsession_id: 0x1324_3546 };
- let packet: UciPacketPacket = build_session_update_controller_multicast_list_cmd_v1(
+ let packet: UciControlPacket = build_session_update_controller_multicast_list_cmd(
0x1425_3647,
UpdateMulticastListAction::AddControlee,
- vec![controlee; 1],
+ Controlees::NoSessionKey(vec![controlee; 1]),
)
+ .unwrap()
.into();
- let packet_fragments: Vec<UciPacketHalPacket> = packet.into();
+ let packet_fragments: Vec<UciControlPacketHal> = packet.into();
let uci_packet: Vec<u8> = packet_fragments[0].clone().into();
assert_eq!(
uci_packet,
@@ -433,4 +944,212 @@ mod tests {
]
);
}
+
+ #[test]
+ fn test_to_raw_payload() {
+ let payload = vec![0x11, 0x22, 0x33];
+ let payload_clone = payload.clone();
+ let packet = UciControlPacketBuilder {
+ group_id: GroupId::Test,
+ message_type: MessageType::Response,
+ opcode: 0x5,
+ payload: Some(payload_clone.into()),
+ }
+ .build();
+
+ assert_eq!(payload, packet.to_raw_payload());
+ }
+
+ #[test]
+ fn test_to_raw_payload_empty() {
+ let payload: Vec<u8> = vec![];
+ let packet = UciControlPacketBuilder {
+ group_id: GroupId::Test,
+ message_type: MessageType::Response,
+ opcode: 0x5,
+ payload: None,
+ }
+ .build();
+
+ assert_eq!(payload, packet.to_raw_payload());
+ }
+
+ #[cfg(test)]
+ mod tests {
+ use crate::{extract_u16, extract_u32, extract_u64, extract_u8, extract_vec};
+ #[test]
+ fn test_extract_func() {
+ let bytes = [0x1, 0x3, 0x5, 0x7, 0x9, 0x2, 0x4, 0x05, 0x07, 0x09, 0x0a];
+ let mut ptr = 0;
+
+ let u8_val = extract_u8(&bytes, &mut ptr, 1);
+ assert_eq!(u8_val, Some(0x1));
+ assert_eq!(ptr, 1);
+
+ let u16_val = extract_u16(&bytes, &mut ptr, 2);
+ assert_eq!(u16_val, Some(0x0503));
+ assert_eq!(ptr, 3);
+
+ let u32_val = extract_u32(&bytes, &mut ptr, 3);
+ assert_eq!(u32_val, Some(0x020907));
+ assert_eq!(ptr, 6);
+
+ let u64_val = extract_u64(&bytes, &mut ptr, 5);
+ assert_eq!(u64_val, Some(0x0a09070504));
+ assert_eq!(ptr, 11);
+
+ let vec = extract_vec(&bytes, &mut ptr, 3);
+ assert_eq!(vec, None);
+ assert_eq!(ptr, 11);
+ }
+ }
+
+ #[test]
+ fn test_short_dltdoa_ranging_measurement() {
+ let bytes = [
+ // All Fields in Little Endian (LE)
+ // First measurement
+ 0x0a, 0x01, 0x33, 0x05, // 2(Mac address), Status, Message Type
+ 0x33, 0x05, 0x02, 0x05, // 2(Message control), 2(Block Index)
+ 0x07, 0x09, 0x0a, 0x01, // Round Index, NLoS, 2(AoA Azimuth)
+ 0x02, 0x05, 0x07, 0x09, // AoA Azimuth FOM, 2(AoA Elevation), AoA Elevation FOM
+ 0x0a, 0x01, 0x02, 0x05, // RSSI, 3(Tx Timestamp..)
+ 0x07, 0x09, 0x0a, 0x01, // 4(Tx Timestamp..)
+ 0x02, 0x05, 0x07, 0x09, // Tx Timestamp, 3(Rx Timestamp..)
+ 0x05, 0x07, 0x09, 0x0a, // 2(Rx Timestamp), 2(Anchor Cfo)
+ 0x01, 0x02, 0x05, 0x07, // 2(Cfo), 2(Initiator Reply Time..)
+ 0x09, 0x05, 0x07, 0x09, // 2(Initiator Reply Time), 2(Responder Reply Time..)
+ 0x0a, 0x01, 0x02, 0x05, // 2(Responder Reply Time), 2(Initiator-Responder ToF)
+ 0x07, 0x09, 0x07, 0x09, // 4(Anchor Location..)
+ 0x05, 0x07, 0x09, 0x0a, // 4(Anchor Location..)
+ 0x01, 0x02, 0x05, 0x07, // 2(Anchor Location..), 2(Active Ranging Rounds..)
+ 0x09, 0x0a, 0x01, 0x02, // 4(Active Ranging Rounds..)
+ 0x05, 0x07, 0x09, 0x05, // 4(Active Ranging Rounds)
+ // Second measurement
+ 0x0a, 0x01, 0x33, 0x05, // 2(Mac address), Status, Message Type
+ 0x33, 0x05, 0x02, 0x05, // 2(Message control), 2(Block Index)
+ 0x07, 0x09, 0x0a, 0x01, // Round Index, NLoS, 2(AoA Azimuth)
+ 0x02, 0x05, 0x07, 0x09, // AoA Azimuth FOM, 2(AoA Elevation), AoA Elevation FOM
+ 0x0a, 0x01, 0x02, 0x05, // RSSI, 3(Tx Timestamp..)
+ 0x07, 0x09, 0x0a, 0x01, // 4(Tx Timestamp..)
+ 0x02, 0x05, 0x07, 0x09, // Tx Timestamp, 3(Rx Timestamp..)
+ 0x05, 0x07, 0x09, 0x0a, // 2(Rx Timestamp), 2(Anchor Cfo)
+ 0x01, 0x02, 0x05, 0x07, // 2(Cfo), 2(Initiator Reply Time..)
+ 0x09, 0x05, 0x07, 0x09, // 2(Initiator Reply Time), 2(Responder Reply Time..)
+ 0x0a, 0x01, 0x02, 0x05, // 2(Responder Reply Time), 2(Initiator-Responder ToF)
+ 0x07, 0x09, 0x07, 0x09, // 4(Anchor Location..)
+ 0x05, 0x07, 0x09, 0x0a, // 4(Anchor Location..)
+ 0x01, 0x02, 0x05, 0x07, // 2(Anchor Location..), 2(Active Ranging Rounds..)
+ 0x09, 0x0a, 0x01, 0x02, // 4(Active Ranging Rounds..)
+ 0x05, 0x07, 0x09, 0x05, // 4(Active Ranging Rounds)
+ ];
+
+ let measurements = ShortAddressDlTdoaRangingMeasurement::parse(&bytes, 2).unwrap();
+ assert_eq!(measurements.len(), 2);
+ let measurement_1 = &measurements[0].measurement;
+ let mac_address_1 = &measurements[0].mac_address;
+ assert_eq!(*mac_address_1, 0x010a);
+ assert_eq!(measurement_1.status, 0x33);
+ assert_eq!(measurement_1.message_type, 0x05);
+ assert_eq!(measurement_1.message_control, 0x0533);
+ assert_eq!(measurement_1.block_index, 0x0502);
+ assert_eq!(measurement_1.round_index, 0x07);
+ assert_eq!(measurement_1.nlos, 0x09);
+ assert_eq!(measurement_1.aoa_azimuth, 0x010a);
+ assert_eq!(measurement_1.aoa_azimuth_fom, 0x02);
+ assert_eq!(measurement_1.aoa_elevation, 0x0705);
+ assert_eq!(measurement_1.aoa_elevation_fom, 0x09);
+ assert_eq!(measurement_1.rssi, 0x0a);
+ assert_eq!(measurement_1.tx_timestamp, 0x02010a0907050201);
+ assert_eq!(measurement_1.rx_timestamp, 0x0705090705);
+ assert_eq!(measurement_1.anchor_cfo, 0x0a09);
+ assert_eq!(measurement_1.cfo, 0x0201);
+ assert_eq!(measurement_1.initiator_reply_time, 0x05090705);
+ assert_eq!(measurement_1.responder_reply_time, 0x010a0907);
+ assert_eq!(measurement_1.initiator_responder_tof, 0x0502);
+ assert_eq!(
+ measurement_1.dt_anchor_location,
+ vec![0x07, 0x09, 0x07, 0x09, 0x05, 0x07, 0x09, 0x0a, 0x01, 0x02]
+ );
+ assert_eq!(
+ measurement_1.ranging_rounds,
+ vec![0x05, 0x07, 0x09, 0x0a, 0x01, 0x02, 0x05, 0x07, 0x09, 0x05,]
+ );
+
+ let measurement_2 = &measurements[1].measurement;
+ let mac_address_2 = &measurements[1].mac_address;
+ assert_eq!(*mac_address_2, 0x010a);
+ assert_eq!(measurement_2.status, 0x33);
+ assert_eq!(measurement_2.message_type, 0x05);
+ assert_eq!(measurement_2.message_control, 0x0533);
+ assert_eq!(measurement_2.block_index, 0x0502);
+ assert_eq!(measurement_2.round_index, 0x07);
+ assert_eq!(measurement_2.nlos, 0x09);
+ assert_eq!(measurement_2.aoa_azimuth, 0x010a);
+ assert_eq!(measurement_2.aoa_azimuth_fom, 0x02);
+ assert_eq!(measurement_2.aoa_elevation, 0x0705);
+ assert_eq!(measurement_2.aoa_elevation_fom, 0x09);
+ assert_eq!(measurement_2.rssi, 0x0a);
+ assert_eq!(measurement_2.tx_timestamp, 0x02010a0907050201);
+ assert_eq!(measurement_2.rx_timestamp, 0x0705090705);
+ assert_eq!(measurement_2.anchor_cfo, 0x0a09);
+ assert_eq!(measurement_2.cfo, 0x0201);
+ assert_eq!(measurement_2.initiator_reply_time, 0x05090705);
+ assert_eq!(measurement_2.responder_reply_time, 0x010a0907);
+ assert_eq!(measurement_2.initiator_responder_tof, 0x0502);
+ assert_eq!(
+ measurement_1.dt_anchor_location,
+ vec![0x07, 0x09, 0x07, 0x09, 0x05, 0x07, 0x09, 0x0a, 0x01, 0x02]
+ );
+ assert_eq!(
+ measurement_1.ranging_rounds,
+ vec![0x05, 0x07, 0x09, 0x0a, 0x01, 0x02, 0x05, 0x07, 0x09, 0x05,]
+ );
+ }
+
+ #[test]
+ fn test_extended_dltdoa_ranging_measurement() {
+ let bytes = [
+ // All Fields in Little Endian (LE)
+ /* First measurement */
+ 0x0a, 0x01, 0x33, 0x05, // 4(Mac address..)
+ 0x33, 0x05, 0x02, 0x05, // 4(Mac address)
+ 0x07, 0x09, 0x0a, 0x01, // Status, Message Type, 2(Message control),
+ 0x02, 0x05, 0x07, 0x09, // 2(Block Index), Round Index, NLoS,
+ 0x0a, 0x01, 0x02, 0x05, // 2(AoA Azimuth), AoA Azimuth FOM, 1(AoA Elevation..)
+ 0x07, 0x09, 0x0a, // 1(AoA Elevation), AoA Elevation FOM, RSSI,
+ 0x01, 0x02, 0x05, 0x07, // 4(Tx Timestamp..)
+ 0x09, 0x05, 0x07, 0x09, // 4(Tx Timestamp),
+ 0x0a, 0x01, 0x02, 0x05, // 4(Rx Timestamp..)
+ 0x07, 0x09, 0x05, 0x07, // 4(Rx Timestamp)
+ 0x09, 0x0a, 0x01, 0x02, // 2(Anchor Cfo), 2(Cfo),
+ 0x05, 0x07, 0x09, 0x05, // 4(Initiator Reply Time)
+ 0x07, 0x09, 0x0a, 0x01, // 4(Responder Reply Time),
+ 0x02, 0x05, 0x02, 0x05, // 2(Initiator-Responder ToF), 2(Active Ranging Rounds)
+ ];
+
+ let measurements = ExtendedAddressDlTdoaRangingMeasurement::parse(&bytes, 1).unwrap();
+ assert_eq!(measurements.len(), 1);
+ let measurement = &measurements[0].measurement;
+ let mac_address = &measurements[0].mac_address;
+ assert_eq!(*mac_address, 0x050205330533010a);
+ assert_eq!(measurement.message_control, 0x010a);
+ assert_eq!(measurement.block_index, 0x0502);
+ assert_eq!(measurement.round_index, 0x07);
+ assert_eq!(measurement.nlos, 0x09);
+ assert_eq!(measurement.aoa_azimuth, 0x010a);
+ assert_eq!(measurement.aoa_azimuth_fom, 0x02);
+ assert_eq!(measurement.aoa_elevation, 0x0705);
+ assert_eq!(measurement.aoa_elevation_fom, 0x09);
+ assert_eq!(measurement.rssi, 0x0a);
+ assert_eq!(measurement.tx_timestamp, 0x0907050907050201);
+ assert_eq!(measurement.rx_timestamp, 0x070509070502010a);
+ assert_eq!(measurement.anchor_cfo, 0x0a09);
+ assert_eq!(measurement.cfo, 0x0201);
+ assert_eq!(measurement.initiator_reply_time, 0x05090705);
+ assert_eq!(measurement.responder_reply_time, 0x010a0907);
+ assert_eq!(measurement.initiator_responder_tof, 0x0502);
+ assert_eq!(measurement.dt_anchor_location, vec![]);
+ assert_eq!(measurement.ranging_rounds, vec![0x02, 0x05]);
+ }
}
diff --git a/src/rust/uwb_uci_packets/uci_packets.pdl b/src/rust/uwb_uci_packets/uci_packets.pdl
index 5ca02d2..848195a 100644
--- a/src/rust/uwb_uci_packets/uci_packets.pdl
+++ b/src/rust/uwb_uci_packets/uci_packets.pdl
@@ -8,7 +8,28 @@ enum PacketBoundaryFlag : 1 {
enum GroupId : 4 {
CORE = 0x00,
SESSION_CONFIG = 0x01,
- RANGING_SESSION_CONTROL = 0x02,
+ SESSION_CONTROL = 0x02,
+ DATA_CONTROL = 0x03,
+ TEST = 0x0d,
+ VENDOR_RESERVED_9 = 0x09,
+ VENDOR_RESERVED_A = 0x0a,
+ VENDOR_RESERVED_B = 0x0b,
+ VENDOR_ANDROID = 0x0c,
+ VENDOR_RESERVED_E = 0x0e,
+ VENDOR_RESERVED_F = 0x0f,
+}
+
+enum DataPacketFormat: 4 {
+ DATA_SND = 0x01,
+ DATA_RCV = 0x02,
+}
+
+// Define a merged enum across GroupId & DataPacketFormat as they are at the same bits in
+// |UciPacketHal|.
+enum GroupIdOrDataPacketFormat : 4 {
+ CORE = 0x00,
+ SESSION_CONFIG_OR_DATA_SND = 0x01,
+ SESSION_CONTROL_OR_DATA_RCV = 0x02,
DATA_CONTROL = 0x03,
TEST = 0x0d,
VENDOR_RESERVED_9 = 0x09,
@@ -30,7 +51,7 @@ enum CoreOpCode : 6 {
CORE_GENERIC_ERROR_NTF = 0x07,
}
-enum SessionOpCode : 6 {
+enum SessionConfigOpCode : 6 {
SESSION_INIT = 0x00,
SESSION_DEINIT = 0x01,
SESSION_STATUS_NTF = 0x02,
@@ -39,13 +60,20 @@ enum SessionOpCode : 6 {
SESSION_GET_COUNT = 0x05,
SESSION_GET_STATE = 0x06,
SESSION_UPDATE_CONTROLLER_MULTICAST_LIST = 0x07,
+ SESSION_UPDATE_ACTIVE_ROUNDS_ANCHOR = 0x08,
+ SESSION_UPDATE_ACTIVE_ROUNDS_DT_TAG = 0x09,
+ SESSION_SET_INITIATOR_DT_ANCHOR_RR_RDM_LIST = 0x0a,
+ SESSION_QUERY_DATA_SIZE_IN_RANGING = 0x0b,
+ SESSION_SET_HUS_CONFIG = 0x0c,
}
-enum RangeOpCode : 6 {
- RANGE_START = 0x00,
- RANGE_STOP = 0x01,
- RANGE_INTERVAL_UPDATE_REQ = 0x02,
- RANGE_GET_RANGING_COUNT = 0x03,
+enum SessionControlOpCode : 6 {
+ SESSION_START = 0x00,
+ SESSION_STOP = 0x01,
+ SESSION_RESERVED = 0x02,
+ SESSION_GET_RANGING_COUNT = 0x03,
+ SESSION_DATA_CREDIT_NTF = 0x04,
+ SESSION_DATA_TRANSFER_STATUS_NTF = 0x05,
}
enum AppDataOpCode : 6 {
@@ -73,6 +101,8 @@ enum StatusCode : 8 {
UCI_STATUS_UNKNOWN_OID = 0x08,
UCI_STATUS_READ_ONLY = 0x09,
UCI_STATUS_COMMAND_RETRY = 0x0A,
+ UCI_STATUS_NOT_APPLICABLE = 0x0B,
+ RFU_STATUS_CODE_RANGE_1 = 0x0C..0x10,
// UWB Session Specific Status Codes
UCI_STATUS_SESSION_NOT_EXIST = 0x11,
@@ -84,6 +114,9 @@ enum StatusCode : 8 {
UCI_STATUS_MULTICAST_LIST_FULL = 0x17,
UCI_STATUS_ADDRESS_NOT_FOUND = 0x18,
UCI_STATUS_ADDRESS_ALREADY_PRESENT = 0x19,
+ UCI_STATUS_ERROR_UWB_INITIATION_TIME_TOO_OLD = 0x1A,
+ UCI_STATUS_OK_NEGATIVE_DISTANCE_REPORT = 0x1B,
+ RFU_STATUS_CODE_RANGE_2 = 0x1C..0x1F,
// UWB Ranging Session Specific Status Codes
UCI_STATUS_RANGING_TX_FAILED = 0x20,
@@ -94,14 +127,63 @@ enum StatusCode : 8 {
UCI_STATUS_RANGING_RX_MAC_DEC_FAILED = 0x25,
UCI_STATUS_RANGING_RX_MAC_IE_DEC_FAILED = 0x26,
UCI_STATUS_RANGING_RX_MAC_IE_MISSING = 0x27,
+ UCI_STATUS_ERROR_ROUND_INDEX_NOT_ACTIVATED = 0x28,
+ UCI_STATUS_ERROR_NUMBER_OF_ACTIVE_RANGING_ROUNDS_EXCEEDED = 0x29,
+ UCI_STATUS_ERROR_ROUND_INDEX_NOT_SET_AS_INITIATOR = 0x2A,
+ UCI_STATUS_ERROR_DL_TDOA_DEVICE_ADDRESS_NOT_MATCHING_IN_REPLY_TIME_LIST = 0x2B,
+ RFU_STATUS_CODE_RANGE_3 = 0x2C..0x2F,
// UWB Data Session Specific Status Codes
UCI_STATUS_DATA_MAX_TX_PSDU_SIZE_EXCEEDED = 0x30,
UCI_STATUS_DATA_RX_CRC_ERROR = 0x31,
+ RFU_STATUS_CODE_RANGE_4 = 0x32..0x4F,
// Vendor Specific Status Codes
- UCI_STATUS_ERROR_CCC_SE_BUSY = 0x50,
- UCI_STATUS_ERROR_CCC_LIFECYCLE = 0x51,
+ VENDOR_SPECIFIC_STATUS_CODE_RANGE_1 = 0x50..0xFE {
+ UCI_STATUS_ERROR_CCC_SE_BUSY = 0x50,
+ UCI_STATUS_ERROR_CCC_LIFECYCLE = 0x51,
+ UCI_STATUS_ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT = 0x52,
+ },
+
+ // For internal usage, we will use 0xFF as default.
+ VENDOR_SPECIFIC_STATUS_CODE_2 = 0xFF,
+}
+
+// This needs a separate type as the Status code values in an OWR for AOA
+// Measurement has different values.
+enum OwrAoaStatusCode : 8 {
+ UCI_STATUS_SUCCESS = 0x00,
+ UCI_STATUS_INTER_FRAME_INTERVAL_TIMEOUT = 0x01,
+}
+
+// This needs a separate StatusCode as the Status code values in the DATA_RCV packet have
+// different values from the generic StatusCode above.
+enum DataRcvStatusCode : 8 {
+ UCI_STATUS_SUCCESS = 0x00,
+ UCI_STATUS_ERROR = 0x01,
+ UCI_STATUS_UNKNOWN = 0x02,
+}
+
+enum CreditAvailability : 8 {
+ CREDIT_NOT_AVAILABLE = 0,
+ CREDIT_AVAILABLE = 1,
+}
+
+// The UCI spec defines these status codes for a DATA_TRANSFER_STATUS_NTF packet.
+enum DataTransferNtfStatusCode : 8 {
+ UCI_DATA_TRANSFER_STATUS_REPETITION_OK = 0x00,
+ UCI_DATA_TRANSFER_STATUS_OK = 0x01,
+ UCI_DATA_TRANSFER_STATUS_ERROR_DATA_TRANSFER = 0x02,
+ UCI_DATA_TRANSFER_STATUS_ERROR_NO_CREDIT_AVAILABLE = 0x03,
+ UCI_DATA_TRANSFER_STATUS_ERROR_REJECTED = 0x04,
+ UCI_DATA_TRANSFER_STATUS_SESSION_TYPE_NOT_SUPPORTED = 0x05,
+ UCI_DATA_TRANSFER_STATUS_ERROR_DATA_TRANSFER_IS_ONGOING = 0x06,
+}
+
+enum FiraComponent : 8 {
+ UWBS = 0x00,
+ HOST = 0x01,
+ SECURE_COMPONENT = 0x02,
}
enum ResetConfig : 8 {
@@ -138,6 +220,7 @@ enum AppConfigTlvType : 8 {
SFD_ID = 0x15,
PSDU_DATA_RATE = 0x16,
PREAMBLE_DURATION = 0x17,
+ LINK_LAYER_MODE = 0x18,
RANGING_TIME_STRUCT = 0x1A,
SLOTS_PER_RR = 0x1B,
TX_ADAPTIVE_PAYLOAD_POWER = 0x1C,
@@ -145,6 +228,7 @@ enum AppConfigTlvType : 8 {
RNG_DATA_NTF_AOA_BOUND = 0x1D,
RESPONDER_SLOT_INDEX = 0x1E,
PRF_MODE = 0x1F,
+ CAP_SIZE_RANGE = 0x20,
SCHEDULED_MODE = 0x22,
KEY_ROTATION = 0x23,
KEY_ROTATION_RATE = 0x24,
@@ -162,25 +246,41 @@ enum AppConfigTlvType : 8 {
SUB_SESSION_ID = 0x30,
BPRF_PHR_DATA_RATE = 0x31,
MAX_NUMBER_OF_MEASUREMENTS = 0x32,
+ UL_TDOA_TX_INTERVAL = 0x33,
+ UL_TDOA_RANDOM_WINDOW = 0x34,
STS_LENGTH = 0x35,
+ UL_TDOA_DEVICE_ID = 0x38,
+ UL_TDOA_TX_TIMESTAMP = 0x39,
+ MIN_FRAMES_PER_RR = 0x3A,
+ MTU_SIZE = 0x3B,
+ INTER_FRAME_INTERVAL = 0x3C,
+ RFU_APP_CFG_TLV_TYPE_RANGE_1 = 0x3D..0x44,
SESSION_KEY = 0x45,
SUBSESSION_KEY = 0x46,
-
- // CCC specific
- CCC_HOP_MODE_KEY = 0xA0,
- CCC_UWB_TIME0 = 0xA1,
- CCC_RANGING_PROTOCOL_VER = 0xA3,
- CCC_UWB_CONFIG_ID = 0xA4,
- CCC_PULSESHAPE_COMBO = 0xA5,
- CCC_URSK_TTL = 0xA6,
-
- // Interleaving ratio if AOA_RESULT_REQ is set to 0xF0.
- NB_OF_RANGE_MEASUREMENTS = 0xE3,
- NB_OF_AZIMUTH_MEASUREMENTS = 0xE4,
- NB_OF_ELEVATION_MEASUREMENTS = 0xE5,
-
- ENABLE_DIAGNOSTICS = 0xE8,
- DIAGRAMS_FRAME_REPORTS_FIELDS = 0xE9,
+ RFU_APP_CFG_TLV_TYPE_RANGE_2 = 0x47..0x9F,
+
+ VENDOR_SPECIFIC_APP_CFG_TLV_TYPE_RANGE_1 = 0xA0..0xDF {
+ // CCC specific
+ CCC_HOP_MODE_KEY = 0xA0,
+ CCC_UWB_TIME0 = 0xA1,
+ CCC_RANGING_PROTOCOL_VER = 0xA3,
+ CCC_UWB_CONFIG_ID = 0xA4,
+ CCC_PULSESHAPE_COMBO = 0xA5,
+ CCC_URSK_TTL = 0xA6,
+ CCC_LAST_INDEX_USED = 0xA8,
+ },
+
+ // Reserved for extension IDs.
+ RFU_APP_CFG_TLV_TYPE_RANGE_3 = 0xE0..0xE2,
+
+ VENDOR_SPECIFIC_APP_CFG_TLV_TYPE_RANGE_2 = 0xE3..0xFF {
+ // Interleaving ratio if AOA_RESULT_REQ is set to 0xF0.
+ NB_OF_RANGE_MEASUREMENTS = 0xE3,
+ NB_OF_AZIMUTH_MEASUREMENTS = 0xE4,
+ NB_OF_ELEVATION_MEASUREMENTS = 0xE5,
+ ENABLE_DIAGNOSTICS = 0xE8,
+ DIAGRAMS_FRAME_REPORTS_FIELDS = 0xE9,
+ },
}
enum FrameReportTlvType : 8 {
@@ -208,23 +308,36 @@ enum CapTlvType : 8 {
SUPPORTED_HPRF_PARAMETER_SETS = 0x0F,
SUPPORTED_AOA = 0x10,
SUPPORTED_EXTENDED_MAC_ADDRESS = 0x11,
- SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 0xE3,
- SUPPORTED_MIN_RANGING_INTERVAL_MS = 0xE4,
- SUPPORTED_RANGE_DATA_NTF_CONFIG = 0xE5,
- SUPPORTED_RSSI_REPORTING = 0xE6,
- SUPPORTED_DIAGNOSTICS = 0xE7,
-
- // CCC specific
- CCC_SUPPORTED_CHAPS_PER_SLOT = 0xA0,
- CCC_SUPPORTED_SYNC_CODES = 0xA1,
- CCC_SUPPORTED_HOPPING_CONFIG_MODES_AND_SEQUENCES = 0xA2,
- CCC_SUPPORTED_CHANNELS = 0xA3,
- CCC_SUPPORTED_VERSIONS = 0xA4,
- CCC_SUPPORTED_UWB_CONFIGS = 0xA5,
- CCC_SUPPORTED_PULSE_SHAPE_COMBOS = 0xA6,
- CCC_SUPPORTED_RAN_MULTIPLIER = 0xA7,
+ SUPPORTED_MAX_MESSAGE_SIZE = 0x12,
+ SUPPORTED_MAX_DATA_PACKET_PAYLOAD_SIZE = 0x13,
+ RFU_CAP_TLV_TYPE_RANGE_1 = 0x14..0x9F,
+
+ VENDOR_SPECIFIC_CAP_TLV_TYPE_RANGE_1 = 0xA0..0xBF {
+ // CCC specific
+ CCC_SUPPORTED_CHAPS_PER_SLOT = 0xA0,
+ CCC_SUPPORTED_SYNC_CODES = 0xA1,
+ CCC_SUPPORTED_HOPPING_CONFIG_MODES_AND_SEQUENCES = 0xA2,
+ CCC_SUPPORTED_CHANNELS = 0xA3,
+ CCC_SUPPORTED_VERSIONS = 0xA4,
+ CCC_SUPPORTED_UWB_CONFIGS = 0xA5,
+ CCC_SUPPORTED_PULSE_SHAPE_COMBOS = 0xA6,
+ CCC_SUPPORTED_RAN_MULTIPLIER = 0xA7,
+ CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER = 0xA8,
+ },
SUPPORTED_POWER_STATS = 0xC0,
+ VENDOR_SPECIFIC_CAP_TLV_TYPE_RANGE_2 = 0xC1..0xDF,
+ RFU_CAP_TLV_TYPE_RANGE_2 = 0xE0..0xE2,
+
+ VENDOR_SPECIFIC_CAP_TLV_TYPE_RANGE_3 = 0xE3..0xFF {
+ SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 0xE3,
+ SUPPORTED_MIN_RANGING_INTERVAL_MS = 0xE4,
+ SUPPORTED_RANGE_DATA_NTF_CONFIG = 0xE5,
+ SUPPORTED_RSSI_REPORTING = 0xE6,
+ SUPPORTED_DIAGNOSTICS = 0xE7,
+ SUPPORTED_MIN_SLOT_DURATION_RSTU = 0xE8,
+ SUPPORTED_MAX_RANGING_SESSION_NUMBER = 0xE9,
+ },
}
@@ -255,12 +368,55 @@ enum ReasonCode : 8 {
STATE_CHANGE_WITH_SESSION_MANAGEMENT_COMMANDS = 0x00,
MAX_RANGING_ROUND_RETRY_COUNT_REACHED = 0x01,
MAX_NUMBER_OF_MEASUREMENTS_REACHED = 0x02,
+ SESSION_SUSPENDED_DUE_TO_INBAND_SIGNAL = 0x03,
+ SESSION_RESUMED_DUE_TO_INBAND_SIGNAL = 0x04,
+ SESSION_STOPPED_DUE_TO_INBAND_SIGNAL = 0x05,
+ RFU_REASON_CODE_RANGE_1 = 0x06..0x1C,
+ ERROR_INVALID_UL_TDOA_RANDOM_WINDOW = 0x1D,
+ ERROR_MIN_RFRAMES_PER_RR_NOT_SUPPORTED = 0x1E,
+ ERROR_TX_DELAY_NOT_SUPPORTED = 0x1F,
ERROR_SLOT_LENGTH_NOT_SUPPORTED = 0x20,
ERROR_INSUFFICIENT_SLOTS_PER_RR = 0x21,
ERROR_MAC_ADDRESS_MODE_NOT_SUPPORTED = 0x22,
- ERROR_INVALID_RANGING_INTERVAL = 0x23,
+ ERROR_INVALID_RANGING_DURATION = 0x23,
ERROR_INVALID_STS_CONFIG = 0x24,
ERROR_INVALID_RFRAME_CONFIG = 0x25,
+ ERROR_HUS_NOT_ENOUGH_SLOTS = 0x26,
+ ERROR_HUS_CFP_PHASE_TOO_SHORT = 0x27,
+ ERROR_HUS_CAP_PHASE_TOO_SHORT = 0x28,
+ ERROR_HUS_OTHERS = 0x29,
+ ERROR_STATUS_SESSION_KEY_NOT_FOUND = 0x2A,
+ ERROR_STATUS_SUB_SESSION_KEY_NOT_FOUND = 0x2B,
+ ERROR_INVALID_PREAMBLE_CODE_INDEX = 0x2C,
+ ERROR_INVALID_SFD_ID = 0x2D,
+ ERROR_INVALID_PSDU_DATA_RATE = 0x2E,
+ ERROR_INVALID_PHR_DATA_RATE = 0x2F,
+ ERROR_INVALID_PREAMBLE_DURATION = 0x30,
+ ERROR_INVALID_STS_LENGTH = 0x31,
+ ERROR_INVALID_NUM_OF_STS_SEGMENTS = 0x32,
+ ERROR_INVALID_NUM_OF_CONTROLEES = 0x33,
+ ERROR_MAX_RANGING_REPLY_TIME_EXCEEDED = 0x34,
+ ERROR_INVALID_DST_ADDRESS_LIST = 0x35,
+ ERROR_INVALID_OR_NOT_FOUND_SUB_SESSION_ID = 0x36,
+ ERROR_INVALID_RESULT_REPORT_CONFIG = 0x37,
+ ERROR_INVALID_RANGING_ROUND_CONTROL_CONFIG = 0x38,
+ ERROR_INVALID_RANGING_ROUND_USAGE = 0x39,
+ ERROR_INVALID_MULTI_NODE_MODE = 0x3A,
+ ERROR_RDS_FETCH_FAILURE = 0x3B,
+ ERROR_REF_UWB_SESSION_DOES_NOT_EXIST = 0x3C,
+ ERROR_REF_UWB_SESSION_RANGING_DURATION_MISMATCH = 0x3D,
+ ERROR_REF_UWB_SESSION_INVALID_OFFSET_TIME = 0x3E,
+ ERROR_REF_UWB_SESSION_LOST = 0x3F,
+ RFU_REASON_CODE_RANGE_2 = 0x40..0x7F {
+ ERROR_DT_ANCHOR_RANGING_ROUNDS_NOT_CONFIGURED = 0x40,
+ ERROR_DT_TAG_RANGING_ROUNDS_NOT_CONFIGURED = 0x41,
+ },
+ VENDOR_SPECIFIC_REASON_CODE_RANGE_1 = 0x80..0xFE {
+ ERROR_INVALID_CHANNEL_WITH_AOA = 0x80,
+ ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT = 0x81,
+ },
+ // For internal usage, we will use 0xFF as default.
+ VENDOR_SPECIFIC_REASON_CODE_2 = 0xFF,
}
enum MulticastUpdateStatusCode : 8 {
@@ -285,17 +441,33 @@ enum SessionType: 8 {
}
enum MessageType: 3 {
+ DATA = 0x00,
COMMAND = 0x01,
RESPONSE = 0x02,
NOTIFICATION = 0x03,
+ RESERVED_FOR_TESTING_1 = 0x04,
+ RESERVED_FOR_TESTING_2 = 0x05,
}
// UCI packet description in compliance with the FIRA UCI spec.
// Only this packet should be sent/expected across the HAL interface.
-packet UciPacketHal; {
- group_id: GroupId,
+packet UciPacketHal {
+ group_id_or_data_packet_format: GroupIdOrDataPacketFormat,
packet_boundary_flag: PacketBoundaryFlag,
message_type: MessageType,
+ _body_
+}
+
+// The UciDataPacketHal must be declared before the UciControlPacketHal for correct parsing to
+// happen. This is required as the Data packet specifies a value for the 'message_type' constraint,
+// while the Control packet does not (as it encompasses multiple 'message_type' values).
+packet UciDataPacketHal: UciPacketHal (message_type = DATA) {
+ _reserved_: 8,
+ _size_(_payload_): 16,
+ _payload_,
+}
+
+packet UciControlPacketHal: UciPacketHal {
opcode: 6,
_reserved_: 2,
_reserved_: 8,
@@ -303,33 +475,76 @@ packet UciPacketHal; {
_payload_,
}
-// This packet definition is used throughout the stack that holds a complete (i.e unfragmented) UCI
-// command/response/notification.
-// UciPacket needs to be converted to one or more UciPacketHal fragments before sending to the HAL.
-// One or more UciPacketHal fragments needs to be converted to UciPacket when receiving from the HAL.
+// This control packet definition is used throughout the stack that holds a complete
+// (i.e unfragmented) UCI command/response/notification.
+//
+// UciControlPacket needs to be converted to one or more UciControlPacketHal fragments before
+// sending to the HAL. One or more UciControlPacketHal fragments needs to be converted to
+// UciControlPacket when receiving from the HAL.
+//
// TODO(b/202760099): Handle fragmentation more cleanly in the PDL.
-packet UciPacket {
+packet UciControlPacket {
group_id: GroupId,
- // This field is different from |UciPacketHal| to provide a placeholder for PBF flag.
+ // This field is different from |UciControlPacketHal| to provide a placeholder for PBF flag.
_reserved_: 1,
message_type: MessageType,
opcode: 6,
_reserved_: 2,
_reserved_: 8,
- // This field is different from |UciPacketHal| to allow holding large unfragmented packet.
+ // This field is different from |UciControlPacketHal| to allow holding a large unfragmented
+ // packet.
+ _size_(_payload_): 32,
+ _payload_,
+}
+
+// This data packet definition is used throughout the stack that holds a complete
+// (i.e unfragmented) UCI data packet.
+//
+// UciDataPacket needs to be converted to one or more UciDataPacketHal fragments before sending to
+// the HAL. One or more UciDataPacketHal fragments needs to be converted to UciDataPacket when
+// receiving from the HAL.
+//
+// TODO(b/202760099): Handle fragmentation more cleanly in the PDL.
+packet UciDataPacket {
+ data_packet_format: DataPacketFormat,
+ // This field is different from |UciDataPacketHal| to provide a placeholder for PBF flag.
+ _reserved_: 1,
+ message_type: MessageType,
+ _reserved_: 8,
+ // This field is different from |UciDataPacketHal| to allow holding large unfragmented packet.
_size_(_payload_): 32,
_payload_,
}
-packet UciCommand : UciPacket (message_type = COMMAND) {
+packet UciDataSnd : UciDataPacket (data_packet_format = DATA_SND, message_type = DATA) {
+ session_id: 32,
+ dest_mac_address: 64,
+ dest_fira_component: FiraComponent,
+ uci_sequence_number: 8,
+ _size_(data): 16,
+ data: 8[]
+}
+
+packet UciDataRcv : UciDataPacket (data_packet_format = DATA_RCV, message_type = DATA) {
+ session_id: 32,
+ status: DataRcvStatusCode,
+ uci_sequence_number: 32,
+ source_mac_address: 64,
+ source_fira_component: FiraComponent,
+ dest_fira_component: FiraComponent,
+ _size_(data): 16,
+ data: 8[]
+}
+
+packet UciCommand : UciControlPacket (message_type = COMMAND) {
_payload_,
}
-packet UciResponse : UciPacket (message_type = RESPONSE) {
+packet UciResponse : UciControlPacket (message_type = RESPONSE) {
_payload_,
}
-packet UciNotification : UciPacket (message_type = NOTIFICATION) {
+packet UciNotification : UciControlPacket (message_type = NOTIFICATION) {
_payload_,
}
@@ -345,27 +560,27 @@ packet CoreNotification : UciNotification (group_id = CORE) {
_body_,
}
-packet SessionCommand : UciCommand (group_id = SESSION_CONFIG) {
+packet SessionConfigCommand : UciCommand (group_id = SESSION_CONFIG) {
_body_,
}
-packet SessionResponse : UciResponse (group_id = SESSION_CONFIG) {
+packet SessionConfigResponse : UciResponse (group_id = SESSION_CONFIG) {
_body_,
}
-packet SessionNotification : UciNotification (group_id = SESSION_CONFIG) {
+packet SessionConfigNotification : UciNotification (group_id = SESSION_CONFIG) {
_body_,
}
-packet RangingCommand : UciCommand (group_id = RANGING_SESSION_CONTROL) {
+packet SessionControlCommand : UciCommand (group_id = SESSION_CONTROL) {
_body_,
}
-packet RangingResponse : UciResponse (group_id = RANGING_SESSION_CONTROL) {
+packet SessionControlResponse : UciResponse (group_id = SESSION_CONTROL) {
_body_,
}
-packet RangingNotification : UciNotification (group_id = RANGING_SESSION_CONTROL) {
+packet SessionControlNotification : UciNotification (group_id = SESSION_CONTROL) {
_body_,
}
@@ -479,6 +694,7 @@ packet SetConfigRsp : CoreResponse (opcode = 0x4) { //CORE_SET_CONFIG
test SetConfigRsp {
"\x40\x04\x00\x04\x00\x00\x00\x01\x01\x01\x01",
+ "\x40\x04\x00\x04\x00\x00\x00\x01\x01\x01\x0B",
}
packet GetConfigCmd : CoreCommand (opcode = 0x5) { //CORE_GET_CONFIG
@@ -508,7 +724,7 @@ test GenericError {
"\x60\x07\x00\x01\x00\x00\x00\x01",
}
-packet SessionInitCmd : SessionCommand (opcode = 0x0) { //SESSION_INIT
+packet SessionInitCmd : SessionConfigCommand (opcode = 0x0) { //SESSION_INIT
session_id: 32,
session_type: SessionType,
}
@@ -517,7 +733,7 @@ test SessionInitCmd {
"\x21\x00\x00\x05\x00\x00\x00\x01\x02\x03\x04\x01",
}
-packet SessionInitRsp : SessionResponse (opcode = 0x0) { //SESSION_INIT
+packet SessionInitRsp : SessionConfigResponse (opcode = 0x0) { //SESSION_INIT
status: StatusCode,
}
@@ -525,7 +741,7 @@ test SessionInitRsp {
"\x41\x00\x00\x01\x00\x00\x00\x11",
}
-packet SessionDeinitCmd : SessionCommand (opcode = 0x1) { //SESSION_DEINIT
+packet SessionDeinitCmd : SessionConfigCommand (opcode = 0x1) { //SESSION_DEINIT
session_id: 32,
}
@@ -533,7 +749,7 @@ test SessionDeinitCmd {
"\x21\x01\x00\x04\x00\x00\x00\x01\x02\x03\x04",
}
-packet SessionDeinitRsp : SessionResponse (opcode = 0x1) { //SESSION_DEINIT
+packet SessionDeinitRsp : SessionConfigResponse (opcode = 0x1) { //SESSION_DEINIT
status: StatusCode,
}
@@ -541,14 +757,17 @@ test SessionDeinitRsp {
"\x41\x01\x00\x01\x00\x00\x00\x00",
}
-packet SessionStatusNtf : SessionNotification (opcode = 0x2) { //SESSION_STATUS_NTF
+packet SessionStatusNtf : SessionConfigNotification (opcode = 0x2) { //SESSION_STATUS_NTF
session_id: 32,
session_state: SessionState,
- reason_code: ReasonCode,
+ // TODO(b/272775225): Switch back to the enum type ReasonCode, once PDL supports defining a
+ // range inside an enum (for the vendor-specific space), in b/267339120.
+ reason_code: 8,
}
test SessionStatusNtf {
"\x61\x02\x00\x06\x00\x00\x00\x01\x02\x03\x04\x02\x21",
+ "\x61\x02\x00\x06\x00\x00\x00\x01\x02\x03\x04\x01\x82", // Vendor Specific Reason Code
}
struct AppConfigTlv {
@@ -557,7 +776,7 @@ struct AppConfigTlv {
v: 8[],
}
-packet SessionSetAppConfigCmd : SessionCommand (opcode = 0x3) { //SESSION_SET_APP_CONFIG
+packet SessionSetAppConfigCmd : SessionConfigCommand (opcode = 0x3) { //SESSION_SET_APP_CONFIG
session_id: 32,
_count_(tlvs): 8,
tlvs: AppConfigTlv[]
@@ -572,7 +791,7 @@ struct AppConfigStatus {
status: StatusCode,
}
-packet SessionSetAppConfigRsp : SessionResponse (opcode = 0x3) { //SESSION_SET_APP_CONFIG
+packet SessionSetAppConfigRsp : SessionConfigResponse (opcode = 0x3) { //SESSION_SET_APP_CONFIG
status: StatusCode,
_count_(cfg_status): 8,
cfg_status: AppConfigStatus[],
@@ -582,7 +801,7 @@ test SessionSetAppConfigRsp {
"\x41\x03\x00\x04\x00\x00\x00\x01\x01\x01\x00",
}
-packet SessionGetAppConfigCmd : SessionCommand (opcode = 0x4) { //SESSION_GET_APP_CONFIG
+packet SessionGetAppConfigCmd : SessionConfigCommand (opcode = 0x4) { //SESSION_GET_APP_CONFIG
session_id: 32,
_count_(app_cfg): 8,
app_cfg: 8[], // AppConfigTlvType (Infra does not allow array of enums)
@@ -592,7 +811,7 @@ test SessionGetAppConfigCmd {
"\x21\x04\x00\x05\x00\x00\x00\x01\x02\x03\x04\x00",
}
-packet SessionGetAppConfigRsp : SessionResponse (opcode = 0x4) { //SESSION_GET_APP_CONFIG
+packet SessionGetAppConfigRsp : SessionConfigResponse (opcode = 0x4) { //SESSION_GET_APP_CONFIG
status: StatusCode,
_count_(tlvs): 8,
tlvs: AppConfigTlv[],
@@ -602,14 +821,14 @@ test SessionGetAppConfigRsp {
"\x41\x04\x00\x02\x00\x00\x00\x01\x00",
}
-packet SessionGetCountCmd : SessionCommand (opcode = 0x5) { //SESSION_GET_COUNT
+packet SessionGetCountCmd : SessionConfigCommand (opcode = 0x5) { //SESSION_GET_COUNT
}
test SessionGetCountCmd {
"\x21\x05\x00\x00\x00\x00\x00",
}
-packet SessionGetCountRsp : SessionResponse (opcode = 0x5) { //SESSION_GET_COUNT
+packet SessionGetCountRsp : SessionConfigResponse (opcode = 0x5) { //SESSION_GET_COUNT
status: StatusCode,
session_count: 8,
}
@@ -618,7 +837,7 @@ test SessionGetCountRsp {
"\x41\x05\x00\x02\x00\x00\x00\x00\x01",
}
-packet SessionGetStateCmd : SessionCommand (opcode = 0x6) { //SESSION_GET_STATE
+packet SessionGetStateCmd : SessionConfigCommand (opcode = 0x6) { //SESSION_GET_STATE
session_id: 32,
}
@@ -626,7 +845,7 @@ test SessionGetStateCmd {
"\x21\x06\x00\x04\x00\x00\x00\x00\x01\x02\x03",
}
-packet SessionGetStateRsp : SessionResponse (opcode = 0x6) { //SESSION_GET_STATE
+packet SessionGetStateRsp : SessionConfigResponse (opcode = 0x6) { //SESSION_GET_STATE
status: StatusCode,
session_state: SessionState,
}
@@ -635,43 +854,51 @@ test SessionGetStateRsp {
"\x41\x06\x00\x02\x00\x00\x00\x00\x01",
}
-enum MessageControl: 8 {
- SUB_SESSION_KEY_NOT_CONFIGURED = 0x0,
- SHORT_SUB_SESSION_KEY_CONFIGURED = 0x8,
- LONG_SUB_SESSION_KEY_CONFIGURED = 0x9,
+packet SessionUpdateDtTagRangingRoundsCmd : SessionConfigCommand (opcode = 0x9) { //SESSION_UPDATE_ACTIVE_ROUNDS_DT_TAG
+ session_id: 32,
+ _count_(ranging_round_indexes): 8,
+ ranging_round_indexes: 8[],
}
-struct Controlee {
- short_address: 16,
- subsession_id: 32,
+test SessionUpdateDtTagRangingRoundsCmd {
+ "\x21\x09\x00\x0a\x00\x00\x00\x03\x03\x0f\x0c\x05\x08\x00\x00\x00\x00",
+}
+
+packet SessionUpdateDtTagRangingRoundsRsp : SessionConfigResponse (opcode = 0x9) { //SESSION_UPDATE_ACTIVE_ROUNDS_DT_TAG
+ status: StatusCode,
+ _count_(ranging_round_indexes): 8,
+ ranging_round_indexes: 8[],
+}
+
+test SessionUpdateDtTagRangingRoundsRsp {
+ "\x41\x09\x00\x03\x00\x00\x00\x01\x01\x01",
}
-struct Controlee_V2_0_0_Byte_Version {
+struct Controlee {
short_address: 16,
subsession_id: 32,
- message_control: MessageControl,
}
struct Controlee_V2_0_16_Byte_Version {
short_address: 16,
subsession_id: 32,
- message_control: MessageControl,
subsession_key: 8[16],
}
struct Controlee_V2_0_32_Byte_Version {
short_address: 16,
subsession_id: 32,
- message_control: MessageControl,
subsession_key: 8[32],
}
enum UpdateMulticastListAction: 8 {
- ADD_CONTROLEE = 0,
- REMOVE_CONTROLEE = 1,
+ ADD_CONTROLEE = 0x00,
+ REMOVE_CONTROLEE = 0x01,
+ ADD_CONTROLEE_WITH_SHORT_SUB_SESSION_KEY = 0x02,
+ ADD_CONTROLEE_WITH_LONG_SUB_SESSION_KEY = 0x03,
}
-packet SessionUpdateControllerMulticastListCmd : SessionCommand (opcode = 0x7) { //SESSION_UPDATE_CONTROLLER_MULTICAST_LIST
+packet SessionUpdateControllerMulticastListCmd : SessionConfigCommand (opcode = 0x7) { //SESSION_UPDATE_CONTROLLER_MULTICAST_LIST
session_id: 32,
action: UpdateMulticastListAction,
_payload_,
@@ -682,11 +909,6 @@ struct SessionUpdateControllerMulticastListCmdPayload {
controlees: Controlee[],
}
-struct SessionUpdateControllerMulticastListCmd_2_0_0_Byte_Payload {
- _count_(controlees): 8,
- controlees: Controlee_V2_0_0_Byte_Version[],
-}
-
struct SessionUpdateControllerMulticastListCmd_2_0_16_Byte_Payload {
_count_(controlees): 8,
controlees: Controlee_V2_0_16_Byte_Version[],
@@ -697,7 +919,7 @@ struct SessionUpdateControllerMulticastListCmd_2_0_32_Byte_Payload {
controlees: Controlee_V2_0_32_Byte_Version[],
}
-packet SessionUpdateControllerMulticastListRsp : SessionResponse (opcode = 0x7) { //SESSION_UPDATE_CONTROLLER_MULTICAST_LIST
+packet SessionUpdateControllerMulticastListRsp : SessionConfigResponse (opcode = 0x7) { //SESSION_UPDATE_CONTROLLER_MULTICAST_LIST
status: StatusCode,
}
@@ -711,7 +933,7 @@ struct ControleeStatus {
status: MulticastUpdateStatusCode,
}
-packet SessionUpdateControllerMulticastListNtf : SessionNotification (opcode = 0x7) { //SESSION_UPDATE_CONTROLLER_MULTICAST_LIST
+packet SessionUpdateControllerMulticastListNtf : SessionConfigNotification (opcode = 0x7) { //SESSION_UPDATE_CONTROLLER_MULTICAST_LIST
session_id: 32,
remaining_multicast_list_size: 8,
_count_(controlee_status): 8,
@@ -722,20 +944,56 @@ test SessionUpdateControllerMulticastListNtf {
"\x61\x07\x00\x06\x00\x00\x00\x00\x01\x02\x03\x04\x00",
}
+packet DataCreditNtf : SessionControlNotification (opcode = 0x04) { // SESSION_DATA_CREDIT_NTF
+ session_id: 32,
+ credit_availability: CreditAvailability,
+}
-packet RangeStartCmd : RangingCommand (opcode = 0x0) { //RANGE_START
+test DataCreditNtf {
+ "\x62\x04\x00\x05\x00\x00\x00\x00\x00\x00\x01\x01",
+}
+
+packet DataTransferStatusNtf : SessionControlNotification (opcode = 0x05) { // SESSION_DATA_TRANSFER_STATUS_NTF
+ session_id: 32,
+ uci_sequence_number: 8,
+ status: DataTransferNtfStatusCode,
+ // TODO(b/269779288): Add the tx_count field for implementing the DATA_REPETITION added in CR490.
+}
+
+test DataTransferStatusNtf {
+ "\x62\x05\x00\x06\x00\x00\x00\x00\x00\x00\x01\x01\x00",
+}
+
+packet SessionQueryMaxDataSizeCmd : SessionConfigCommand (opcode = 0xB) { //QUERY_MAX_DATA_SIZE
+ session_id: 32,
+}
+
+test SessionQueryMaxDataSizeCmd {
+ "\x21\x0B\x00\x04\x00\x00\x00\x00",
+}
+
+packet SessionQueryMaxDataSizeRsp : SessionConfigResponse (opcode = 0xB) { //QUER_MAX_DATA_SIZE
+ session_id: 32,
+ max_data_size: 16,
+}
+
+test SessionQueryMaxDataSizeRsp {
+ "\x41\x0B\x00\x06\x00\x00\x00\x00\x0E7\0x07",
+}
+
+packet SessionStartCmd : SessionControlCommand (opcode = 0x0) { //RANGE_START
session_id: 32,
}
-test RangeStartCmd {
+test SessionStartCmd {
"\x22\x00\x00\x04\x00\x00\x00\x00\x01\x02\x03",
}
-packet RangeStartRsp : RangingResponse (opcode = 0x0) { //RANGE_START
+packet SessionStartRsp : SessionControlResponse (opcode = 0x0) { //RANGE_START
status: StatusCode,
}
-test RangeStartRsp {
+test SessionStartRsp {
"\x42\x00\x00\x01\x00\x00\x00\x00",
}
@@ -754,7 +1012,11 @@ struct ShortAddressTwoWayRangingMeasurement {
aoa_destination_elevation_fom: 8,
slot_index: 8,
rssi: 8,
- _reserved_: 88,
+ // b/272301550: The pdl compiler cannot handle individual fields
+ // larger than 64 bit. The work around is to split the 88 bit
+ // field into two.
+ _reserved_: 64,
+ _reserved_: 24,
}
struct ExtendedAddressTwoWayRangingMeasurement {
@@ -775,12 +1037,38 @@ struct ExtendedAddressTwoWayRangingMeasurement {
_reserved_: 40,
}
+struct ShortAddressOwrAoaRangingMeasurement {
+ mac_address: 16,
+ status: OwrAoaStatusCode,
+ nlos: 8,
+ frame_sequence_number: 8,
+ block_index: 16,
+ aoa_azimuth: 16,
+ aoa_azimuth_fom: 8,
+ aoa_elevation: 16,
+ aoa_elevation_fom: 8,
+}
+
+struct ExtendedAddressOwrAoaRangingMeasurement {
+ mac_address: 64,
+ status: OwrAoaStatusCode,
+ nlos: 8,
+ frame_sequence_number: 8,
+ block_index: 16,
+ aoa_azimuth: 16,
+ aoa_azimuth_fom: 8,
+ aoa_elevation: 16,
+ aoa_elevation_fom: 8,
+}
+
enum RangingMeasurementType : 8 {
ONE_WAY = 0x0,
TWO_WAY = 0x1,
+ DL_TDOA = 0x02,
+ OWR_AOA = 0x03,
}
-packet RangeDataNtf : RangingNotification (opcode = 0x0) { //RANGE_START
+packet SessionInfoNtf : SessionControlNotification (opcode = 0x0) { // SESSION_INFO
sequence_number: 32,
session_id: 32,
rcr_indicator: 8,
@@ -792,54 +1080,96 @@ packet RangeDataNtf : RangingNotification (opcode = 0x0) { //RANGE_START
_body_,
}
-packet ShortMacTwoWayRangeDataNtf : RangeDataNtf (ranging_measurement_type = TWO_WAY, mac_address_indicator = SHORT_ADDRESS) {
+packet ShortMacTwoWaySessionInfoNtf : SessionInfoNtf (ranging_measurement_type = TWO_WAY, mac_address_indicator = SHORT_ADDRESS) {
_count_(two_way_ranging_measurements) : 8,
two_way_ranging_measurements : ShortAddressTwoWayRangingMeasurement[],
+ vendor_data: 8[],
}
-test ShortMacTwoWayRangeDataNtf {
+test ShortMacTwoWaySessionInfoNtf {
"\x62\x00\x00\x19\x00\x00\x00\x00\x02\x03\x04\x05\x06\x07\x08\x00\x0a\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
}
-packet ExtendedMacTwoWayRangeDataNtf : RangeDataNtf (ranging_measurement_type = TWO_WAY, mac_address_indicator = EXTENDED_ADDRESS) {
+packet ExtendedMacTwoWaySessionInfoNtf : SessionInfoNtf (ranging_measurement_type = TWO_WAY, mac_address_indicator = EXTENDED_ADDRESS) {
_count_(two_way_ranging_measurements) : 8,
two_way_ranging_measurements : ExtendedAddressTwoWayRangingMeasurement[],
+ vendor_data: 8[],
}
-test ExtendedMacTwoWayRangeDataNtf {
+test ExtendedMacTwoWaySessionInfoNtf {
"\x62\x00\x00\x19\x00\x00\x00\x00\x02\x03\x04\x05\x06\x07\x08\x00\x0a\x01\x01\x01\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00",
}
-packet RangeStopCmd : RangingCommand (opcode = 0x1) { //RANGE_STOP
+packet ShortMacDlTDoASessionInfoNtf : SessionInfoNtf (ranging_measurement_type = DL_TDOA, mac_address_indicator = SHORT_ADDRESS) {
+ no_of_ranging_measurements : 8,
+ dl_tdoa_measurements : 8[],
+}
+
+test ShortMacDlTDoASessionInfoNtf {
+ "\x62\x00\x00\x19\x00\x00\x00\x00\x02\x03\x04\x05\x06\x07\x08\x00\x0a\x02\x01\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+}
+
+packet ExtendedMacDlTDoASessionInfoNtf : SessionInfoNtf (ranging_measurement_type = DL_TDOA, mac_address_indicator = EXTENDED_ADDRESS) {
+ no_of_ranging_measurements : 8,
+ dl_tdoa_measurements : 8[],
+}
+
+test ExtendedMacDlTDoASessionInfoNtf {
+ "\x62\x00\x00\x19\x00\x00\x00\x00\x02\x03\x04\x05\x06\x07\x08\x00\x0a\x01\x01\x01\x02\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+}
+
+packet ShortMacOwrAoaSessionInfoNtf : SessionInfoNtf (ranging_measurement_type = OWR_AOA, mac_address_indicator = SHORT_ADDRESS) {
+ _count_(owr_aoa_ranging_measurements) : 8,
+ owr_aoa_ranging_measurements : ShortAddressOwrAoaRangingMeasurement[],
+ vendor_data: 8[],
+}
+
+test ShortMacOwrAoaSessionInfoNtf {
+ "\x62\x00\x00\x19\x00\x00\x00\x00\x02\x03\x04\x05\x06\x07\x08\x00\x0a\x01\x01\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\x62\x00\x00\x26\x00\x00\x00\x00\x02\x03\x04\x05\x06\x07\x08\x00\x0a\x01\x01\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xbb\x00\x00\x01\x01\x00\x03\x04\x60\x05\x06\x50",
+}
+
+packet ExtendedMacOwrAoaSessionInfoNtf : SessionInfoNtf (ranging_measurement_type = OWR_AOA, mac_address_indicator = EXTENDED_ADDRESS) {
+ _count_(owr_aoa_ranging_measurements) : 8,
+ owr_aoa_ranging_measurements : ExtendedAddressOwrAoaRangingMeasurement[],
+ vendor_data: 8[],
+}
+
+test ExtendedMacOwrAoaSessionInfoNtf {
+ "\x62\x00\x00\x19\x00\x00\x00\x00\x02\x03\x04\x05\x06\x07\x08\x00\x0a\x01\x01\x01\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\x62\x00\x00\x2c\x00\x00\x00\x00\x02\x03\x04\x05\x06\x07\x08\x00\x0a\x01\x01\x01\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xbb\xcc\xdd\x01\x02\x03\x04\x00\x00\x01\x01\x00\x03\x04\x60\x05\x06\x50",
+}
+
+packet SessionStopCmd : SessionControlCommand (opcode = 0x1) { // SESSION_STOP
session_id: 32,
}
-test RangeStopCmd {
+test SessionStopCmd {
"\x22\x01\x00\x04\x00\x00\x00\x00\x02\x03\x04",
}
-packet RangeStopRsp : RangingResponse (opcode = 0x1) { //RANGE_STOP
+packet SessionStopRsp : SessionControlResponse (opcode = 0x1) { // SESSION_STOP
status: StatusCode,
}
-test RangeStopRsp {
+test SessionStopRsp {
"\x42\x01\x00\x01\x00\x00\x00\x00",
}
-packet RangeGetRangingCountCmd : RangingCommand (opcode = 0x3) { //RANGE_GET_RANGING_COUNT
+packet SessionGetRangingCountCmd : SessionControlCommand (opcode = 0x3) { // SESSION_GET_RANGING_COUNT
session_id: 32,
}
-test RangeGetRangingCountCmd {
+test SessionGetRangingCountCmd {
"\x22\x03\x00\x04\x00\x00\x00\x00\x02\x03\x04",
}
-packet RangeGetRangingCountRsp : RangingResponse (opcode = 0x3) { //RANGE_GET_RANGING_COUNT
+packet SessionGetRangingCountRsp : SessionControlResponse (opcode = 0x3) { // SESSION_GET_RANGING_COUNT
status: StatusCode,
count: 32,
}
-test RangeGetRangingCountRsp {
+test SessionGetRangingCountRsp {
"\x42\x03\x00\x05\x00\x00\x00\x00\x02\x03\x04\x05",
}
@@ -957,26 +1287,6 @@ test AndroidRangeDiagnosticsNtf {
"\x6c\x02\x00\x34\x00\x00\x00\x01\x01\x01\x01\x02\x02\x02\x02\x01\x00\x01\x02\x03\x01\x08\x00\x01\x02\x01\x02\x01\x02\x01\x01\x02\x15\x00\x01\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x02\x04\x00\x01\x02\x03\x04\x00\x01\x00\x00",
}
-packet UciVendor_9_Command : UciCommand (group_id = VENDOR_RESERVED_9) {
- _payload_,
-}
-
-packet UciVendor_A_Command : UciCommand (group_id = VENDOR_RESERVED_A) {
- _payload_,
-}
-
-packet UciVendor_B_Command : UciCommand (group_id = VENDOR_RESERVED_B) {
- _payload_,
-}
-
-packet UciVendor_E_Command : UciCommand (group_id = VENDOR_RESERVED_E) {
- _payload_,
-}
-
-packet UciVendor_F_Command : UciCommand (group_id = VENDOR_RESERVED_F) {
- _payload_,
-}
-
packet UciVendor_9_Response : UciResponse (group_id = VENDOR_RESERVED_9) {
_payload_,
}
diff --git a/src/uci/include/uci_defs.h b/src/uci/include/uci_defs.h
index 9237a75..8579e63 100755
--- a/src/uci/include/uci_defs.h
+++ b/src/uci/include/uci_defs.h
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
- * Copyright 2021 NXP.
+ * Copyright 2021-2022 NXP.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* You may not use this file except in compliance with the License.
@@ -27,6 +27,9 @@
#include <stdint.h>
+#define UCI_PAYLOAD_SUPPORT 1
+#define UCI_MAX_PAYLOAD_SIZE 4096
+
/* Define the message header size for all UCI Commands and Notifications.
*/
#define UCI_MSG_HDR_SIZE 0x04 /* per UCI spec */
@@ -37,9 +40,10 @@
#define UCI_PAYLOAD_SUPPORT 1
#define MAX_UCI_DATA_PKT_SIZE 4096
-#define LENGTH_INDCATOR_BIT 0x80 // 1000 0000
#define UCI_LENGTH_SHIFT 8
#define UCI_RESPONSE_STATUS_OFFSET 0x04
+#define UCI_RESPONSE_PAYLOAD_OFFSET 0x05
+#define UCI_MAX_FRAGMENT_BUFF_SIZE 4200
/* UCI Command and Notification Format:
* 4 byte message header:
@@ -51,6 +55,7 @@
/* MT: Message Type (byte 0) */
#define UCI_MT_MASK 0xE0
#define UCI_MT_SHIFT 0x05
+#define UCI_MT_DATA 0x00 /* (UCI_MT_DATA << UCI_MT_SHIFT) = 0x00 */
#define UCI_MT_CMD 0x01 /* (UCI_MT_CMD << UCI_MT_SHIFT) = 0x20 */
#define UCI_MT_RSP 0x02 /* (UCI_MT_RSP << UCI_MT_SHIFT) = 0x40 */
#define UCI_MT_NTF 0x03 /* (UCI_MT_NTF << UCI_MT_SHIFT) = 0x60 */
@@ -68,13 +73,15 @@
#define UCI_PBF_NO_OR_LAST 0x00 /* not fragmented or last fragment */
#define UCI_PBF_ST_CONT 0x10 /* start or continuing fragment */
+#define DATA_MESSAGE_SND 0x01
+
/* GID: Group Identifier (byte 0) */
#define UCI_GID_MASK 0x0F
#define UCI_GID_SHIFT 0x00
#define UCI_GID_CORE 0x00 /* 0000b UCI Core group */
#define UCI_GID_SESSION_MANAGE 0x01 /* 0001b Session Config commands */
#define UCI_GID_RANGE_MANAGE 0x02 /* 0010b Range Management group */
-#define UCI_GID_ANDROID 0x0E /* 1110b Android vendor group */
+#define UCI_GID_ANDROID 0x0C /* 1110b Android vendor group */
#define UCI_GID_TEST 0x0D /* 1101b RF Test Gropup */
/* Vendor specific group Identifier */
@@ -120,6 +127,17 @@
((UWB_HDR*)phUwb_GKI_getbuf((uint16_t)(UWB_HDR_SIZE + UCI_MSG_HDR_SIZE + \
UCI_MSG_OFFSET_SIZE + (paramlen))))
+/* UCI Data Format:
+ * byte 0: MT(0) PBF DPF
+ * byte 1: RFU
+ * byte 2: Data Length
+ * byte 3: Data Length */
+#define UCI_DATA_PBLD_HDR(p, pbf, len) \
+ *(p)++ = (uint8_t)(((pbf) << UCI_PBF_SHIFT) | DATA_MESSAGE_SND); \
+ *(p)++ = 0x00; \
+ *(p)++ = (uint8_t)(len); \
+ *(p)++ = (uint8_t)(((len) >> UCI_LENGTH_SHIFT));
+
/**********************************************
* UCI Core Group-0: Opcodes and size of commands
**********************************************/
@@ -136,6 +154,9 @@
#define UCI_MSG_CORE_DEVICE_INFO_CMD_SIZE 0x00
#define UCI_MSG_CORE_GET_CAPS_INFO_CMD_SIZE 0x00
+#define UCI_MSG_DATA_CREDIT_NTF 0x0B
+#define UCI_MSG_DATA_TRANSFER_STATUS_NTF 0x0C
+
/*********************************************************
* UCI session config Group-2: Opcodes and size of command
********************************************************/
@@ -147,6 +168,9 @@
#define UCI_MSG_SESSION_GET_COUNT 0x05
#define UCI_MSG_SESSION_GET_STATE 0x06
#define UCI_MSG_SESSION_UPDATE_CONTROLLER_MULTICAST_LIST 0x07
+#define UCI_MSG_SESSION_UPDATE_ACTIVE_ROUNDS_OF_DT_ANCHOR 0x08
+#define UCI_MSG_SESSION_UPDATE_ACTIVE_ROUNDS_OF_DT_TAG 0x09
+#define UCI_MSG_SESSION_CONFIGURE_DT_ANCHOR_RR_RDM_LIST 0x0A
/* Pay load size for each command*/
#define UCI_MSG_SESSION_INIT_CMD_SIZE 0x05
@@ -219,6 +243,7 @@
#define UCI_PARAM_ID_TX_ADAPTIVE_PAYLOAD_POWER 0x1C
#define UCI_PARAM_ID_RESPONDER_SLOT_INDEX 0x1E
#define UCI_PARAM_ID_PRF_MODE 0x1F
+#define UCI_PARAM_ID_CAP_SIZE_RANGE 0x20
#define UCI_PARAM_ID_SCHEDULED_MODE 0x22
#define UCI_PARAM_ID_KEY_ROTATION 0x23
#define UCI_PARAM_ID_KEY_ROTATION_RATE 0x24
@@ -236,6 +261,10 @@
#define UCI_PARAM_ID_SUB_SESSION_ID 0x30
#define UCI_PARAM_ID_BPRF_PHR_DATA_RATE 0x31
#define UCI_PARAM_ID_MAX_NUMBER_OF_MEASUREMENTS 0x32
+#define UCI_PARAM_ID_UL_TDOA_TX_INTERVAL 0x33
+#define UCI_PARAM_ID_UL_TDOA_RANDOM_WINDOW 0x34
+#define UCI_PARAM_ID_UL_TDOA_DEVICE_ID 0x38
+#define UCI_PARAM_ID_UL_TDOA_TX_TIMESTAMP 0x39
/* UCI Parameter ID Length */
#define UCI_PARAM_LEN_DEVICE_ROLE 0x01
@@ -278,6 +307,10 @@
#define UCI_PARAM_LEN_IN_BAND_TERMINATION_ATTEMPT_COUNT 0x01
#define UCI_PARAM_LEN_SUB_SESSION_ID 0x04
#define UCI_PARAM_LEN_BLOCK_STRIDE_LENGTH 0x01
+#define UCI_PARAM_LEN_UL_TDOA_TX_INTERVAL 0x04
+#define UCI_PARAM_LEN_UL_TDOA_RANDOM_WINDOW 0x04
+#define UCI_PARAM_LEN_UL_TDOA_DEVICE_ID 0x09
+#define UCI_PARAM_LEN_UL_TDOA_TX_TIMESTAMP 0x01
#define MAX_VENDOR_INFO_LENGTH 1000 // vendor specific info of rangedata max length considering 24 measures for TDOA
@@ -313,6 +346,8 @@
#define UCI_STATUS_RANGING_RX_MAC_DEC_FAILED 0x25
#define UCI_STATUS_RANGING_RX_MAC_IE_DEC_FAILED 0x26
#define UCI_STATUS_RANGING_RX_MAC_IE_MISSING 0x27
+#define STS_LENGTH 0x35
+#define RSSI_REPORTING 0x36
/* UWB Data Session Specific Status Codes */
#define UCI_STATUS_DATA_MAX_TX_PSDU_SIZE_EXCEEDED 0x30
@@ -334,8 +369,21 @@
/*************************************************
* Ranging Mesaurement type
**************************************************/
-#define MEASUREMENT_TYPE_ONEWAY 0x00
+#define MEASUREMENT_TYPE_ULTDOA 0x00
#define MEASUREMENT_TYPE_TWOWAY 0x01
+#define MEASUREMENT_TYPE_DLTDOA 0x02
+#define MEASUREMENT_TYPE_OWR_WITH_AOA 0x03
+
+#define EXTENDED_ADDRESS_LEN 0x08
+#define EXTENDED_PARAM_ID_MASK 0xF0
+
+/* Maximum size of UCI DATA Message the UWBS can receive */
+#define MAX_DATA_MSG_SIZE 0x00
+#define MAX_DATA_PKT_PAYLOAD_SIZE 0x01
+
+
+/* Maximum Length of RrRdmList*/
+#define MAX_RRRDM_LIST_LENGTH 0XFF
/*************************************************
* Mac Addressing Mode Indicator
@@ -348,6 +396,10 @@
#define SHORT_ADDRESS_LEN 0x02
#define EXTENDED_ADDRESS_LEN 0x08
#define MAX_NUM_OF_TDOA_MEASURES 24
+#define MAX_NUM_OF_DLTDOA_MEASURES 10
+#define MAX_NUM_OWR_AOA_MEASURES 1
+#define UCI_MAX_DATA_SIZE 4196
+
#define MAX_NUM_RESPONDERS \
12 // max number of responders for contention based raning
#define MAX_NUM_CONTROLLEES \
diff --git a/src/uwa/dm/uwa_dm_act.cc b/src/uwa/dm/uwa_dm_act.cc
index 57e27ed..e1d13f9 100755
--- a/src/uwa/dm/uwa_dm_act.cc
+++ b/src/uwa/dm/uwa_dm_act.cc
@@ -2,7 +2,7 @@
/******************************************************************************
*
* Copyright (C) 1999-2014 Broadcom Corporation
- * Copyright 2018-2020 NXP
+ * Copyright 2018-2022 NXP
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -359,6 +359,32 @@ static void uwa_dm_uwb_response_cback(tUWB_RESPONSE_EVT event,
&dm_cback_data);
} break;
+ case UWB_SESSION_ACTIVE_ROUNDS_INDEX_UPDATE_REVT:
+ {
+ dm_cback_data.status = p_data->status;
+ tUWA_UPDATE_RANGE_ROUND_INDEX_REVT* p_resp_data = &dm_cback_data.sRange_round_index;
+ p_resp_data->status = p_data->sRange_round_index.status;
+ p_resp_data->len = p_data->sRange_round_index.len;
+ if(p_resp_data->len > 0){
+ memcpy(p_resp_data->rng_round_index, p_data->sRange_round_index.rng_round_index, p_data->sRange_round_index.len);
+ }
+ }
+ (*uwa_dm_cb.p_dm_cback)(UWA_DM_SESSION_ACTIVE_ROUNDS_INDEX_UPDATE_REVT, &dm_cback_data);
+ break;
+
+ case UWB_SESSION_CONFIGURE_DT_ANCHOR_RR_RDM_REVT:
+ {
+ dm_cback_data.status = p_data->status;
+ tUWA_CONFIGURE_DT_ANCHOR_RR_RDM_LIST_REVT* p_resp_data = &dm_cback_data.sConfigure_dt_anchor_rr_rdm_list;
+ p_resp_data->status = p_data->sConfigure_dt_anchor_rr_rdm_list.status;
+ p_resp_data->len = p_data->sConfigure_dt_anchor_rr_rdm_list.len;
+ if(p_resp_data->len > 0){
+ memcpy(p_resp_data->rng_round_indexs, p_data->sConfigure_dt_anchor_rr_rdm_list.rng_round_indexs, p_data->sConfigure_dt_anchor_rr_rdm_list.len);
+ }
+ }
+ (*uwa_dm_cb.p_dm_cback)(UWA_DM_SESSION_CONFIGURE_DT_ANCHOR_RR_RDM_REVT, &dm_cback_data);
+ break;
+
case UWB_SET_COUNTRY_CODE_REVT: /* set country code response*/
if (p_data->status != UWB_STATUS_OK) {
UCI_TRACE_E(" Set country code request failed");
@@ -386,6 +412,32 @@ static void uwa_dm_uwb_response_cback(tUWB_RESPONSE_EVT event,
(*uwa_dm_cb.p_dm_cback)(UWA_DM_SEND_BLINK_DATA_NTF_EVT, &dm_cback_data);
} break;
+ case UWB_SEND_DATA_STATUS_EVT:
+ {
+ dm_cback_data.status = p_data->status;
+ (*uwa_dm_cb.p_dm_cback)(UWA_DM_SEND_DATA_STATUS_EVT, &dm_cback_data);
+ }
+ break;
+
+ case UWB_DATA_TRANSFER_STATUS_NTF_REVT:
+ {
+ tUWA_DATA_TRANSFER_STATUS_NTF_REVT* p_data_transmit = &dm_cback_data.sData_xfer_status;
+ p_data_transmit->session_id = p_data->sData_xfer_status.session_id;
+ p_data_transmit->sequence_num = p_data->sData_xfer_status.sequence_num;
+ p_data_transmit->status = p_data->sData_xfer_status.status;
+ (*uwa_dm_cb.p_dm_cback)(UWA_DM_DATA_TRANSFER_STATUS_NTF_EVT, &dm_cback_data);
+ }
+ break;
+
+ case UWB_DATA_RECV_REVT:
+ {
+ tUWA_RX_DATA_REVT* p_rcv_data = &dm_cback_data.sRcvd_data;
+ memset(p_rcv_data, 0, sizeof(tUWA_RX_DATA_REVT));
+ memcpy((uint8_t*)p_rcv_data, (uint8_t*)&p_data->sRcvd_data, sizeof(tUWA_RX_DATA_REVT));
+ (*uwa_dm_cb.p_dm_cback)(UWA_DM_DATA_RECV_EVT, &dm_cback_data);
+ }
+ break;
+
case UWB_CONFORMANCE_TEST_DATA: /* conformance test notification */
{
tUWA_CONFORMANCE_TEST_DATA* p_sConformance_data_ntf =
@@ -403,8 +455,8 @@ static void uwa_dm_uwb_response_cback(tUWB_RESPONSE_EVT event,
} break;
case UWB_VENDOR_SPECIFIC_UCI_NTF_EVT:
{
- dm_cback_data.sVendor_specific_ntf.len = p_data->sVendor_specific_ntf.len;
- memcpy((uint8_t*)dm_cback_data.sVendor_specific_ntf.data, p_data->sVendor_specific_ntf.data, p_data->sVendor_specific_ntf.len);
+ dm_cback_data.vendor_specific_ntf.len = p_data->vendor_specific_ntf.len;
+ memcpy((uint8_t*)dm_cback_data.vendor_specific_ntf.data, p_data->vendor_specific_ntf.data, p_data->vendor_specific_ntf.len);
(*uwa_dm_cb.p_dm_cback)(UWA_VENDOR_SPECIFIC_UCI_NTF_EVT, &dm_cback_data);
} break;
default:
@@ -909,6 +961,63 @@ bool uwa_dm_act_send_raw_cmd(tUWA_DM_MSG* p_data) {
/*******************************************************************************
**
+** Function uwa_dm_act_send_data_frame
+**
+** Description send data frame over UWB
+**
+** Returns FALSE (message buffer is NOT freed by caller)
+**
+*******************************************************************************/
+bool uwa_dm_act_send_data_frame(tUWA_DM_MSG* p_data){
+ tUWB_STATUS status;
+
+ if(p_data == NULL) {
+ UCI_TRACE_E("uwa_dm_act_test_stop_session(): p_data is NULL)");
+ return false;
+ } else {
+ status = UWB_SendData(
+ p_data->send_data_frame.session_id,
+ p_data->send_data_frame.p_addr, p_data->send_data_frame.dest_end_point,
+ p_data->send_data_frame.sequence_num, p_data->send_data_frame.data_len,
+ p_data->send_data_frame.p_data);
+ }
+ if(status == UWB_STATUS_OK) {
+ UCI_TRACE_D("uwa_dm_act_send_data_frame(): success , status=0x%X",status);
+ } else {
+ UCI_TRACE_E("uwa_dm_act_send_data_frame(): failed , status=0x%X",status);
+ }
+ return true;
+}
+
+/*******************************************************************************
+**
+** Function uwa_dm_act_update_active_range_round_index
+**
+** Description Update Active Ranging Index Command
+**
+** Returns FALSE (message buffer is NOT freed by caller)
+**
+*******************************************************************************/
+bool uwa_dm_act_update_active_range_round_index(tUWA_DM_MSG* p_data){
+ tUWB_STATUS status;
+
+ if(p_data == NULL) {
+ UCI_TRACE_E("uwa_dm_act_update_active_range_round_index(): p_data is NULL)");
+ return false;
+ } else {
+ status = UWB_UpdateRangingRoundIndex(p_data->update_rng_index.dlTdoaRole, p_data->update_rng_index.session_id, p_data->update_rng_index.number_of_rng_index,
+ p_data->update_rng_index.length, p_data->update_rng_index.p_rng_index);
+ }
+ if(status == UWB_STATUS_OK) {
+ UCI_TRACE_D("uwa_dm_act_update_active_range_round_index(): success , status=0x%X",status);
+ } else {
+ UCI_TRACE_E("uwa_dm_act_update_active_range_round_index(): failed , status=0x%X",status);
+ }
+ return true;
+}
+
+/*******************************************************************************
+**
** Function uwa_dm_act_get_range_count
**
** Description Send the get range count command to the ranging count
@@ -1020,6 +1129,32 @@ bool uwa_dm_act_multicast_list_update(tUWA_DM_MSG* p_data) {
/*******************************************************************************
**
+** Function uwa_dm_act_configure_dt_anchor_rr_rdm
+**
+** Description Configure dt anchor rr rdm list command
+**
+** Returns FALSE (message buffer is NOT freed by caller)
+**
+*******************************************************************************/
+bool uwa_dm_act_configure_dt_anchor_rr_rdm(tUWA_DM_MSG* p_data){
+ tUWB_STATUS status;
+ if (p_data->sConfigure_dt_anchor_rr_rdm_list.length + 2 > MAX_RRRDM_LIST_LENGTH) {
+ /* Total length of mac addr list must be less than 256 (1 byte) */
+ status = UWA_STATUS_FAILED;
+ } else {
+ status = UWB_ConfigureDTAnchorForRrRdmList(p_data->sConfigure_dt_anchor_rr_rdm_list.session_id, p_data->sConfigure_dt_anchor_rr_rdm_list.rr_rdm_count, p_data->sConfigure_dt_anchor_rr_rdm_list.length,
+ p_data->sConfigure_dt_anchor_rr_rdm_list.p_data);
+ if(UWB_STATUS_OK == status){
+ UCI_TRACE_D("uwa_dm_act_configure_dt_anchor_rr_rdm(): success ,status=0x%X",status);
+ } else {
+ UCI_TRACE_E("uwa_dm_act_configure_dt_anchor_rr_rdm(): failed ,status=0x%X",status);
+ }
+ }
+ return true;
+}
+
+/*******************************************************************************
+**
** Function uwa_dm_act_set_country_code
**
** Description send country code set command.
@@ -1346,6 +1481,15 @@ std::string uwa_dm_uwb_revt_2_str(tUWB_RESPONSE_EVT event) {
case UWB_BLINK_DATA_TX_NTF_REVT:
return "UWB_BLINK_DATA_TX_NTF_REVT";
+ case UWB_DATA_RECV_REVT:
+ return "UWB_DATA_RECV_REVT";
+
+ case UWB_DATA_TRANSFER_STATUS_NTF_REVT:
+ return "UWB_DATA_TRANSFER_STATUS_NTF_REVT";
+
+ case UWB_SEND_DATA_STATUS_EVT:
+ return "UWB_SEND_DATA_STATUS_EVT";
+
case UWB_CONFORMANCE_TEST_DATA:
return "UWB_CONFORMANCE_TEST_DATA";
diff --git a/src/uwa/dm/uwa_dm_api.cc b/src/uwa/dm/uwa_dm_api.cc
index f394318..b58ccba 100755
--- a/src/uwa/dm/uwa_dm_api.cc
+++ b/src/uwa/dm/uwa_dm_api.cc
@@ -1,7 +1,7 @@
/******************************************************************************
*
* Copyright (C) 2010-2014 Broadcom Corporation
- * Copyright 2018-2020 NXP
+ * Copyright 2018-2022 NXP
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -413,6 +413,45 @@ tUWA_STATUS UWA_GetAppConfig(uint32_t session_id, uint8_t noOfParams,
return (UWA_STATUS_FAILED);
}
+
+/*******************************************************************************
+**
+** Function UWA_UpdateRangingRoundIndex
+**
+** Description Update the Ranging Round Index for the given session for
+** TDoA Feature,The result is reported with an
+** UWA_DM_SESSION_ACTIVE_ROUNDS_INDEX_UPDATE_REVT in the tUWA_DM_CBACK
+** callback.
+**
+** Returns UWA_STATUS_OK if command is sent successfully
+** UWA_STATUS_FAILED otherwise
+**
+*******************************************************************************/
+tUWA_STATUS UWA_UpdateRangingRoundIndex(uint8_t dlTdoaRole, uint32_t session_id, uint8_t number_of_active_rngIndex,
+ uint8_t rng_round_index_len, uint8_t* p_rng_round_index) {
+ tUWA_DM_API_UPDATE_ACTIVE_RNG_INDEX* p_msg;
+
+ if ((p_msg = (tUWA_DM_API_UPDATE_ACTIVE_RNG_INDEX*)phUwb_GKI_getbuf(
+ (uint16_t)(sizeof(tUWA_DM_API_UPDATE_ACTIVE_RNG_INDEX) + rng_round_index_len))) != NULL)
+ {
+ p_msg->hdr.event = UWA_DM_API_UPDATE_ACTIVE_RNG_INDEX_EVT;
+ p_msg->session_id = session_id;
+ p_msg->dlTdoaRole = dlTdoaRole;
+ p_msg->number_of_rng_index = number_of_active_rngIndex;
+ p_msg->length = rng_round_index_len;
+ p_msg->p_rng_index = (uint8_t*)(p_msg + 1);
+
+ /* Copy the param IDs */
+ memcpy(p_msg->p_rng_index, p_rng_round_index, rng_round_index_len);
+
+ uwa_sys_sendmsg(p_msg);
+
+ return (UWA_STATUS_OK);
+ }
+
+ return (UWA_STATUS_FAILED);
+}
+
/*******************************************************************************
**
** Function UWA_StartRangingSession
@@ -599,6 +638,38 @@ extern tUWA_STATUS UWA_ControllerMulticastListUpdate(
/*******************************************************************************
**
+** Function UWA_ConfigureDTAnchorForRrRdmList
+**
+** Description This function is called to Configure DT Anchor RR RDM List Update.
+** The result is reported with an
+** UWA_SESSION_CONFIGURE_DT_ANCHOR_RR_RDM_REVT in the tUWA_DM_CBACK
+** callback.
+** Returns UWA_STATUS_OK if command is successfully initiated
+** UWA_STATUS_FAILED otherwise
+**
+*******************************************************************************/
+tUWA_STATUS UWA_ConfigureDTAnchorForRrRdmList(uint32_t session_id, uint8_t noOfParams, uint8_t rrRdmConfigParamLen , uint8_t rrRdmConfigParam[]) {
+ tUWA_DM_API_CONFIGURE_DT_ANCHOR_RR_RDM_LIST* p_msg;
+ p_msg = (tUWA_DM_API_CONFIGURE_DT_ANCHOR_RR_RDM_LIST*)phUwb_GKI_getbuf(sizeof(tUWA_DM_API_CONFIGURE_DT_ANCHOR_RR_RDM_LIST));
+
+ if (p_msg != NULL) {
+ p_msg->hdr.event = UWA_DM_API_CONFIGURE_DT_ANCHOR_RR_RDM_LIST_EVT;
+ p_msg->session_id = session_id;
+ p_msg->rr_rdm_count = noOfParams;
+ p_msg->length = rrRdmConfigParamLen;
+ p_msg->p_data= (uint8_t*)(p_msg + 1);
+
+ memcpy(p_msg->p_data, rrRdmConfigParam, (rrRdmConfigParamLen));
+
+ uwa_sys_sendmsg(p_msg);
+
+ return UWA_STATUS_OK;
+ }
+ return UWA_STATUS_FAILED;
+}
+
+/*******************************************************************************
+**
** Function UWA_ControllerSetCountryCode
**
** Description This function is called to set country code.
@@ -928,4 +999,43 @@ tUWA_STATUS UWA_SendRawCommand(uint16_t cmd_params_len, uint8_t* p_cmd_params,
}
return UWA_STATUS_FAILED;
-} \ No newline at end of file
+}
+
+/*******************************************************************************
+**
+** Function UWA_SendUwbDataFrame
+**
+** Description This function is called to send UWB data over UWB RF interafce .
+**
+** Returns UWA_STATUS_OK if data sucessfully accepeted by UWB subsystem
+** UWA_STATUS_FAILED otherwise
+**
+*******************************************************************************/
+tUWA_STATUS UWA_SendUwbData(uint32_t session_id,
+ uint8_t* p_addr, uint8_t dest_end_point, uint8_t sequence_num,
+ uint16_t data_len,
+ uint8_t* p_data) {
+ tUWA_DM_API_SEND_DATA_FRAME* p_msg;
+ UCI_TRACE_I("UWA_SendUwbDataFrame: data_len = %d", data_len);
+ if ((data_len == 0) || (p_data == nullptr) || (p_addr == nullptr))
+ return (UWA_STATUS_FAILED);
+
+ p_msg = (tUWA_DM_API_SEND_DATA_FRAME*)phUwb_GKI_getbuf(sizeof(tUWA_DM_API_SEND_DATA_FRAME) + data_len);
+ if (p_msg != nullptr) {
+ p_msg->hdr.event = UWA_DM_API_SEND_DATA_FRAME_EVT;
+ p_msg->session_id = session_id;
+ memcpy(p_msg->p_addr, p_addr, EXTENDED_ADDRESS_LEN);
+ p_msg->dest_end_point = dest_end_point;
+ p_msg->sequence_num = sequence_num;
+ p_msg->data_len = data_len;
+
+ p_msg->p_data = (uint8_t*)(p_msg + 1);
+ memcpy(p_msg->p_data, p_data, data_len);
+
+ uwa_sys_sendmsg(p_msg);
+
+ return (UWA_STATUS_OK);
+ }
+ return UWA_STATUS_FAILED;
+
+}
diff --git a/src/uwa/dm/uwa_dm_main.cc b/src/uwa/dm/uwa_dm_main.cc
index 014bc93..7502e56 100755
--- a/src/uwa/dm/uwa_dm_main.cc
+++ b/src/uwa/dm/uwa_dm_main.cc
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
- * Copyright 2021 NXP.
+ * Copyright 2021-2022 NXP.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* You may not use this file except in compliance with the License.
@@ -71,7 +71,11 @@ const tUWA_DM_ACTION uwa_dm_action[] = {
uwa_dm_act_test_per_rx, /* UWA_DM_API_TEST_PER_RX_EVT */
uwa_dm_act_test_uwb_loopback, /* UWA_DM_API_TEST_UWB_LOOPBACK_EVT */
uwa_dm_act_test_rx, /* UWA_DM_API_TEST_RX_EVT */
- uwa_dm_act_test_stop_session /* UWA_DM_API_TEST_STOP_SESSION_EVT */
+ uwa_dm_act_test_stop_session, /* UWA_DM_API_TEST_STOP_SESSION_EVT */
+ /* API events for Data tranfer handling */
+ uwa_dm_act_send_data_frame, /* UWA_DM_API_SEND_DATA_FRAME_EVT */
+ uwa_dm_act_configure_dt_anchor_rr_rdm, /* UWA_DM_API_CONFIGURE_DT_ANCHOR_RR_RDM_LIST_EVT */
+ uwa_dm_act_update_active_range_round_index /* UWA_DM_API_UPDATE_ACTIVE_RNG_INDEX_EVT */
};
/*****************************************************************************
diff --git a/src/uwa/include/uwa_api.h b/src/uwa/include/uwa_api.h
index 5da7cba..0e14a4a 100755
--- a/src/uwa/include/uwa_api.h
+++ b/src/uwa/include/uwa_api.h
@@ -1,7 +1,7 @@
/******************************************************************************
*
* Copyright (C) 1999-2012 Broadcom Corporation
- * Copyright 2018-2020 NXP
+ * Copyright 2018-2022 NXP
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -146,6 +146,12 @@ enum {
UWA_DM_CONFORMANCE_NTF_EVT, /* Conformance Test Ntf Event */
UWA_DM_SET_COUNTRY_CODE_RSP_EVT, /* Country code update resp event */
UWA_VENDOR_SPECIFIC_UCI_NTF_EVT, /* Proprietary Ntf Event */
+ UWA_DM_SEND_DATA_STATUS_EVT, /* data status EVT */
+ UWA_DM_SEND_DATA_PACKET_RSP_EVT, /* data reception status by UWBS */
+ UWA_DM_DATA_TRANSFER_STATUS_NTF_EVT, /* data transfer status over UWB */
+ UWA_DM_DATA_RECV_EVT, /* Recieved data over UWB */
+ UWA_DM_SESSION_CONFIGURE_DT_ANCHOR_RR_RDM_REVT, /* Result of Configure DT Anchor RR RDM List Cmd */
+ UWA_DM_SESSION_ACTIVE_ROUNDS_INDEX_UPDATE_REVT, /* Result of Update Active Ranging Index Cmd */
};
/* UWA_DM callback events for UWB RF events */
@@ -186,7 +192,7 @@ typedef struct {
uint16_t phy_version;
uint16_t uciTest_version;
uint8_t vendor_info_len;
- uint8_t vendor_info[UCI_VENDOR_INFO_MAX_SIZE];
+ uint8_t vendor_info[UCI_MAX_FRAGMENT_BUFF_SIZE];
} tUWA_GET_DEVICE_INFO_REVT;
/* Data for UWA_DM_CORE_SET_CONFIG_RSP_EVT */
@@ -261,30 +267,71 @@ typedef struct {
uint16_t aoa_dest_elevation;
uint8_t aoa_dest_elevation_FOM;
uint8_t slot_index;
- uint8_t rfu[12];
+ uint8_t rssi;
+ uint8_t rfu[11];
} tUWA_TWR_RANGING_MEASR;
typedef struct {
uint8_t mac_addr[8];
+ uint8_t message_control;
uint8_t frame_type;
uint8_t nLos; /* non line of sight */
uint16_t aoa_azimuth;
uint8_t aoa_azimuth_FOM;
uint16_t aoa_elevation;
uint8_t aoa_elevation_FOM;
- uint64_t timeStamp;
- uint32_t blink_frame_number; /* blink frame number received from tag/master
- anchor */
- uint8_t rfu[12];
- uint8_t device_info_size; /* Size of Device Specific Information */
- uint8_t* device_info; /* Device Specific Information */
- uint8_t blink_payload_size; /* Size of Blink Payload Data */
- uint8_t* blink_payload_data; /* Blink Payload Data */
+ uint32_t frame_number;
+ uint8_t rxTimeStamp[8];
+ uint8_t ulTdoa_device_id[8];
+ uint8_t txTimeStamp[8];
} tUWA_TDoA_RANGING_MEASR;
+/* the data type associated with vendor notification */
+typedef struct {
+ uint16_t len;
+ uint8_t data[UCI_VENDOR_INFO_MAX_SIZE];
+}tUWA_VENDOR_SPECIFIC_NTF;
+
+typedef struct {
+ uint8_t mac_addr[8];
+ uint8_t status;
+ uint8_t nLos;
+ uint8_t frame_seq_num;
+ uint16_t block_index;
+ uint16_t aoa_azimuth;
+ uint8_t aoa_azimuth_FOM;
+ uint16_t aoa_elevation;
+ uint8_t aoa_elevation_FOM;
+} tUWA_OWR_WITH_AOA_RANGING_MEASR;
+
+typedef struct {
+ uint8_t mac_addr[8];
+ uint8_t status;
+ uint8_t message_type;
+ uint16_t message_control;
+ uint16_t block_index;
+ uint8_t round_index;
+ uint8_t nLos;
+ uint16_t aoa_azimuth;
+ uint8_t aoa_azimuth_FOM;
+ uint16_t aoa_elevation;
+ uint8_t aoa_elevation_FOM;
+ uint8_t txTimeStamp[8];
+ uint8_t rxTimeStamp[8];
+ uint16_t cfo_anchor;
+ uint16_t cfo;
+ uint32_t initiator_reply_time;
+ uint32_t responder_reply_time;
+ uint16_t initiator_responder_TOF;
+ uint8_t anchor_location[12];
+ uint8_t active_ranging_round[15];
+} tUWA_DLTDOA_RANGING_MEASR;
+
typedef union {
tUWA_TWR_RANGING_MEASR twr_range_measr[MAX_NUM_RESPONDERS];
tUWA_TDoA_RANGING_MEASR tdoa_range_measr[MAX_NUM_OF_TDOA_MEASURES];
+ tUWA_DLTDOA_RANGING_MEASR dltdoa_range_measr[MAX_NUM_OF_DLTDOA_MEASURES];
+ tUWA_OWR_WITH_AOA_RANGING_MEASR owr_with_aoa_range_measr;
} tUWA_RANGING_MEASR;
typedef struct {
@@ -299,6 +346,7 @@ typedef struct {
uint8_t reserved[8];
uint8_t no_of_measurements;
tUWA_RANGING_MEASR ranging_measures;
+ tUWA_VENDOR_SPECIFIC_NTF vendor_specific_ntf;
} tUWA_RANGE_DATA_NTF;
/* the data type associated with UWB_GET_RANGE_COUNT_REVT */
@@ -332,17 +380,44 @@ typedef struct {
exhausted */
} tUWA_SEND_BLINK_DATA_NTF;
+/* the data type associated with UWB_DATA_TRANSFER_STATUS_NTF_REVT */
+typedef struct {
+ uint32_t session_id;
+ uint8_t sequence_num;
+ uint8_t status;
+} tUWA_DATA_TRANSFER_STATUS_NTF_REVT;
+
+/* the data type associated with UWA_DM_DATA_RECV_REVT */
+typedef struct {
+ uint32_t session_id;
+ uint8_t status;
+ uint32_t sequence_num;
+ uint8_t address[EXTENDED_ADDRESS_LEN];
+ uint8_t source_end_point;
+ uint8_t dest_end_point;
+ uint16_t data_len;
+ uint8_t data[UCI_MAX_DATA_SIZE];
+} tUWA_RX_DATA_REVT;
+
/* the data type associated with UWB_CONFORMANCE_TEST_DATA */
typedef struct {
uint16_t length;
uint8_t data[CONFORMANCE_TEST_MAX_UCI_PKT_LENGTH];
} tUWA_CONFORMANCE_TEST_DATA;
-/* the data type associated with vendor notification */
+/* the data type associated with UWB_SESSION_ACTIVE_ROUNDS_INDEX_UPDATE_REVT */
typedef struct {
+ uint8_t status;
uint16_t len;
- uint8_t data[UCI_VENDOR_INFO_MAX_SIZE];
-}tUWA_VENDOR_SPECIFIC_NTF;
+ uint8_t rng_round_index[255];
+}tUWA_UPDATE_RANGE_ROUND_INDEX_REVT;
+
+/* the data type associated with UWB_SESSION_CONFIGURE_DT_ANCHOR_RR_RDM_REVT */
+typedef struct {
+ uint8_t status;
+ uint16_t len;
+ uint8_t rng_round_indexs[255];
+}tUWA_CONFIGURE_DT_ANCHOR_RR_RDM_LIST_REVT;
/* Union of all DM callback structures */
typedef union {
@@ -373,8 +448,12 @@ typedef union {
tUWA_SESSION_UPDATE_MULTICAST_LIST_NTF
sMulticast_list_ntf; /*UWA_DM_SESSION_MC_LIST_UPDATE_NTF_EVT*/
tUWA_SEND_BLINK_DATA_NTF sBlink_data_ntf; /*UWA_DM_SEND_BLINK_DATA_NTF_EVT*/
+ tUWA_DATA_TRANSFER_STATUS_NTF_REVT sData_xfer_status ; /*UWA_DATA_TRANSFER_STATUS_NTF_REVT*/
+ tUWA_RX_DATA_REVT sRcvd_data; /*UWA_DM_DATA_RECV_REVT */
+ tUWA_UPDATE_RANGE_ROUND_INDEX_REVT sRange_round_index; /*UWA_DM_UPDATE_RANGE_ROUND_INDEX_REVT */
+ tUWA_CONFIGURE_DT_ANCHOR_RR_RDM_LIST_REVT sConfigure_dt_anchor_rr_rdm_list; /*UWA_SESSION_CONFIGURE_DT_ANCHOR_RR_RDM_REVT */
tUWA_CONFORMANCE_TEST_DATA sConformance_ntf; /* UWA_DM_CONFORMANCE_NTF_EVT */
- tUWA_VENDOR_SPECIFIC_NTF sVendor_specific_ntf; /*Vendor Specific ntf data */
+ tUWA_VENDOR_SPECIFIC_NTF vendor_specific_ntf; /*Vendor Specific ntf data */
void* p_vs_evt_data; /* Vendor-specific evt data */
} tUWA_DM_CBACK_DATA;
@@ -843,4 +922,48 @@ extern tUWA_STATUS UWA_SendRawCommand(uint16_t cmd_params_len,
uint8_t* p_cmd_params,
tUWA_RAW_CMD_CBACK* p_cback);
+/*******************************************************************************
+**
+** Function UWA_SendUwbDataFrame
+**
+** Description This function is called to send UWB data over UWB RF interafce .
+**
+** data_len - The data length
+** p_data - pointer to data buffer
+**
+** Returns UWA_STATUS_OK if data sucessfully accepeted by UWB subsystem
+** UWA_STATUS_FAILED otherwise
+**
+*******************************************************************************/
+extern tUWA_STATUS UWA_SendUwbData(uint32_t session_id,
+ uint8_t* p_addr, uint8_t dest_end_point, uint8_t sequence_num,
+ uint16_t data_len,
+ uint8_t* p_data);
+
+/*******************************************************************************
+**
+** Function UWA_ConfigureDTAnchorForRrRdmList
+**
+** Description This function is called to Configure DT anchor RR RDM List.
+**
+** Returns tUWA_STATUS
+**
+*******************************************************************************/
+extern tUWA_STATUS UWA_ConfigureDTAnchorForRrRdmList(uint32_t session_id, uint8_t rr_rdm_count,
+ uint8_t rrRdmConfigParamLen, uint8_t rrRdmConfigParam[]);
+
+/*******************************************************************************
+**
+** Function UWA_UpdateRangingRoundIndex
+**
+** Description This function is called to update Ranging round index for TDoA feature.
+**
+** Returns UWA_STATUS_OK if data sucessfully accepeted by UWB subsystem
+** UWA_STATUS_FAILED otherwise
+**
+*******************************************************************************/
+
+extern tUWA_STATUS UWA_UpdateRangingRoundIndex(uint8_t dlTdoaRole, uint32_t session_id,
+ uint8_t number_of_active_rngIndex, uint8_t rng_round_index_len,
+ uint8_t* p_rng_round_index);
#endif /* UWA_API_H */
diff --git a/src/uwa/include/uwa_dm_int.h b/src/uwa/include/uwa_dm_int.h
index d88d378..160501e 100755
--- a/src/uwa/include/uwa_dm_int.h
+++ b/src/uwa/include/uwa_dm_int.h
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
- * Copyright 2021 NXP.
+ * Copyright 2021-2022 NXP.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* You may not use this file except in compliance with the License.
@@ -66,6 +66,9 @@ enum {
UWA_DM_API_TEST_RX_EVT,
UWA_DM_API_TEST_STOP_SESSION_EVT,
/* UWB Data packet events */
+ UWA_DM_API_SEND_DATA_FRAME_EVT,
+ UWA_DM_API_CONFIGURE_DT_ANCHOR_RR_RDM_LIST_EVT,
+ UWA_DM_API_UPDATE_ACTIVE_RNG_INDEX_EVT,
UWA_DM_MAX_EVT
};
@@ -192,6 +195,15 @@ typedef struct {
uint32_t subsession_id_list[MAX_NUM_CONTROLLEES];
} tUWA_DM_API_SESSION_UPDATE_MULTICAST_LIST;
+/* data type for UWA_DM_API_CONFIGURE_DT_ANCHOR_RR_RDM_LIST_EVT */
+typedef struct {
+ UWB_HDR hdr;
+ uint32_t session_id;
+ uint8_t rr_rdm_count;
+ uint8_t length;
+ uint8_t* p_data;
+} tUWA_DM_API_CONFIGURE_DT_ANCHOR_RR_RDM_LIST;
+
/* data type for UWA_DM_API_SESSION_UPDATE_MULTICAST_LIST_EVT */
typedef struct {
UWB_HDR hdr;
@@ -207,6 +219,27 @@ typedef struct {
uint8_t app_data[UCI_MAX_PAYLOAD_SIZE];
} tUWA_DM_API_SEND_BLINK_DATA;
+/* data type for UWA_DM_API_SEND_DATA_FRAME_EVT */
+typedef struct {
+ UWB_HDR hdr;
+ uint32_t session_id;
+ uint8_t p_addr[EXTENDED_ADDRESS_LEN];
+ uint8_t dest_end_point;
+ uint8_t sequence_num;
+ uint16_t data_len;
+ uint8_t* p_data;
+} tUWA_DM_API_SEND_DATA_FRAME;
+
+/* data type for UWA_DM_API_UPDATE_ACTIVE_RNG_INDEX_EVT */
+typedef struct {
+ UWB_HDR hdr;
+ uint8_t dlTdoaRole;
+ uint32_t session_id;
+ uint8_t number_of_rng_index;
+ uint8_t length;
+ uint8_t* p_rng_index;
+} tUWA_DM_API_UPDATE_ACTIVE_RNG_INDEX;
+
/* data type for UWA_DM_API_TEST_SET_CONFIG_EVT */
typedef struct {
UWB_HDR hdr;
@@ -288,11 +321,16 @@ typedef union {
sUwb_loopback; /* UWA_DM_API_TEST_UWB_LOOPBACK_EVT */
tUWA_DM_API_SESSION_UPDATE_MULTICAST_LIST
sMulticast_list; /* UWA_DM_API_SESSION_UPDATE_MULTICAST_LIST_EVT */
+ tUWA_DM_API_CONFIGURE_DT_ANCHOR_RR_RDM_LIST
+ sConfigure_dt_anchor_rr_rdm_list; /* UWA_DM_API_CONFIGURE_DT_ANCHOR_RR_RDM_LIST_EVT */
+ tUWA_DM_API_UPDATE_ACTIVE_RNG_INDEX
+ update_rng_index; /* UWA_DM_API_UPDATE_ACTIVE_RNG_INDEX_EVT */
tUWA_DM_API_SET_COUNTRY_CODE
sCountryCode; /* UWA_DM_API_SET_COUNTRY_CODE_EVT */
tUWA_DM_API_SEND_BLINK_DATA
sSend_blink_data; /* UWA_DM_API_SEND_BLINK_DATA_EVT */
/* data types for all UWB RF TEST events */
+ tUWA_DM_API_SEND_DATA_FRAME send_data_frame; /* UWA_DM_API_SEND_DATA_FRAME_EVT */
tUWA_DM_API_TEST_GET_CONFIG
sTest_get_config; /* UWA_DM_API_TEST_GET_CONFIG_EVT */
tUWA_DM_API_TEST_SET_CONFIG
@@ -341,6 +379,9 @@ bool uwa_dm_act_get_device_capability(tUWA_DM_MSG* p_data);
bool uwa_dm_act_multicast_list_update(tUWA_DM_MSG* p_data);
bool uwa_dm_act_set_country_code(tUWA_DM_MSG* p_data);
bool uwa_dm_act_send_blink_data(tUWA_DM_MSG* p_data);
+bool uwa_dm_act_send_data_frame(tUWA_DM_MSG* p_data);
+bool uwa_dm_act_configure_dt_anchor_rr_rdm(tUWA_DM_MSG* p_data);
+bool uwa_dm_act_update_active_range_round_index(tUWA_DM_MSG* p_data);
/* Action function prototypes for all RF test functionality */
bool uwa_dm_act_test_set_config(tUWA_DM_MSG* p_data);
diff --git a/src/uwb/include/uci_hmsgs.h b/src/uwb/include/uci_hmsgs.h
index f317100..2ecbe04 100755
--- a/src/uwb/include/uci_hmsgs.h
+++ b/src/uwb/include/uci_hmsgs.h
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
- * Copyright 2021 NXP.
+ * Copyright 2021-2022 NXP.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* You may not use this file except in compliance with the License.
@@ -52,6 +52,15 @@ uint8_t uci_snd_range_start_cmd(uint32_t session_id);
uint8_t uci_snd_range_stop_cmd(uint32_t session_id);
uint8_t uci_snd_blink_data_cmd(uint32_t session_id, uint8_t repetition_count,
uint8_t app_data_len, uint8_t* app_data);
+uint8_t uci_send_data_frame(uint32_t session_id,
+ uint8_t* p_addr, uint8_t dest_end_point, uint8_t sequence_num,
+ uint16_t data_len,
+ uint8_t* p_data);
+uint8_t uci_send_range_round_index_update_cmd(uint8_t dlTdoaRole,
+ uint32_t session_id, uint8_t number_of_active_rngIndex,
+ uint8_t rng_round_index_len, uint8_t* p_rng_round_index);
+uint8_t uci_snd_configure_dt_anchor_for_rr_rdm_list_cmd(uint32_t session_id,
+ uint8_t rr_rdm_count, uint8_t length, uint8_t* data);
/* APIs for UWB RF test functionality */
uint8_t uci_snd_test_get_config_cmd(uint32_t session_id, uint8_t num_ids,
@@ -83,6 +92,9 @@ extern void uci_proc_test_management_rsp(uint8_t op_code, uint8_t* p_buf,
uint16_t len);
extern void uci_proc_raw_cmd_rsp(uint8_t* p_buf, uint16_t len);
+extern void uci_proc_data_control_ntf(uint8_t op_code, uint8_t* p_buf, uint16_t len);
+
+extern void uci_proc_app_data_management_ntf(uint8_t op_code, uint8_t* p_buf, uint16_t len);
extern void uci_proc_vendor_specific_ntf(uint8_t gid, uint8_t* p_buf, uint16_t len);
#endif /* UWB_UCI_MSGS_H */
diff --git a/src/uwb/include/uwb_api.h b/src/uwb/include/uwb_api.h
index 1378cab..e75e924 100755
--- a/src/uwb/include/uwb_api.h
+++ b/src/uwb/include/uwb_api.h
@@ -104,7 +104,7 @@ typedef uint8_t tUWB_STATUS;
// RFU size for tdoa Ranging
#define TDOA_RANGE_MEASR_RFU 12
-#define TWR_RANGE_MEASR_RFU 12
+#define TWR_RANGE_MEASR_RFU 11
#define CONFORMANCE_TEST_MAX_UCI_PKT_LENGTH 260
@@ -141,7 +141,14 @@ enum {
UWB_BLINK_DATA_TX_NTF_REVT, /* 31 Blink Data Tx ntf */
UWB_CONFORMANCE_TEST_DATA, /* 32 Conformance test data ntf */
UWB_SET_COUNTRY_CODE_REVT, /* 33 Set country code resp */
- UWB_VENDOR_SPECIFIC_UCI_NTF_EVT /* 34 Proprietary ntf */
+ UWB_VENDOR_SPECIFIC_UCI_NTF_EVT, /* 34 Proprietary ntf */
+ UWB_SEND_DATA_STATUS_EVT, /* 35 UWB data reception status by UWBS */
+ UWB_DATA_TRANSFER_STATUS_NTF_REVT, /* 36 UWB data transfer status over UWB */
+ UWB_DATA_RECV_REVT, /* 37 received data over UWB */
+ UWB_SESSION_CONFIGURE_DT_ANCHOR_RR_RDM_REVT, /* 38 DL TDoA Configure DT Anchor
+ RR RDM List Response */
+ UWB_SESSION_ACTIVE_ROUNDS_INDEX_UPDATE_REVT /* 39 DL-TDoA Update Ranging Index
+ status Response */
};
typedef uint16_t tUWB_RESPONSE_EVT;
@@ -261,32 +268,81 @@ typedef struct {
uint16_t aoa_dest_elevation;
uint8_t aoa_dest_elevation_FOM;
uint8_t slot_index;
+ uint8_t rssi;
uint8_t rfu[TWR_RANGE_MEASR_RFU];
} tUWB_TWR_RANGING_MEASR;
typedef struct {
uint8_t mac_addr[8];
+ uint8_t message_control;
uint8_t frame_type;
uint8_t nLos; /* non line of sight */
uint16_t aoa_azimuth;
uint8_t aoa_azimuth_FOM;
uint16_t aoa_elevation;
uint8_t aoa_elevation_FOM;
- uint64_t timeStamp; /* Time stamp */
- uint32_t blink_frame_number; /* blink frame number received from tag/master
- anchor */
- uint8_t rfu[TDOA_RANGE_MEASR_RFU];
- uint8_t device_info_size; /* Size of Device Specific Information */
- uint8_t* device_info; /* Device Specific Information */
- uint8_t blink_payload_size; /* Size of Blink Payload Data */
- uint8_t* blink_payload_data; /* Blink Payload Data */
+ uint32_t frame_number; /* Number received in the payload of the Blink UTM */
+ uint8_t rxTimeStamp[8]; /* Local RX timestamp of the received UWB RFRAME */
+ uint8_t ulTdoa_device_id[8]; /* Device ID of the sender of the received UTM */
+ uint8_t txTimeStamp[8]; /* TX timestamp of the UWB RFRAME */
} tUWB_TDoA_RANGING_MEASR;
+
+/* the data type associated with vendor notification */
+typedef struct {
+ uint16_t len;
+ uint8_t data[UCI_VENDOR_INFO_MAX_SIZE];
+}tUWB_VENDOR_SPECIFIC_NTF;
+
+typedef struct {
+ uint8_t mac_addr[8];
+ uint8_t status;
+ uint8_t message_type;
+ uint16_t message_control;
+ uint16_t block_index;
+ uint8_t round_index;
+ uint8_t nLos;
+ uint16_t aoa_azimuth;
+ uint8_t aoa_azimuth_FOM;
+ uint16_t aoa_elevation;
+ uint8_t aoa_elevation_FOM;
+ uint8_t rssi;
+ uint64_t txTimeStamp;
+ uint64_t rxTimeStamp;
+ uint16_t cfo_anchor;
+ uint16_t cfo;
+ uint32_t initiator_reply_time;
+ uint32_t responder_reply_time;
+ uint16_t initiator_responder_TOF;
+ uint8_t anchor_location[12];
+ uint8_t active_ranging_round[15];
+} tUWB_DLTDOA_RANGING_MEASR;
+
+typedef struct {
+ uint8_t mac_addr[8];
+ uint8_t status;
+ uint8_t nLos;
+ uint8_t frame_seq_num;
+ uint16_t block_index;
+ uint16_t aoa_azimuth;
+ uint8_t aoa_azimuth_FOM;
+ uint16_t aoa_elevation;
+ uint8_t aoa_elevation_FOM;
+} tUWB_OWR_WITH_AOA_RANGING_MEASR;
+
typedef union {
tUWB_TWR_RANGING_MEASR twr_range_measr[MAX_NUM_RESPONDERS];
tUWB_TDoA_RANGING_MEASR tdoa_range_measr[MAX_NUM_OF_TDOA_MEASURES];
+ tUWB_DLTDOA_RANGING_MEASR dltdoa_range_measr[MAX_NUM_OF_DLTDOA_MEASURES];
+ tUWB_OWR_WITH_AOA_RANGING_MEASR owr_with_aoa_range_measr;
} tUWB_RANGING_MEASR;
+/* the data type associated with vendor notification */
+typedef struct {
+ uint16_t len;
+ uint8_t data[UCI_VENDOR_INFO_MAX_SIZE];
+}tUWB_VENDOR_SPECIFIC_NTF;
+
/* the data type associated with UWB_RANGE_DATA_REVT */
typedef struct {
uint16_t range_data_len;
@@ -300,6 +356,7 @@ typedef struct {
uint8_t reserved[8];
uint8_t no_of_measurements;
tUWB_RANGING_MEASR ranging_measures;
+ tUWB_VENDOR_SPECIFIC_NTF vendor_specific_ntf;
} tUWB_RANGE_DATA_REVT;
/* the data type associated with UWB_CONFORMANCE_TEST_DATA */
@@ -343,6 +400,40 @@ typedef struct {
uint8_t repetition_count_status; /* repetition count status */
} tUWB_SEND_BLINK_DATA_NTF_REVT;
+/* the data type associated with UWB_DATA_TRANSFER_STATUS_NTF_REVT */
+typedef struct {
+ uint32_t session_id;
+ uint32_t sequence_num;
+ uint8_t status;
+}tUWB_DATA_TRANSFER_STATUS_NTF_REVT;
+
+/* the data type associated with UWB_DATA_RECV_REVT */
+typedef struct {
+ uint32_t session_id;
+ uint8_t status;
+ uint32_t sequence_num;
+ uint8_t address[EXTENDED_ADDRESS_LEN];
+ uint8_t source_end_point;
+ uint8_t dest_end_point;
+ uint16_t data_len;
+ uint8_t data[UCI_MAX_DATA_SIZE];
+}tUWB_RX_DATA_REVT;
+
+
+/* the data type associated with UWB_SESSION_CONFIGURE_DT_ANCHOR_RR_RDM_REVT */
+typedef struct {
+ uint8_t status;
+ uint16_t len;
+ uint8_t rng_round_indexs[255];
+}tUWB_CONFIGURE_DT_ANCHOR_RR_RDM_LIST_REVT;
+
+/* the data type associated with UWB_DATA_RECV_REVT */
+typedef struct {
+ uint8_t status;
+ uint16_t len;
+ uint8_t rng_round_index[255];
+}tUWB_UPDATE_RANGE_ROUND_INDEX_REVT;
+
typedef struct {
tUWB_STATUS status; /* The event status. */
} tUWB_SET_COUNTRY_CODE_REVT;
@@ -368,7 +459,11 @@ typedef union {
tUWB_SET_COUNTRY_CODE_REVT sSet_country_code_status;
tUWB_SEND_BLINK_DATA_NTF_REVT sSend_blink_data_ntf;
tUWB_CONFORMANCE_TEST_DATA sConformance_test_data;
- tUWB_VENDOR_SPECIFIC_REVT sVendor_specific_ntf;
+ tUWB_VENDOR_SPECIFIC_REVT vendor_specific_ntf;
+ tUWB_DATA_TRANSFER_STATUS_NTF_REVT sData_xfer_status;
+ tUWB_RX_DATA_REVT sRcvd_data;
+ tUWB_UPDATE_RANGE_ROUND_INDEX_REVT sRange_round_index;
+ tUWB_CONFIGURE_DT_ANCHOR_RR_RDM_LIST_REVT sConfigure_dt_anchor_rr_rdm_list;
} tUWB_RESPONSE;
/* Data types associated with all RF test Events */
@@ -794,6 +889,55 @@ extern tUWB_STATUS UWB_SendRawCommand(UWB_HDR* p_data, tUWB_RAW_CBACK* p_cback);
/*******************************************************************************
**
+** Function UWB_SendData
+**
+** Description This function is called to send the data packet over UWB.
+**
+** Parameters p_data - The data buffer
+**
+** Returns tUWB_STATUS
+**
+*******************************************************************************/
+tUWB_STATUS UWB_SendData(uint32_t session_id, uint8_t* p_addr,
+ uint8_t dest_end_point, uint8_t sequence_num,
+ uint16_t data_len, uint8_t* p_data);
+/*******************************************************************************
+**
+** Function UWB_ConfigureDTAnchorForRrRdmList
+**
+** Description This function is called to Configure DT anchor RR RDM List.
+**
+** Parameter session_id - Session id To which Rangng index need to update
+** rr_rdm_count - Number Of rr_rdm
+** length - length of data buffer
+** p_data - The data buffer
+**
+** Returns tUWB_STATUS
+**
+*******************************************************************************/
+extern tUWB_STATUS UWB_ConfigureDTAnchorForRrRdmList(uint32_t session_id, uint8_t rr_rdm_count,
+ uint8_t length, uint8_t* p_data);
+
+/*******************************************************************************
+**
+** Function UWB_UpdateRangingRoundIndex
+**
+** Description This function is called to Update Active Ranging Index.
+**
+** Parameter dlTdoaRole - 0x00(Anchor) or 0x01(Tag)
+** session_id - Session id To which Rangng index need to update
+** number_of_active_rngIndex - NUmber Of Ranging index to be updated
+** rng_round_index_len - Range Round Index Len
+** p_rng_round_index - pointer to Ranging Index buffer
+**
+** Returns tUWB_STATUS
+**
+*******************************************************************************/
+tUWB_STATUS UWB_UpdateRangingRoundIndex(uint8_t dlTdoaRole, uint32_t session_id, uint8_t number_of_rng_index,
+ uint8_t rng_round_index_len, uint8_t* p_rng_round_index);
+
+/*******************************************************************************
+**
** Function UWB_EnableConformanceTest
**
** Description This function is called to set MCTT/PCTT mode.
@@ -808,6 +952,32 @@ void UWB_EnableConformanceTest(uint8_t enable);
/*******************************************************************************
**
+** Function UWB_SetDataXferCapMaxMsgSize
+**
+** Description This function is called to set max msg size supported for data Tranfer
+**
+** Parameters maxMsgSize - max msg size value
+**
+** Returns None
+**
+*******************************************************************************/
+void UWB_SetDataXferCapMaxMsgSize(uint16_t maxMsgSize);
+
+/*******************************************************************************
+**
+** Function UWB_SetDataXferCapMaxDataPktPayloadSize
+**
+** Description This function is called to set max data packet size at one time supported for data Tranfer
+**
+** Parameters maxDataPktPayloadSize - max data packet size value
+**
+** Returns None
+**
+*******************************************************************************/
+void UWB_SetDataXferCapMaxDataPktPayloadSize(uint16_t maxDataPktPayloadSize);
+
+/*******************************************************************************
+**
** Function UWB_GetStatusName
**
** Description This function returns the status name.
diff --git a/src/uwb/include/uwb_int.h b/src/uwb/include/uwb_int.h
index 16d6af7..da2952e 100755
--- a/src/uwb/include/uwb_int.h
+++ b/src/uwb/include/uwb_int.h
@@ -34,6 +34,7 @@
/* UWB Timer events */
#define UWB_TTYPE_UCI_WAIT_RSP 0x00
#define UWB_WAIT_RSP_RAW_CMD 0x01
+#define UWB_TTYPE_UCI_WAIT_DATA_NTF 0x02
#define UWB_SAVED_HDR_SIZE 2
@@ -97,17 +98,48 @@ typedef struct {
uint8_t device_state;
uint16_t cmd_retry_count;
+ uint8_t invalid_len_cmd_retry_cnt;
UWB_HDR* pLast_cmd_buf;
+ UWB_HDR* pLast_data_buf;
+ uint8_t data_pkt_retry_count;
+ bool is_credit_ntf_pending;
+
bool IsConformaceTestEnabled; /* MCTT mode indicator */
+
+ uint8_t data_credits; /* number of buffer credits */
+ TIMER_LIST_ENT
+ uci_wait_credit_ntf_timer; /* Timer for waiting for uci credit ntf */
+ uint16_t uci_credit_ntf_timeout; /* UCI credit timeout (in ms) */
+ bool is_first_frgmnt_done; /*flag indicates recieved pbf=1 uci pkt before*/
} tUWB_CB;
+typedef struct {
+ DATA_BUFFER_Q tx_data_pkt[5];
+ uint8_t no_of_sessions;
+ uint32_t curr_session_id;
+ uint8_t curr_session_idx;
+ uint16_t max_data_pkt_payload_size;
+ uint16_t max_msg_size;
+}tDATA_TX_CB;
+
+struct chained_uci_packet {
+ uint8_t buffer[UCI_MAX_FRAGMENT_BUFF_SIZE];
+ uint8_t oid;
+ uint8_t gid;
+ uint16_t offset;
+};
+
+typedef struct chained_uci_packet chained_uci_packet;
+extern chained_uci_packet chained_packet;
+
/*****************************************************************************
** EXTERNAL FUNCTION DECLARATIONS
*****************************************************************************/
/* Global UWB data */
extern tUWB_CB uwb_cb;
+extern tDATA_TX_CB data_tx_cb;
/****************************************************************************
** Internal uwb functions
@@ -160,6 +192,15 @@ extern void uwb_ucif_proc_test_set_config_status(uint8_t* p_buf, uint16_t len);
extern void uwb_ucif_proc_rf_test_data(tUWB_RESPONSE_EVT event, uint8_t* p_buf,
uint16_t len);
+/* APIs for handling data transfer */
+extern void uwb_ucif_send_data_frame(uint32_t session_id, uint8_t* p_addr,
+ uint16_t data_len, uint8_t* p_data);
+extern void uwb_ucif_proc_data_credit_ntf(uint8_t* p_buf, uint16_t len);
+extern void uwb_ucif_proc_data_transfer_status_ntf(uint8_t* p_buf, uint16_t len);
+extern void uci_ucif_proc_data_packet(uint8_t* p_buf, uint16_t len);
+extern void uwb_ucif_credit_ntf_timeout(void);
+extern void uwb_ucif_send_data_frame(UWB_HDR* p_data);
+
/* From uwb_task.c */
extern uint32_t uwb_task(uint32_t param);
void uwb_task_shutdown_uwbc(void);
@@ -168,6 +209,7 @@ void uwb_task_shutdown_uwbc(void);
void uwb_enabled(tUWB_STATUS uwb_status, UWB_HDR* p_init_rsp_msg);
void uwb_set_state(tUWB_STATE uwb_state);
void uwb_main_flush_cmd_queue(void);
+void uwb_main_flush_data_queue(void);
void uwb_main_handle_hal_evt(tUWB_HAL_EVT_MSG* p_msg);
void uwb_gen_cleanup(void);
diff --git a/src/uwb/uci/uci_hmsgs.cc b/src/uwb/uci/uci_hmsgs.cc
index 247c79d..8e57954 100755
--- a/src/uwb/uci/uci_hmsgs.cc
+++ b/src/uwb/uci/uci_hmsgs.cc
@@ -204,6 +204,11 @@ uint8_t uci_snd_session_init_cmd(uint32_t session_id, uint8_t sessionType) {
UINT32_TO_STREAM(pp, session_id);
UINT8_TO_STREAM(pp, sessionType);
+ data_tx_cb.tx_data_pkt[data_tx_cb.no_of_sessions].session_id = session_id;
+ data_tx_cb.tx_data_pkt[data_tx_cb.no_of_sessions].credit_available = 1;
+ phUwb_GKI_init_q(&data_tx_cb.tx_data_pkt[data_tx_cb.no_of_sessions].tx_data_pkt_q);
+ data_tx_cb.no_of_sessions++;
+
uwb_ucif_send_cmd(p);
return (UCI_STATUS_OK);
}
@@ -233,6 +238,14 @@ uint8_t uci_snd_session_deinit_cmd(uint32_t session_id) {
UINT8_TO_STREAM(pp, UCI_MSG_SESSION_DEINIT_CMD_SIZE);
UINT32_TO_STREAM(pp, session_id);
+ for(int i=0; i < data_tx_cb.no_of_sessions; i++) {
+ if(data_tx_cb.tx_data_pkt[i].session_id == session_id)
+ data_tx_cb.tx_data_pkt[i].session_id = 0;
+ }
+ if (data_tx_cb.no_of_sessions > 0) {
+ data_tx_cb.no_of_sessions--;
+ }
+
uwb_ucif_send_cmd(p);
return (UCI_STATUS_OK);
}
@@ -526,7 +539,7 @@ uint8_t uci_snd_multicast_list_update_cmd(uint32_t session_id, uint8_t action,
UINT8_TO_STREAM(pp, action);
UINT8_TO_STREAM(pp, noOfControlees);
for (uint8_t i = 0; i < noOfControlees; i++) {
- UINT16_TO_BE_STREAM(pp, shortAddressList[i]);
+ UINT16_TO_STREAM(pp, shortAddressList[i]);
UINT32_TO_STREAM(pp, subSessionIdList[i]);
}
@@ -536,6 +549,41 @@ uint8_t uci_snd_multicast_list_update_cmd(uint32_t session_id, uint8_t action,
/*******************************************************************************
**
+** Function uci_snd_configure_dt_anchor_for_rr_rdm_list_cmd
+**
+** Description compose and send SESSION_CONFIGURE_DT_ANCHOR_RR_RDM_LIST_CMD command
+**
+** Returns status
+**
+*******************************************************************************/
+uint8_t uci_snd_configure_dt_anchor_for_rr_rdm_list_cmd(uint32_t session_id, uint8_t rr_rdm_count, uint8_t length, uint8_t* data) {
+ UWB_HDR* p;
+ uint8_t* pp;
+ uint16_t total_size = 0;
+
+ total_size = sizeof(session_id) + sizeof(rr_rdm_count) + length;
+ if ((p = UCI_GET_CMD_BUF(total_size)) == NULL) return (UCI_STATUS_FAILED);
+ p->event = BT_EVT_TO_UWB_UCI;
+ p->len = (uint16_t) (UCI_MSG_HDR_SIZE + total_size);
+
+ p->offset = UCI_MSG_OFFSET_SIZE;
+ p->layer_specific = 0;
+ pp = (uint8_t*)(p + 1) + p->offset;
+
+ UCI_MSG_BLD_HDR0(pp, UCI_MT_CMD, UCI_GID_SESSION_MANAGE);
+ UCI_MSG_BLD_HDR1(pp, UCI_MSG_SESSION_CONFIGURE_DT_ANCHOR_RR_RDM_LIST);
+ UINT8_TO_STREAM(pp, 0x00);
+ UINT8_TO_STREAM(pp, total_size);
+ UINT32_TO_STREAM(pp, session_id);
+ UINT8_TO_STREAM(pp, rr_rdm_count);
+ ARRAY_TO_STREAM(pp, data, length);
+
+ uwb_ucif_send_cmd(p);
+ return (UCI_STATUS_OK);
+}
+
+/*******************************************************************************
+**
** Function uci_snd_set_country_code_cmd
**
** Description compose and send SET_COUNTRY_CODE_CMD command
@@ -558,7 +606,7 @@ uint8_t uci_snd_set_country_code_cmd(uint8_t *country_code) {
UCI_MSG_BLD_HDR1(pp, UCI_MSG_ANDROID_SET_COUNTRY_CODE);
UINT8_TO_STREAM(pp, 0x00);
UINT8_TO_STREAM(pp, UCI_MSG_ANDROID_SET_COUNTRY_CODE_CMD_SIZE);
- ARRAY8_TO_STREAM(pp, country_code);
+ ARRAY8_TO_STREAM(pp, country_code, UCI_MSG_ANDROID_SET_COUNTRY_CODE_CMD_SIZE);
uwb_ucif_send_cmd(p);
return (UCI_STATUS_OK);
@@ -850,3 +898,135 @@ uint8_t uci_snd_test_stop_session_cmd(void) {
uwb_ucif_send_cmd(p);
return (UCI_STATUS_OK);
}
+
+/*******************************************************************************
+**
+** Function uci_send_data_frame
+**
+** Description compose and send data packets
+**
+** Returns status
+**
+*******************************************************************************/
+uint8_t uci_send_data_frame(uint32_t session_id, uint8_t* p_addr, uint8_t dest_end_point, uint8_t sequence_num,
+ uint16_t data_len, uint8_t* p_data) {
+ UCI_TRACE_I("uci_send_data_frame()");
+ UWB_HDR* p;
+ uint8_t* pp;
+ uint16_t uci_pkt_len;
+ uint8_t pbf = 1;
+ tUWB_RESPONSE evt_data;
+ uint16_t max_supported_uci_payload;
+ uint16_t starIndex = 0;
+ bool isFirstSegment = true;
+
+ int16_t total_size = sizeof(session_id) + EXTENDED_ADDRESS_LEN + data_len +
+ sizeof(dest_end_point) + sizeof(uint8_t) +
+ sizeof(data_len);
+ data_tx_cb.curr_session_id = session_id;
+
+ for (int i = 0; i < data_tx_cb.no_of_sessions; i++) {
+ if (data_tx_cb.curr_session_id == data_tx_cb.tx_data_pkt[i].session_id) {
+ data_tx_cb.curr_session_idx = i;
+ }
+ }
+
+
+ if((p_data == nullptr) || (p_addr == nullptr)){
+ evt_data.status = UCI_STATUS_FAILED;
+ (*uwb_cb.p_resp_cback)(UWB_SEND_DATA_STATUS_EVT, &evt_data);
+ return (UCI_STATUS_FAILED);
+ }
+
+ max_supported_uci_payload = data_tx_cb.max_data_pkt_payload_size;
+ while (data_len > 0) {
+ if (total_size <= max_supported_uci_payload) {
+ pbf = 0; /* last fragment */
+ uci_pkt_len = total_size;
+ } else { /* Handling PBF as per generic specification*/
+ pbf = 1;
+ uci_pkt_len = max_supported_uci_payload;
+ }
+ if ((p = UCI_GET_CMD_BUF(uci_pkt_len)) == NULL) {
+ evt_data.status = UCI_STATUS_FAILED;
+ (*uwb_cb.p_resp_cback)(UWB_SEND_DATA_STATUS_EVT, &evt_data);
+ }
+
+ p->event = BT_EVT_TO_UWB_UCI;
+ p->len = uci_pkt_len + UCI_MSG_HDR_SIZE;
+ pp = (uint8_t*)(p + 1) + p->offset;
+
+ UCI_DATA_PBLD_HDR(pp, pbf, uci_pkt_len);
+
+ if (isFirstSegment) {
+ UINT32_TO_STREAM(pp, session_id);
+ ARRAY_TO_STREAM(pp, p_addr, EXTENDED_ADDRESS_LEN);
+ UINT8_TO_STREAM(pp, dest_end_point);
+ UINT8_TO_STREAM(pp, sequence_num);
+ uci_pkt_len -= (sizeof(session_id) + EXTENDED_ADDRESS_LEN + sizeof(dest_end_point) +
+ sizeof(data_len) + sizeof(uint8_t));
+ }
+ if(!isFirstSegment){
+ uci_pkt_len -= sizeof(data_len);
+ }
+ UINT16_TO_STREAM(pp, uci_pkt_len);
+
+ ARRAY_TO_STREAM(pp, (p_data + starIndex), uci_pkt_len);
+ starIndex += uci_pkt_len;
+ data_len -= uci_pkt_len;
+ total_size = sizeof(data_len) + data_len;
+
+ uwb_ucif_send_data_frame(p);
+ isFirstSegment = false;
+ }
+ evt_data.status = UCI_STATUS_OK;
+ (*uwb_cb.p_resp_cback)(UWB_SEND_DATA_STATUS_EVT, &evt_data);
+ return (UCI_STATUS_OK);
+}
+
+/*******************************************************************************
+**
+** Function uci_send_range_round_index_update_cmd
+**
+** Description compose and send range round index update command
+**
+** Returns status
+**
+*******************************************************************************/
+uint8_t uci_send_range_round_index_update_cmd(uint8_t dlTdoaRole, uint32_t session_id, uint8_t number_of_active_rngIndex,
+ uint8_t rng_round_index_len, uint8_t* p_rng_round_index) {
+ UWB_HDR* p;
+ uint8_t* pp;
+ uint16_t total_size;
+ uint8_t oid;
+
+ total_size = sizeof(session_id) + sizeof(number_of_active_rngIndex) + rng_round_index_len;
+
+ if ((p = UCI_GET_CMD_BUF(total_size)) == NULL) return (UCI_STATUS_FAILED);
+
+ p->event = BT_EVT_TO_UWB_UCI;
+
+ p->len = (uint16_t) (UCI_MSG_HDR_SIZE + total_size);
+
+ p->offset = UCI_MSG_OFFSET_SIZE;
+ p->layer_specific = 0;
+ pp = (uint8_t*)(p + 1) + p->offset;
+
+ if(dlTdoaRole == 0x00) {
+ oid = UCI_MSG_SESSION_UPDATE_ACTIVE_ROUNDS_OF_DT_ANCHOR;
+ } else {
+ oid = UCI_MSG_SESSION_UPDATE_ACTIVE_ROUNDS_OF_DT_TAG;
+ }
+
+ UCI_MSG_BLD_HDR0(pp, UCI_MT_CMD, UCI_GID_SESSION_MANAGE);
+ UCI_MSG_BLD_HDR1(pp, oid);
+ UINT8_TO_STREAM(pp, 0x00);
+ UINT8_TO_STREAM(pp, total_size);
+
+ UINT32_TO_STREAM(pp, session_id);
+ UINT8_TO_STREAM(pp, number_of_active_rngIndex);
+ ARRAY_TO_STREAM(pp, p_rng_round_index, rng_round_index_len);
+
+ uwb_ucif_send_cmd(p);
+ return (UCI_STATUS_OK);
+}
diff --git a/src/uwb/uci/uci_hrcv.cc b/src/uwb/uci/uci_hrcv.cc
index e8ff495..69c5591 100755
--- a/src/uwb/uci/uci_hrcv.cc
+++ b/src/uwb/uci/uci_hrcv.cc
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
- * Copyright 2021 NXP.
+ * Copyright 2021-2022 NXP.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* You may not use this file except in compliance with the License.
@@ -131,6 +131,14 @@ void uci_proc_session_management_rsp(uint8_t op_code, uint8_t* p_buf,
uwb_ucif_session_management_status(UWB_SESSION_UPDATE_MULTICAST_LIST_REVT,
p_buf, len);
break;
+ case UCI_MSG_SESSION_CONFIGURE_DT_ANCHOR_RR_RDM_LIST:
+ uwb_ucif_session_management_status(UWB_SESSION_CONFIGURE_DT_ANCHOR_RR_RDM_REVT, p_buf, len);
+ break;
+ case UCI_MSG_SESSION_UPDATE_ACTIVE_ROUNDS_OF_DT_ANCHOR:
+ case UCI_MSG_SESSION_UPDATE_ACTIVE_ROUNDS_OF_DT_TAG:
+ uwb_ucif_session_management_status(UWB_SESSION_ACTIVE_ROUNDS_INDEX_UPDATE_REVT, p_buf,
+ len);
+ break;
default:
UCI_TRACE_E("%s: unknown opcode:0x%x", __func__, op_code);
break;
@@ -194,6 +202,12 @@ void uci_proc_session_management_ntf(uint8_t op_code, uint8_t* p_buf,
case UCI_MSG_SESSION_UPDATE_CONTROLLER_MULTICAST_LIST:
uwb_ucif_proc_multicast_list_update_ntf(p_buf, len);
break;
+ case UCI_MSG_DATA_CREDIT_NTF:
+ uwb_ucif_proc_data_credit_ntf(p_buf, len);
+ break;
+ case UCI_MSG_DATA_TRANSFER_STATUS_NTF:
+ uwb_ucif_proc_data_transfer_status_ntf(p_buf, len);
+ break;
default:
UCI_TRACE_E("%s: unknown opcode:0x%x", __func__, op_code);
break;
@@ -293,9 +307,9 @@ void uci_proc_vendor_specific_ntf(uint8_t gid, uint8_t* p_buf, uint16_t len) {
if (uwb_cb.p_resp_cback == NULL) {
UCI_TRACE_E("ext response callback is null");
} else {
- evt_data.sVendor_specific_ntf.len = len;
- if (evt_data.sVendor_specific_ntf.len > 0) {
- STREAM_TO_ARRAY(evt_data.sVendor_specific_ntf.data, p_buf,
+ evt_data.vendor_specific_ntf.len = len;
+ if (evt_data.vendor_specific_ntf.len > 0) {
+ STREAM_TO_ARRAY(evt_data.vendor_specific_ntf.data, p_buf,
len);
}
(*uwb_cb.p_resp_cback)(UWB_VENDOR_SPECIFIC_UCI_NTF_EVT, &evt_data);
diff --git a/src/uwb/uwb/uwb_main.cc b/src/uwb/uwb/uwb_main.cc
index 51b9471..b79de22 100755
--- a/src/uwb/uwb/uwb_main.cc
+++ b/src/uwb/uwb/uwb_main.cc
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
- * Copyright 2021 NXP.
+ * Copyright 2021-2022 NXP.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* You may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@
** Declarations
****************************************************************************/
tUWB_CB uwb_cb;
+tDATA_TX_CB data_tx_cb;
/*******************************************************************************
**
@@ -159,6 +160,7 @@ void uwb_set_state(tUWB_STATE uwb_state) {
void uwb_gen_cleanup(void) {
/* clear any pending CMD/RSP */
uwb_main_flush_cmd_queue();
+ uwb_main_flush_data_queue();
}
/*******************************************************************************
@@ -192,6 +194,10 @@ void uwb_main_handle_hal_evt(tUWB_HAL_EVT_MSG* p_msg) {
}
break;
+ case HAL_UWB_INIT_CPLT_EVT: /* only for failure case */
+ uwb_set_state(UWB_STATE_NONE);
+ break;
+
case HAL_UWB_ERROR_EVT:
switch (p_msg->status) {
case HAL_UWB_STATUS_ERR_TRANSPORT:
@@ -247,6 +253,34 @@ void uwb_main_flush_cmd_queue(void) {
/*******************************************************************************
**
+** Function uwb_main_flush_data_queue
+**
+** Description This function is called when setting power off sleep state.
+**
+** Returns void
+**
+*******************************************************************************/
+void uwb_main_flush_data_queue(void) {
+ UWB_HDR* p_msg;
+
+ UCI_TRACE_I(__func__);
+
+ /* Stop command-pending timer */
+ uwb_stop_quick_timer(&uwb_cb.uci_wait_credit_ntf_timer);
+ uwb_cb.is_credit_ntf_pending = false;
+ uwb_cb.data_pkt_retry_count = 0;
+
+ /* dequeue and free buffer */
+ for (int i = 0; i < data_tx_cb.no_of_sessions; i++) {
+ while ((p_msg = (UWB_HDR*)phUwb_GKI_dequeue(&data_tx_cb.tx_data_pkt[i].tx_data_pkt_q)) !=
+ NULL) {
+ phUwb_GKI_freebuf(p_msg);
+ }
+ }
+}
+
+/*******************************************************************************
+**
** Function uwb_main_post_hal_evt
**
** Description This function posts HAL event to UWB_TASK
@@ -300,6 +334,10 @@ static void uwb_main_hal_cback(uint8_t event, tUWB_STATUS status) {
}
break;
+ case HAL_UWB_INIT_CPLT_EVT:
+ UCI_TRACE_D("uwb_main_hal_cback HAL Init complete %x", event);
+ break;
+
case HAL_UWB_CLOSE_CPLT_EVT:
case HAL_UWB_ERROR_EVT:
uwb_main_post_hal_evt(event, status);
@@ -435,9 +473,20 @@ void UWB_Init(tHAL_UWB_CONTEXT* p_hal_entry_cntxt) {
((UWB_CMD_CMPL_TIMEOUT * QUICK_TIMER_TICKS_PER_SEC) / 1000);
uwb_cb.pLast_cmd_buf = NULL;
uwb_cb.is_resp_pending = false;
+ uwb_cb.is_credit_ntf_pending = false;
+ data_tx_cb.max_data_pkt_payload_size = 255;
+ data_tx_cb.max_msg_size = 255;
+ data_tx_cb.no_of_sessions = 0;
uwb_cb.cmd_retry_count = 0;
uwb_cb.is_recovery_in_progress = false;
uwb_cb.IsConformaceTestEnabled = false;
+ uwb_cb.uci_credit_ntf_timeout = ((UWB_CMD_CMPL_TIMEOUT * QUICK_TIMER_TICKS_PER_SEC) / 1000); // currently used same timeout value as cmd timeout
+ uwb_cb.data_credits = 1;
+ /* initialize the segment handling context */
+ chained_packet.offset = 0;
+ uwb_cb.is_first_frgmnt_done = false;
+ chained_packet.oid = 0xFF;
+ chained_packet.gid = 0xFF;
}
/*******************************************************************************
@@ -954,6 +1003,61 @@ tUWB_STATUS UWB_SendRawCommand(UWB_HDR* p_data, tUWB_RAW_CBACK* p_cback) {
/*******************************************************************************
**
+** Function UWB_SendData
+**
+** Description This function is called to send the data packet over UWB.
+**
+** Parameters p_data - The data buffer
+**
+** Returns tUWB_STATUS
+**
+*******************************************************************************/
+tUWB_STATUS UWB_SendData(uint32_t session_id, uint8_t* p_addr,
+ uint8_t dest_end_point, uint8_t sequence_num,
+ uint16_t data_len, uint8_t* p_data) {
+ return uci_send_data_frame(session_id, p_addr, dest_end_point, sequence_num, data_len, p_data);
+}
+
+/*******************************************************************************
+**
+** Function UWB_UpdateRangingRoundIndex
+**
+** Description This function is called to Update Active Ranging Index.
+**
+** Parameter dlTdoaRole - 0x00(Anchor) or 0x01(Tag)
+** session_id - Session id To which Rangng index need to update
+** number_of_active_rngIndex - NUmber Of Ranging index to be updated
+** rng_round_index_len - Range Round Index Len
+** p_rng_round_index - pointer to Ranging Index buffer
+**
+** Returns tUWB_STATUS
+**
+*******************************************************************************/
+tUWB_STATUS UWB_UpdateRangingRoundIndex(uint8_t dlTdoaRole, uint32_t session_id, uint8_t number_of_rng_index,
+ uint8_t rng_round_index_len, uint8_t* p_rng_round_index) {
+ return uci_send_range_round_index_update_cmd(dlTdoaRole, session_id, number_of_rng_index, rng_round_index_len, p_rng_round_index);
+}
+
+/*******************************************************************************
+**
+** Function UWB_ConfigureDTAnchorForRrRdmList
+**
+** Description This function is called to Configure DT anchor RR RDM List.
+**
+** Parameter session_id - Session id To which Rangng index need to update
+** rr_rdm_count - Number Of rr_rdm
+** length - length of data buffer
+** p_data - The data buffer
+**
+** Returns tUWB_STATUS
+**
+*******************************************************************************/
+tUWB_STATUS UWB_ConfigureDTAnchorForRrRdmList(uint32_t session_id, uint8_t rr_rdm_count, uint8_t length, uint8_t* p_data) {
+ return uci_snd_configure_dt_anchor_for_rr_rdm_list_cmd(session_id, rr_rdm_count, length, p_data);
+}
+
+/*******************************************************************************
+**
** Function UWB_EnableConformanceTest
**
** Description This function is called to set MCTT/PCTT mode.
@@ -970,6 +1074,41 @@ void UWB_EnableConformanceTest(uint8_t enable) {
/*******************************************************************************
**
+** Function UWB_SetDataXferCapMaxMsgSize
+**
+** Description This function is called to set max msg size supported for data Tranfer
+**
+** Parameters maxMsgSize - max msg size value
+**
+** Returns None
+**
+*******************************************************************************/
+void UWB_SetDataXferCapMaxMsgSize(uint16_t maxMsgSize){
+ data_tx_cb.max_msg_size = maxMsgSize;
+ UCI_TRACE_D(
+ "UWB_SetDataXferCapMaxMsgSize %d ",data_tx_cb.max_msg_size);
+}
+
+/*******************************************************************************
+**
+** Function UWB_SetDataXferCapMaxDataPktPayloadSize
+**
+** Description This function is called to set max data packet size at one time supported for data Tranfer
+**
+** Parameters maxDataPktPayloadSize - max data packet size value
+**
+** Returns None
+**
+*******************************************************************************/
+void UWB_SetDataXferCapMaxDataPktPayloadSize(uint16_t maxDataPktPayloadSize)
+{
+ data_tx_cb.max_data_pkt_payload_size = maxDataPktPayloadSize;
+ UCI_TRACE_D(
+ "UWB_SetDataXferCapMaxDataPktPayloadSize %d ",data_tx_cb.max_data_pkt_payload_size);
+}
+
+/*******************************************************************************
+**
** Function UWB_GetStatusName
**
** Description This function returns the status name.
diff --git a/src/uwb/uwb/uwb_ucif.cc b/src/uwb/uwb/uwb_ucif.cc
index 327aa19..04cbd77 100755
--- a/src/uwb/uwb/uwb_ucif.cc
+++ b/src/uwb/uwb/uwb_ucif.cc
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
- * Copyright 2021 NXP.
+ * Copyright 2021-2022 NXP.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* You may not use this file except in compliance with the License.
@@ -34,6 +34,22 @@
#include "uwb_target.h"
#define NORMAL_MODE_LENGTH_OFFSET 0x03
+#define DATA_PACKET_LEN_SHIFT 0x08
+#define TDOA_TX_TIMESTAMP_OFFSET 0x00FF
+#define TDOA_TX_TIMESTAMP_OFFSET_MASK 0x06
+#define TDOA_RX_TIMESTAMP_OFFSET 0x00FF
+#define TDOA_RX_TIMESTAMP_OFFSET_MASK 0x18
+#define ULTDOA_RX_TIMESTAMP_OFFSET 0xF0
+#define ULTDOA_RX_TIMESTAMP_OFFSET_MASK 0x30
+#define ULTDOA_DEVICE_ID_OFFSET 0x0F
+#define ULTDOA_DEVICE_ID_OFFSET_MASK 0X03
+#define ULTDOA_TX_TIMESTAMP_OFFSET 0x0F
+#define ULTDOA_TX_TIMESTAMP_OFFSET_MASK 0x0C
+#define TDOA_ANCHOR_LOC_OFFSET 0x00FF
+#define TDOA_ANCHOR_LOC_OFFSET_MASK 0x60
+#define TDOA_ACTIVE_RR_OFFSET 0x0FF0
+#define TDOA_ACTIVE_RR_OFFSET_MASK 0x0780
+
#define MAC_SHORT_ADD_LEN 2
#define MAC_EXT_ADD_LEN 8
#define PDOA_LEN 4
@@ -41,29 +57,48 @@
#define AOA_DEST_LEN 4
#define CONFIG_TLV_OFFSET 2
#define TWO_WAY_MEASUREMENT_LENGTH 31
+#define ULTDOA_MEASUREMENT_LENGTH 45
#define ONE_WAY_MEASUREMENT_LENGTH 36
#define RANGING_DATA_LENGTH 25
#define VENDOR_SPEC_INFO_LEN 2
+#define OWR_WITH_AOA_MEASUREMENT_LENGTH 11
+#define TDOA_TIMESTAMP_LEN_40BITS 5
+#define TDOA_TIMESTAMP_LEN_64BITS 8
+#define TDOA_ANCHOR_LOC_LEN_10BYTES 10
+#define TDOA_ANCHOR_LOC_LEN_12BYTES 12
+#define TDOA_TX_TIMESTAMP_40BITS 0
+#define TDOA_TX_TIMESTAMP_64BITS 2
+#define TDOA_RX_TIMESTAMP_40BITS 0
+#define TDOA_RX_TIMESTAMP_64BITS 8
+#define ULTDOA_TIMESTAMP_LEN 0
+#define ULTDOA_TIMESTAMP_LEN_40BITS 5
+#define ULTDOA_TIMESTAMP_LEN_64BITS 8
+#define ULTDOA_DEVICE_ID_LEN 0
+#define ULTDOA_DEVICE_ID_LEN_16BITS 2
+#define ULTDOA_DEVICE_ID_LEN_32BITS 4
+#define ULTDOA_DEVICE_ID_LEN_64BITS 8
+#define ULTDOA_RX_TIMESTAMP_40BITS 0
+#define ULTDOA_RX_TIMESTAMP_64BITS 20
+#define ULTDOA_DEVICE_ID_PRESCENCE 0
+#define ULTDOA_DEVICE_ID_16BITS 1
+#define ULTDOA_DEVICE_ID_32BITS 2
+#define ULTDOA_DEVICE_ID_64BITS 3
+#define ULTDOA_TX_TIMESTAMP_PRESENCE 0
+#define ULTDOA_TX_TIMESTAMP_40BITS 8
+#define ULTDOA_TX_TIMESTAMP_64BITS 4
+#define TDOA_ANCHOR_LOC_NOT_INCLUDED 0
+#define TDOA_ANCHOR_LOC_NOT_INCLUDED 0
+#define TDOA_ANCHOR_LOC_IN_RELATIVE_SYSTEM 0x40
+#define TDOA_ANCHOR_LOC_IN_WGS84_SYSTEM 0x20
+#define TDOA_ACTIVE_RR_INDEX_POSITION 7
uint8_t last_cmd_buff[UCI_MAX_PAYLOAD_SIZE];
uint8_t last_data_buff[4096];
-static uint8_t device_info_buffer[MAX_NUM_OF_TDOA_MEASURES]
- [UCI_MAX_PAYLOAD_SIZE];
-static uint8_t blink_payload_buffer[MAX_NUM_OF_TDOA_MEASURES]
- [UCI_MAX_PAYLOAD_SIZE];
static uint8_t range_data_ntf_buffer[2048];
static uint8_t range_data_ntf_len =0;
-struct chained_uci_packet {
- uint8_t buffer[4192];
- uint8_t oid;
- uint8_t gid;
- uint16_t offset;
- uint8_t is_first_frgmnt_done;
-};
-
-typedef struct chained_uci_packet chained_uci_packet;
+chained_uci_packet chained_packet;
/*******************************************************************************
**
@@ -113,7 +148,6 @@ void uwb_ucif_cmd_timeout(void) {
uwb_cb.cmd_retry_count++;
} else {
uwb_ucif_event_status(UWB_UWBS_RESP_TIMEOUT_REVT, UWB_STATUS_FAILED);
- uwb_ucif_uwb_recovery();
}
}
@@ -141,6 +175,28 @@ void uwb_ucif_retransmit_cmd(UWB_HDR* p_buf) {
/*******************************************************************************
**
+ ** Function uwb_ucif_retransmit_data
+ **
+ ** Description Retransmission of last data packet
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void uwb_ucif_retransmit_data(UWB_HDR* p_buf) {
+ UCI_TRACE_I("uwb_ucif_retransmit_data");
+ if (p_buf == NULL) {
+ UCI_TRACE_E("uwb_ucif_retransmit_data: p_data is NULL");
+ return;
+ }
+ HAL_RE_WRITE(p_buf);
+
+ /* start the credit timeout timer */
+ uwb_start_quick_timer(&uwb_cb.uci_wait_credit_ntf_timer,
+ (uint16_t)(UWB_TTYPE_UCI_WAIT_DATA_NTF),uwb_cb.uci_credit_ntf_timeout);
+}
+
+/*******************************************************************************
+ **
** Function uwb_ucif_check_cmd_queue
**
** Description Send UCI command to the transport
@@ -199,7 +255,7 @@ void uwb_ucif_check_cmd_queue(UWB_HDR* p_buf) {
uwb_cb.rawCmdCbflag = true;
}
- /* Indicate command is pending */
+ /* Indicate command is pending */
uwb_cb.uci_cmd_window--;
uwb_cb.is_resp_pending = true;
uwb_cb.cmd_retry_count = 0;
@@ -241,6 +297,287 @@ void uwb_ucif_send_cmd(UWB_HDR* p_buf) {
/*******************************************************************************
**
+ ** Function uwb_ucif_credit_ntf_timeout
+ **
+ ** Description Handle a credit ntf timeout
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void uwb_ucif_credit_ntf_timeout(void){
+ UCI_TRACE_I("uwb_ucif_credit_ntf_timeout");
+/* if enabling UWB, notify upper layer of failure */
+ if (uwb_cb.is_credit_ntf_pending && (uwb_cb.data_pkt_retry_count < UCI_CMD_MAX_RETRY_COUNT)) {
+ uwb_stop_quick_timer(&uwb_cb.uci_wait_credit_ntf_timer); /*stop the pending timer */
+ uwb_ucif_retransmit_data(uwb_cb.pLast_data_buf);
+ uwb_cb.data_pkt_retry_count++;
+ } else {
+ uwb_cb.is_credit_ntf_pending = false;
+ uwb_cb.data_pkt_retry_count = 0;
+ uwb_ucif_event_status(UWB_UWBS_RESP_TIMEOUT_REVT, UWB_STATUS_FAILED);
+ uwb_ucif_uwb_recovery();
+ }
+}
+
+/*******************************************************************************
+**
+** Function uwb_ucif_send_data_frame
+**
+** Description This function is called to send UCI data packet to UWB subsystem as credits are available
+**
+** Returns void
+**
+*******************************************************************************/
+
+void uwb_ucif_send_data_frame(UWB_HDR* p_data){
+ UCI_TRACE_I("uwb_ucif_send_data_frame()");
+ uint8_t* ps;
+ uint8_t* pTemp;
+
+ if (uwb_cb.uwb_state == UWB_STATE_W4_HAL_CLOSE ||
+ uwb_cb.uwb_state == UWB_STATE_NONE) {
+ UCI_TRACE_E("%s: HAL is not initialized", __func__);
+ return;
+ }
+
+ /* If no credit available */
+ /* then enqueue this command */
+ if (p_data) {
+ if ((data_tx_cb.tx_data_pkt[data_tx_cb.curr_session_idx].credit_available ==
+ 0) ||
+ (data_tx_cb.tx_data_pkt[data_tx_cb.curr_session_idx]
+ .tx_data_pkt_q.count) ||
+ (uwb_cb.uci_cmd_window == 0)) {
+ UCI_TRACE_D(
+ "Enqueuing p_Data");
+ phUwb_GKI_enqueue(
+ &data_tx_cb.tx_data_pkt[data_tx_cb.curr_session_idx].tx_data_pkt_q,
+ p_data);
+ if (p_data != NULL) {
+ UCI_TRACE_D(
+ "uwb_ucif_send_data_frame : making p_data NULL.");
+ p_data = NULL;
+ }
+ }
+ }
+
+ if ((data_tx_cb.tx_data_pkt[data_tx_cb.curr_session_idx].credit_available) && (uwb_cb.uci_cmd_window > 0)) {
+ if (!p_data) {
+ UCI_TRACE_D(
+ "Dequeueing p_Data");
+ p_data = (UWB_HDR*)phUwb_GKI_dequeue(
+ &data_tx_cb.tx_data_pkt[data_tx_cb.curr_session_idx].tx_data_pkt_q);
+ }
+
+ if (p_data) {
+ /* save the message header to double check the response */
+ ps = (uint8_t*)(p_data + 1) + p_data->offset;
+ /* copying command to temp buff for retransmission */
+ uwb_cb.pLast_data_buf = (UWB_HDR*)last_data_buff;
+ uwb_cb.pLast_data_buf->offset = p_data->offset;
+ pTemp =
+ (uint8_t*)(uwb_cb.pLast_data_buf + 1) + uwb_cb.pLast_data_buf->offset;
+ uwb_cb.pLast_data_buf->len = p_data->len;
+ memcpy(pTemp, ps, p_data->len);
+ /* decrease the credits */
+ data_tx_cb.tx_data_pkt[data_tx_cb.curr_session_idx].credit_available = 0;
+ uwb_cb.is_credit_ntf_pending = true;
+ uwb_cb.uci_cmd_window--;
+ /* send to HAL */
+ HAL_WRITE(p_data);
+ /* start the credit timeout timer */
+ uwb_start_quick_timer(&uwb_cb.uci_wait_credit_ntf_timer,
+ (uint16_t)(UWB_TTYPE_UCI_WAIT_DATA_NTF),
+ uwb_cb.uci_credit_ntf_timeout);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function uwb_ucif_proc_data_credit_ntf
+**
+** Description This function is called to process credits ntf
+**
+** Returns void
+**
+*******************************************************************************/
+void uwb_ucif_proc_data_credit_ntf(uint8_t* p_buf, uint16_t len) {
+ uint32_t session_id;
+
+ /* Stop pending credit ntf timer */
+ if (uwb_cb.is_credit_ntf_pending) {
+ uwb_stop_quick_timer(&uwb_cb.uci_wait_credit_ntf_timer);
+ uwb_cb.is_credit_ntf_pending = false;
+ uwb_cb.data_pkt_retry_count = 0;
+ uwb_cb.invalid_len_cmd_retry_cnt = 0;
+ uwb_cb.uci_cmd_window++;
+ }
+
+ if (len != 0) {
+ STREAM_TO_UINT32(session_id, p_buf);
+ STREAM_TO_UINT8(uwb_cb.data_credits, p_buf);
+ for (int i = 0; i < data_tx_cb.no_of_sessions; i++) {
+ if (session_id == data_tx_cb.tx_data_pkt[i].session_id) {
+ data_tx_cb.curr_session_idx = i;
+ }
+ }
+ data_tx_cb.tx_data_pkt[data_tx_cb.curr_session_idx].credit_available =
+ uwb_cb.data_credits;
+ if ((data_tx_cb.tx_data_pkt[data_tx_cb.curr_session_idx]
+ .credit_available) &&
+ (data_tx_cb.tx_data_pkt[data_tx_cb.curr_session_idx]
+ .tx_data_pkt_q.count)) {
+ uwb_ucif_send_data_frame(NULL);
+ } else {
+ for (int i = 0; i < data_tx_cb.no_of_sessions; i++) {
+ if ((data_tx_cb.tx_data_pkt[i].credit_available) &&
+ (data_tx_cb.tx_data_pkt[i].tx_data_pkt_q.count)) {
+ data_tx_cb.curr_session_idx = i;
+ break;
+ }
+ }
+ uwb_ucif_send_data_frame(NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function uwb_ucif_proc_data_transfer_status_ntf
+**
+** Description This function is called to process data transfer status over UWB
+**
+** Returns void
+**
+*******************************************************************************/
+void uwb_ucif_proc_data_transfer_status_ntf(uint8_t* p_buf, uint16_t len){
+ tUWB_DATA_TRANSFER_STATUS_NTF_REVT dataXferStatus;
+ tUWB_RESPONSE uwb_response;
+ if (len == 0) {
+ UCI_TRACE_E("%s: len is zero", __func__);
+ return;
+ }
+ if (uwb_cb.is_credit_ntf_pending == true) {
+ uwb_stop_quick_timer(&uwb_cb.uci_wait_credit_ntf_timer);
+ uwb_cb.is_credit_ntf_pending = false;
+ uwb_cb.data_pkt_retry_count = 0;
+ uwb_cb.uci_cmd_window++;
+ }
+
+ if (uwb_cb.p_resp_cback == NULL) {
+ UCI_TRACE_E("%s: response callback is null", __func__);
+ return;
+ }
+ memset(&dataXferStatus, 0, sizeof(tUWB_DATA_TRANSFER_STATUS_NTF_REVT ));
+ STREAM_TO_UINT32(dataXferStatus.session_id, p_buf);
+ STREAM_TO_UINT8(dataXferStatus.sequence_num, p_buf);
+ STREAM_TO_UINT8(dataXferStatus.status, p_buf);
+
+ uwb_response.sData_xfer_status = dataXferStatus;
+
+ for (int i = 0; i < data_tx_cb.no_of_sessions; i++) {
+ if (dataXferStatus.session_id == data_tx_cb.tx_data_pkt[i].session_id) {
+ data_tx_cb.tx_data_pkt[i].credit_available = 1;
+ data_tx_cb.curr_session_idx = i;
+ break;
+ }
+ }
+
+ (*uwb_cb.p_resp_cback)(UWB_DATA_TRANSFER_STATUS_NTF_REVT, &uwb_response);
+
+ if ((data_tx_cb.tx_data_pkt[data_tx_cb.curr_session_idx].credit_available) &&
+ (data_tx_cb.tx_data_pkt[data_tx_cb.curr_session_idx]
+ .tx_data_pkt_q.count)) {
+ uwb_ucif_send_data_frame(NULL);
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function uci_ucif_proc_data_packet()
+ **
+ ** Description This function is called to report received data
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void uci_ucif_proc_data_packet(uint8_t* p_buf, uint16_t len) {
+ tUWB_RESPONSE evt_data;
+
+ UCI_TRACE_D("%s: len = %d", __func__, len);
+
+ if (uwb_cb.p_resp_cback == NULL) {
+ UCI_TRACE_E("%s: response callback is null", __func__);
+ return;
+ }
+ STREAM_TO_UINT32(evt_data.sRcvd_data.session_id, p_buf);
+ STREAM_TO_UINT8(evt_data.sRcvd_data.status, p_buf);
+ STREAM_TO_UINT32(evt_data.sRcvd_data.sequence_num, p_buf);
+ STREAM_TO_ARRAY(evt_data.sRcvd_data.address, p_buf, EXTENDED_ADDRESS_LEN);
+ STREAM_TO_UINT8(evt_data.sRcvd_data.source_end_point, p_buf);
+ STREAM_TO_UINT8(evt_data.sRcvd_data.dest_end_point, p_buf);
+ STREAM_TO_UINT16(evt_data.sRcvd_data.data_len, p_buf);
+ STREAM_TO_ARRAY(evt_data.sRcvd_data.data, p_buf, evt_data.sRcvd_data.data_len);
+
+ (*uwb_cb.p_resp_cback)(UWB_DATA_RECV_REVT, &evt_data);
+}
+
+void chain_data_packet(UWB_HDR* p_msg) {
+ uint16_t payload_length = 0;
+ uint8_t mt, pbf, dpf, *p, *pp;
+ p = (uint8_t*)(p_msg + 1) + p_msg->offset;
+ pp = p;
+ if ((p != NULL) & (pp != NULL)) {
+ UCI_MSG_PRS_HDR0(pp, mt, pbf, dpf);
+ pp = pp + 3;
+ payload_length = p[NORMAL_MODE_LENGTH_OFFSET];
+ payload_length = (uint16_t)((payload_length << DATA_PACKET_LEN_SHIFT) |
+ p[NORMAL_MODE_LENGTH_OFFSET - 1]);
+ if (!uwb_cb.IsConformaceTestEnabled) {
+ if (pbf) {
+ if (!uwb_cb.is_first_frgmnt_done) {
+ chained_packet.gid = dpf;
+ memcpy(&chained_packet.buffer[chained_packet.offset], p, p_msg->len);
+ chained_packet.offset = p_msg->len;
+ uwb_cb.is_first_frgmnt_done = true;
+ } else {
+ memcpy(&chained_packet.buffer[chained_packet.offset], pp,
+ payload_length);
+ chained_packet.offset =
+ (uint16_t)(chained_packet.offset + payload_length);
+ }
+ } else {
+ if (uwb_cb.is_first_frgmnt_done) {
+ memcpy(&chained_packet.buffer[chained_packet.offset], pp,
+ payload_length); // Append only payload to chained packet
+ chained_packet.offset =
+ (uint16_t)(chained_packet.offset + payload_length);
+
+ // Update P & PP
+ p = &chained_packet
+ .buffer[0]; // p -> points to complete UCI packet
+ pp = p + 2; // Skip oid & gid bytes
+ payload_length =
+ (uint16_t)(chained_packet.offset - UCI_MSG_HDR_SIZE);
+ UINT16_TO_STREAM(pp,
+ payload_length); // Update overall payload length
+ // into the chained packet
+ }
+ // Clear flags
+ chained_packet.offset = 0;
+ uwb_cb.is_first_frgmnt_done = false;
+ chained_packet.oid = 0xFF;
+ chained_packet.gid = 0xFF;
+ }
+ }
+ uci_ucif_proc_data_packet(pp, payload_length);
+ }
+}
+
+/*******************************************************************************
+ **
** Function uwb_ucif_process_event
**
** Description This function is called to process the
@@ -252,71 +589,74 @@ void uwb_ucif_send_cmd(UWB_HDR* p_buf) {
bool uwb_ucif_process_event(UWB_HDR* p_msg) {
uint8_t mt, pbf, gid, oid, *p, *pp;
bool free = true;
- uint16_t payload_length;
+ uint16_t payload_length =0;
uint8_t *p_old, old_gid, old_oid, old_mt;
- static chained_uci_packet chained_packet;
+ uint8_t is_extended_length = 0;
p = (uint8_t*)(p_msg + 1) + p_msg->offset;
pp = p;
if ((p != NULL) & (pp != NULL)) {
UCI_MSG_PRS_HDR0(pp, mt, pbf, gid);
- UCI_MSG_PRS_HDR1(pp, oid);
- pp = pp + 2; // Skip payload fields
- UCI_TRACE_E("uwb_ucif_process_event enter gid:0x%x status:0x%x", p[0],
+ if (mt == UCI_MT_DATA) {
+ chain_data_packet(p_msg);
+ } else {
+ UCI_MSG_PRS_HDR1(pp, oid);
+ pp = pp + 2; // Skip payload fields
+ UCI_TRACE_I("uwb_ucif_process_event enter gid:0x%x status:0x%x", p[0],
pp[0]);
- payload_length = p[NORMAL_MODE_LENGTH_OFFSET];
-
- if (!uwb_cb.IsConformaceTestEnabled) {
- if (pbf) {
- if (!chained_packet.is_first_frgmnt_done) {
- chained_packet.oid = oid;
- chained_packet.gid = gid;
- memcpy(&chained_packet.buffer[chained_packet.offset], p,
- p_msg->len); // Copy first fragment(uci packet with header)(p)
- chained_packet.offset = p_msg->len;
- chained_packet.is_first_frgmnt_done = true;
- } else {
- // if first fragment is copied, then copy only uci payload(pp) for
- // subsequent fragments
- if ((chained_packet.oid == oid) && (chained_packet.gid == gid)) {
- memcpy(&chained_packet.buffer[chained_packet.offset], pp,
- payload_length);
- chained_packet.offset =
- (uint16_t)(chained_packet.offset + payload_length);
+ payload_length = p[NORMAL_MODE_LENGTH_OFFSET];
+ if (!uwb_cb.IsConformaceTestEnabled) {
+ if (pbf) {
+ if (!uwb_cb.is_first_frgmnt_done) {
+ chained_packet.oid = oid;
+ chained_packet.gid = gid;
+ memcpy(&chained_packet.buffer[chained_packet.offset], p,
+ p_msg->len); // Copy first fragment(uci packet with header)(p)
+ chained_packet.offset = p_msg->len;
+ uwb_cb.is_first_frgmnt_done = true;
} else {
- UCI_TRACE_E(
- "uwb_ucif_process_event: unexpected chain packet: "
- "chained_packed_gid: 0x%x, chained_packet_oid=0x%x, received "
- "packet gid:0x%x, recived packet oid:0x%x",
- chained_packet.gid, chained_packet.oid, gid, oid);
+ // if first fragment is copied, then copy only uci payload(pp) for
+ // subsequent fragments
+ if ((chained_packet.oid == oid) && (chained_packet.gid == gid)) {
+ memcpy(&chained_packet.buffer[chained_packet.offset], pp,
+ payload_length);
+ chained_packet.offset =
+ (uint16_t)(chained_packet.offset + payload_length);
+ } else {
+ UCI_TRACE_D(
+ "uwb_ucif_process_event: unexpected chain packet: "
+ "chained_packed_gid: 0x%x, chained_packet_oid=0x%x, received "
+ "packet gid:0x%x, recived packet oid:0x%x",
+ chained_packet.gid, chained_packet.oid, gid, oid);
+ }
}
- }
- return (free);
- } else {
- if (chained_packet.is_first_frgmnt_done) {
- if ((chained_packet.oid == oid) && (chained_packet.gid == gid)) {
- memcpy(&chained_packet.buffer[chained_packet.offset], pp,
- payload_length); // Append only payload to chained packet
- chained_packet.offset =
- (uint16_t)(chained_packet.offset + payload_length);
-
- // Update P & PP
- p = &chained_packet
- .buffer[0]; // p -> points to complete UCI packet
- pp = p + 2; // Skip oid & gid bytes
- payload_length =
- (uint16_t)(chained_packet.offset - UCI_MSG_HDR_SIZE);
- UINT16_TO_STREAM(pp,
- payload_length); // Update overall payload length
- // into the chained packet
-
- // Clear flags
- chained_packet.offset = 0;
- chained_packet.is_first_frgmnt_done = false;
- chained_packet.oid = 0xFF;
- chained_packet.gid = 0xFF;
+ return (free);
+ } else {
+ if (uwb_cb.is_first_frgmnt_done) {
+ if ((chained_packet.oid == oid) && (chained_packet.gid == gid)) {
+ memcpy(&chained_packet.buffer[chained_packet.offset], pp,
+ payload_length); // Append only payload to chained packet
+ chained_packet.offset =
+ (uint16_t)(chained_packet.offset + payload_length);
+
+ // Update P & PP
+ p = &chained_packet
+ .buffer[0]; // p -> points to complete UCI packet
+ pp = p + 2; // Skip oid & gid bytes
+ payload_length =
+ (uint16_t)(chained_packet.offset - UCI_MSG_HDR_SIZE);
+ UCI_TRACE_I("%s: payloadLength is %d", __func__, payload_length);
+ UINT16_TO_STREAM(pp,
+ payload_length); // Update overall payload length
+ // into the chained packet
+ }
}
+ // Clear flags
+ chained_packet.offset = 0;
+ chained_packet.oid = 0xFF;
+ chained_packet.gid = 0xFF;
+ uwb_cb.is_first_frgmnt_done = false;
}
}
}
@@ -381,7 +721,7 @@ bool uwb_ucif_process_event(UWB_HDR* p_msg) {
case UCI_GID_CORE:
uci_proc_core_management_ntf(oid, pp, payload_length);
break;
- case UCI_GID_SESSION_MANAGE: /* 0010b UCI management group */
+ case UCI_GID_SESSION_MANAGE: /* 0001b UCI management group */
uci_proc_session_management_ntf(oid, pp, payload_length);
break;
case UCI_GID_RANGE_MANAGE: /* 0011b UCI Range management group */
@@ -573,6 +913,24 @@ void uwb_ucif_session_management_status(tUWB_RESPONSE_EVT event, uint8_t* p_buf,
evt = UWB_SESSION_UPDATE_MULTICAST_LIST_REVT;
evt_data.status = status;
break;
+ case UWB_SESSION_CONFIGURE_DT_ANCHOR_RR_RDM_REVT:
+ evt_data.status = status;
+ evt = UWB_SESSION_CONFIGURE_DT_ANCHOR_RR_RDM_REVT;
+ evt_data.sConfigure_dt_anchor_rr_rdm_list.status = status;
+ evt_data.sConfigure_dt_anchor_rr_rdm_list.len = len;
+ if(len > 0){
+ STREAM_TO_ARRAY(evt_data.sConfigure_dt_anchor_rr_rdm_list.rng_round_indexs, p_buf, len);
+ }
+ break;
+ case UWB_SESSION_ACTIVE_ROUNDS_INDEX_UPDATE_REVT:
+ evt_data.status = status;
+ evt = UWB_SESSION_ACTIVE_ROUNDS_INDEX_UPDATE_REVT;
+ evt_data.sRange_round_index.status = status;
+ evt_data.sRange_round_index.len = len;
+ if(len > 0){
+ STREAM_TO_ARRAY(evt_data.sRange_round_index.rng_round_index, p_buf, len);
+ }
+ break;
default:
UCI_TRACE_E("unknown response event %x", event);
}
@@ -711,6 +1069,7 @@ void uwb_ucif_get_range_count_status(tUWB_RESPONSE_EVT event, uint8_t* p_buf,
tUWB_RESPONSE evt_data;
tUWB_RESPONSE_EVT evt = 0;
tUWB_GET_RANGE_COUNT_REVT get_count;
+ get_count.count = 0x00;
uint8_t* p = p_buf;
if (len == 0) {
@@ -760,10 +1119,6 @@ void uwb_ucif_proc_core_device_status(uint8_t* p_buf, uint16_t len) {
uwb_cb.device_state = status;
(*uwb_cb.p_resp_cback)(UWB_DEVICE_STATUS_REVT, &uwb_response);
- if (status == UWBS_STATUS_ERROR) {
- uwb_stop_quick_timer(&uwb_cb.uci_wait_rsp_timer);
- uwb_ucif_uwb_recovery();
- }
}
/*******************************************************************************
@@ -839,10 +1194,21 @@ void uwb_ucif_proc_ranging_data(uint8_t* p, uint16_t len) {
"%s: MEASUREMENT_TYPE_TWOWAY Wrong number of measurements received:%d",
__func__, sRange_data.no_of_measurements);
return;
- } else if (sRange_data.ranging_measure_type == MEASUREMENT_TYPE_ONEWAY &&
+ } else if (sRange_data.ranging_measure_type == MEASUREMENT_TYPE_ULTDOA &&
sRange_data.no_of_measurements > MAX_NUM_OF_TDOA_MEASURES) {
UCI_TRACE_E(
- "%s: MEASUREMENT_TYPE_ONEWAY Wrong number of measurements received:%d",
+ "%s: MEASUREMENT_TYPE_ULTDOA Wrong number of measurements received:%d",
+ __func__, sRange_data.no_of_measurements);
+ return;
+ } else if (sRange_data.ranging_measure_type == MEASUREMENT_TYPE_DLTDOA &&
+ sRange_data.no_of_measurements > MAX_NUM_OF_DLTDOA_MEASURES) {
+ UCI_TRACE_E(
+ "%s: MEASUREMENT_TYPE_DLTDOA Wrong number of measurements received:%d",
+ __func__, sRange_data.no_of_measurements);
+ return;
+ } else if (sRange_data.ranging_measure_type == MEASUREMENT_TYPE_OWR_WITH_AOA &&
+ sRange_data.no_of_measurements > MAX_NUM_OWR_AOA_MEASURES) {
+ UCI_TRACE_E("%s: MEASUREMENT_TYPE_OWR_WITH_AOA Wrong number of measurements received:%d",
__func__, sRange_data.no_of_measurements);
return;
}
@@ -877,28 +1243,99 @@ void uwb_ucif_proc_ranging_data(uint8_t* p, uint16_t len) {
STREAM_TO_UINT16(twr_range_measr->aoa_dest_elevation, p);
STREAM_TO_UINT8(twr_range_measr->aoa_dest_elevation_FOM, p);
STREAM_TO_UINT8(twr_range_measr->slot_index, p);
+ STREAM_TO_UINT8(twr_range_measr->rssi, p);
/* Read & Ignore RFU bytes
- if mac address format is short, then 12 bytes
- if mac address format is extended, then read 6 bytes */
+ if mac address format is short, then 11 bytes
+ if mac address format is extended, then read 5 bytes */
if (sRange_data.mac_addr_mode_indicator == SHORT_MAC_ADDRESS) {
- STREAM_TO_ARRAY(&twr_range_measr->rfu[0], p, 12);
+ STREAM_TO_ARRAY(&twr_range_measr->rfu[0], p, 11);
+ } else {
+ STREAM_TO_ARRAY(&twr_range_measr->rfu[0], p, 5);
+ }
+ }
+ } else if (sRange_data.ranging_measure_type == MEASUREMENT_TYPE_DLTDOA) {
+ for (uint8_t i = 0; i < sRange_data.no_of_measurements; i++) {
+ tUWB_DLTDOA_RANGING_MEASR *dltdoa_range_measr = (tUWB_DLTDOA_RANGING_MEASR*)&sRange_data.ranging_measures.dltdoa_range_measr[i];
+ uint16_t txTimeStampValue = 0;
+ uint16_t rxTimeStampValue = 0;
+ uint16_t anchorLocationValue = 0;
+ uint16_t activeRangingRoundValue = 0;
+
+ if(sRange_data.mac_addr_mode_indicator == SHORT_MAC_ADDRESS) {
+ STREAM_TO_ARRAY(&dltdoa_range_measr->mac_addr[0], p, MAC_SHORT_ADD_LEN);
+ } else if(sRange_data.mac_addr_mode_indicator == EXTENDED_MAC_ADDRESS) {
+ STREAM_TO_ARRAY(&dltdoa_range_measr->mac_addr[0], p, MAC_EXT_ADD_LEN);
+ } else {
+ UCI_TRACE_E("%s: Invalid mac addressing indicator", __func__);
+ return;
+ }
+ STREAM_TO_UINT8(dltdoa_range_measr->status, p);
+ STREAM_TO_UINT8(dltdoa_range_measr->message_type, p);
+ STREAM_TO_UINT16(dltdoa_range_measr->message_control, p);
+ STREAM_TO_UINT16(dltdoa_range_measr->block_index, p);
+ STREAM_TO_UINT8(dltdoa_range_measr->round_index, p);
+ STREAM_TO_UINT8(dltdoa_range_measr->nLos, p);
+ STREAM_TO_UINT16(dltdoa_range_measr->aoa_azimuth, p);
+ STREAM_TO_UINT8(dltdoa_range_measr->aoa_azimuth_FOM, p);
+ STREAM_TO_UINT16(dltdoa_range_measr->aoa_elevation, p);
+ STREAM_TO_UINT8(dltdoa_range_measr->aoa_elevation_FOM, p);
+ STREAM_TO_UINT8(dltdoa_range_measr->rssi, p);
+ txTimeStampValue = ((dltdoa_range_measr->message_control & TDOA_TX_TIMESTAMP_OFFSET ) & (TDOA_TX_TIMESTAMP_OFFSET_MASK));
+ if(txTimeStampValue == TDOA_TX_TIMESTAMP_40BITS) {
+ STREAM_TO_UINT40(dltdoa_range_measr->txTimeStamp, p);
+ } else if(txTimeStampValue == TDOA_TX_TIMESTAMP_64BITS) {
+ STREAM_TO_UINT64(dltdoa_range_measr->txTimeStamp, p);
+ } else {
+ UCI_TRACE_E("%s: Invalid txTimeStamp value", __func__);
+ return;
+ }
+ rxTimeStampValue = ((dltdoa_range_measr->message_control & TDOA_RX_TIMESTAMP_OFFSET ) & (TDOA_RX_TIMESTAMP_OFFSET_MASK));
+ if(rxTimeStampValue == TDOA_RX_TIMESTAMP_40BITS) {
+ STREAM_TO_UINT40(dltdoa_range_measr->rxTimeStamp, p);
+ } else if(rxTimeStampValue == TDOA_RX_TIMESTAMP_64BITS) {
+ STREAM_TO_UINT64(dltdoa_range_measr->rxTimeStamp, p);
+ } else {
+ UCI_TRACE_E("%s: Invalid rxTimeStamp value", __func__);
+ return;
+ }
+ STREAM_TO_UINT16(dltdoa_range_measr->cfo_anchor, p);
+ STREAM_TO_UINT16(dltdoa_range_measr->cfo, p);
+ STREAM_TO_UINT32(dltdoa_range_measr->initiator_reply_time, p);
+ STREAM_TO_UINT32(dltdoa_range_measr->responder_reply_time, p);
+ STREAM_TO_UINT16(dltdoa_range_measr->initiator_responder_TOF, p);
+ anchorLocationValue = ((dltdoa_range_measr->message_control & TDOA_ANCHOR_LOC_OFFSET ) & (TDOA_ANCHOR_LOC_OFFSET_MASK));
+ if(anchorLocationValue == TDOA_ANCHOR_LOC_NOT_INCLUDED) {
+ UCI_TRACE_D("%s: anchorLocation not included", __func__);
+ } else if(anchorLocationValue == TDOA_ANCHOR_LOC_IN_RELATIVE_SYSTEM) {
+ STREAM_TO_ARRAY(&dltdoa_range_measr->anchor_location[0], p, TDOA_ANCHOR_LOC_LEN_10BYTES);
+ } else if(anchorLocationValue == TDOA_ANCHOR_LOC_IN_WGS84_SYSTEM) {
+ STREAM_TO_ARRAY(&dltdoa_range_measr->anchor_location[0], p, TDOA_ANCHOR_LOC_LEN_12BYTES);
+ } else {
+ UCI_TRACE_E("%s: Invalid anchorLocationvalue value", __func__);
+ return;
+ }
+ activeRangingRoundValue = ((dltdoa_range_measr->message_control & TDOA_ACTIVE_RR_OFFSET)
+ & (TDOA_ACTIVE_RR_OFFSET_MASK)) >> TDOA_ACTIVE_RR_INDEX_POSITION;
+ if(activeRangingRoundValue != 0) {
+ STREAM_TO_ARRAY(&dltdoa_range_measr->active_ranging_round[0], p, activeRangingRoundValue);
} else {
- STREAM_TO_ARRAY(&twr_range_measr->rfu[0], p, 6);
+ UCI_TRACE_D("%s: activeRangingRound not included", __func__);
}
}
- } else if (sRange_data.ranging_measure_type == MEASUREMENT_TYPE_ONEWAY) {
+ } else if (sRange_data.ranging_measure_type == MEASUREMENT_TYPE_ULTDOA) {
for (uint8_t i = 0; i < sRange_data.no_of_measurements; i++) {
tUWA_TDoA_RANGING_MEASR* tdoa_range_measr =
(tUWA_TDoA_RANGING_MEASR*)&sRange_data.ranging_measures
.tdoa_range_measr[i];
- uint16_t blink_payload_length = 0;
- uint16_t device_info_length = 0;
- if (ranging_measures_length < ONE_WAY_MEASUREMENT_LENGTH) {
+ if (ranging_measures_length < ULTDOA_MEASUREMENT_LENGTH) {
UCI_TRACE_E("%s: Invalid ranging_measures_length = %x", __func__,
ranging_measures_length);
return;
}
- ranging_measures_length -= ONE_WAY_MEASUREMENT_LENGTH;
+ uint16_t txTimeStampValue = 0;
+ uint16_t ultdoaDeviceIdValue = 0;
+ uint16_t rxTimeStampValue = 0;
+ ranging_measures_length -= ULTDOA_MEASUREMENT_LENGTH;
if (sRange_data.mac_addr_mode_indicator == SHORT_MAC_ADDRESS) {
STREAM_TO_ARRAY(&tdoa_range_measr->mac_addr[0], p, MAC_SHORT_ADD_LEN);
} else if (sRange_data.mac_addr_mode_indicator == EXTENDED_MAC_ADDRESS) {
@@ -907,52 +1344,79 @@ void uwb_ucif_proc_ranging_data(uint8_t* p, uint16_t len) {
UCI_TRACE_E("%s: Invalid mac addressing indicator", __func__);
return;
}
+ STREAM_TO_UINT8(tdoa_range_measr->message_control, p);
STREAM_TO_UINT8(tdoa_range_measr->frame_type, p);
STREAM_TO_UINT8(tdoa_range_measr->nLos, p);
STREAM_TO_UINT16(tdoa_range_measr->aoa_azimuth, p);
STREAM_TO_UINT8(tdoa_range_measr->aoa_azimuth_FOM, p);
STREAM_TO_UINT16(tdoa_range_measr->aoa_elevation, p);
STREAM_TO_UINT8(tdoa_range_measr->aoa_elevation_FOM, p);
- STREAM_TO_UINT64(tdoa_range_measr->timeStamp, p);
- STREAM_TO_UINT32(tdoa_range_measr->blink_frame_number, p);
- if (sRange_data.mac_addr_mode_indicator == SHORT_MAC_ADDRESS) {
- STREAM_TO_ARRAY(&tdoa_range_measr->rfu[0], p, 12);
+ STREAM_TO_UINT32(tdoa_range_measr->frame_number, p);
+ rxTimeStampValue = ((tdoa_range_measr->message_control & ULTDOA_RX_TIMESTAMP_OFFSET ) & (ULTDOA_RX_TIMESTAMP_OFFSET_MASK));
+ if(rxTimeStampValue == ULTDOA_RX_TIMESTAMP_40BITS) {
+ STREAM_TO_ARRAY(&tdoa_range_measr->rxTimeStamp[0], p, ULTDOA_TIMESTAMP_LEN_40BITS);
+ } else if(rxTimeStampValue == ULTDOA_RX_TIMESTAMP_64BITS) {
+ STREAM_TO_ARRAY(&tdoa_range_measr->rxTimeStamp[0], p, ULTDOA_TIMESTAMP_LEN_64BITS);
} else {
- STREAM_TO_ARRAY(&tdoa_range_measr->rfu[0], p, 6);
- }
- STREAM_TO_UINT8(tdoa_range_measr->device_info_size, p);
- device_info_length = tdoa_range_measr->device_info_size;
- ranging_measures_length -= device_info_length;
- if (ranging_measures_length < device_info_length) {
- UCI_TRACE_E(
- "%s: Invalid ranging_measures_length to copy device_info_length = "
- "%x",
- __func__, ranging_measures_length);
+ UCI_TRACE_E("%s: Invalid rxTimeStamp value", __func__);
return;
}
- STREAM_TO_ARRAY(&device_info_buffer[i][0], p,
- tdoa_range_measr->device_info_size);
- tdoa_range_measr->device_info = &device_info_buffer[i][0];
- STREAM_TO_UINT8(tdoa_range_measr->blink_payload_size, p);
- blink_payload_length = tdoa_range_measr->blink_payload_size;
- ranging_measures_length -= blink_payload_length;
- if (ranging_measures_length < blink_payload_length) {
- UCI_TRACE_E(
- "%s: Invalid ranging_measures_length to copy blink_payload_length "
- "= %x",
- __func__, ranging_measures_length);
- return;
+ ultdoaDeviceIdValue = ((tdoa_range_measr->message_control & ULTDOA_DEVICE_ID_OFFSET ) & (ULTDOA_DEVICE_ID_OFFSET_MASK));
+ if(ultdoaDeviceIdValue > 0) {
+ if(ultdoaDeviceIdValue == ULTDOA_DEVICE_ID_16BITS) {
+ STREAM_TO_ARRAY(&tdoa_range_measr->ulTdoa_device_id[0], p, ULTDOA_DEVICE_ID_LEN_16BITS);
+ } else if(ultdoaDeviceIdValue == ULTDOA_DEVICE_ID_32BITS) {
+ STREAM_TO_ARRAY(&tdoa_range_measr->ulTdoa_device_id[0], p, ULTDOA_DEVICE_ID_LEN_32BITS);
+ } else if(ultdoaDeviceIdValue == ULTDOA_DEVICE_ID_64BITS) {
+ STREAM_TO_ARRAY(&tdoa_range_measr->ulTdoa_device_id[0], p, ULTDOA_DEVICE_ID_LEN_64BITS);
+ } else {
+ UCI_TRACE_E("%s: Invalid Device Id value", __func__);
+ return;
+ }
+ }
+ txTimeStampValue = ((tdoa_range_measr->message_control & ULTDOA_TX_TIMESTAMP_OFFSET ) & (ULTDOA_TX_TIMESTAMP_OFFSET_MASK));
+ if(txTimeStampValue > 0) {
+ if(txTimeStampValue == ULTDOA_TX_TIMESTAMP_40BITS) {
+ STREAM_TO_ARRAY(&tdoa_range_measr->txTimeStamp[0], p, ULTDOA_TIMESTAMP_LEN_40BITS);
+ } else if(txTimeStampValue == ULTDOA_TX_TIMESTAMP_64BITS){
+ STREAM_TO_ARRAY(&tdoa_range_measr->txTimeStamp[0], p, ULTDOA_TIMESTAMP_LEN_64BITS);
+ } else {
+ UCI_TRACE_E("%s: Invalid txTimeStamp value", __func__);
+ return;
+ }
}
- STREAM_TO_ARRAY(&blink_payload_buffer[i][0], p,
- tdoa_range_measr->blink_payload_size);
- tdoa_range_measr->blink_payload_data = &blink_payload_buffer[i][0];
}
+ } else if (sRange_data.ranging_measure_type == MEASUREMENT_TYPE_OWR_WITH_AOA) {
+ tUWA_OWR_WITH_AOA_RANGING_MEASR* owr_aoa_range_measr =
+ (tUWA_OWR_WITH_AOA_RANGING_MEASR*)&sRange_data.ranging_measures
+ .owr_with_aoa_range_measr;
+ if (ranging_measures_length < OWR_WITH_AOA_MEASUREMENT_LENGTH) {
+ UCI_TRACE_E("%s: Invalid one way ranging_measures_length = %x", __func__,
+ ranging_measures_length);
+ return;
+ }
+ ranging_measures_length -= OWR_WITH_AOA_MEASUREMENT_LENGTH;
+ if (sRange_data.mac_addr_mode_indicator == SHORT_MAC_ADDRESS) {
+ STREAM_TO_ARRAY(&owr_aoa_range_measr->mac_addr[0], p, MAC_SHORT_ADD_LEN);
+ ranging_measures_length -= MAC_SHORT_ADD_LEN;
+ } else if (sRange_data.mac_addr_mode_indicator == EXTENDED_MAC_ADDRESS) {
+ STREAM_TO_ARRAY(&owr_aoa_range_measr->mac_addr[0], p, MAC_EXT_ADD_LEN);
+ ranging_measures_length -= MAC_EXT_ADD_LEN;
+ } else {
+ UCI_TRACE_E("%s: Invalid mac addressing indicator", __func__);
+ return;
+ }
+ STREAM_TO_UINT8(owr_aoa_range_measr->status, p);
+ STREAM_TO_UINT8(owr_aoa_range_measr->nLos, p);
+ STREAM_TO_UINT8(owr_aoa_range_measr->frame_seq_num, p);
+ STREAM_TO_UINT16(owr_aoa_range_measr->block_index, p);
+ STREAM_TO_UINT16(owr_aoa_range_measr->aoa_azimuth, p);
+ STREAM_TO_UINT8(owr_aoa_range_measr->aoa_azimuth_FOM, p);
+ STREAM_TO_UINT16(owr_aoa_range_measr->aoa_elevation, p);
+ STREAM_TO_UINT8(owr_aoa_range_measr->aoa_elevation_FOM, p);
} else {
- UCI_TRACE_E("%s: Measurement type not matched", __func__);
+ UCI_TRACE_E("%s: Measurement type(%d) not matched", __func__, sRange_data.ranging_measure_type);
}
- uwb_response.sRange_data = sRange_data;
-
- (*uwb_cb.p_resp_cback)(UWB_RANGE_DATA_REVT, &uwb_response);
UCI_TRACE_I("%s: ranging_measures_length = %d range_data_ntf_len = %d", __func__,ranging_measures_length,range_data_ntf_len);
if (ranging_measures_length >= VENDOR_SPEC_INFO_LEN) {
@@ -962,15 +1426,16 @@ void uwb_ucif_proc_ranging_data(uint8_t* p, uint16_t len) {
if (vendor_specific_length > MAX_VENDOR_INFO_LENGTH) {
UCI_TRACE_E("%s: Invalid Range_data vendor_specific_length = %x",
__func__, vendor_specific_length);
- return;
}
- uint8_t *range_data_with_vendor_info = range_data_ntf_buffer;
- uwb_response.sVendor_specific_ntf.len = range_data_ntf_len;
- STREAM_TO_ARRAY(uwb_response.sVendor_specific_ntf.data, range_data_with_vendor_info, range_data_ntf_len);
- (*uwb_cb.p_resp_cback)(UWB_VENDOR_SPECIFIC_UCI_NTF_EVT, &uwb_response);
+ STREAM_TO_ARRAY(sRange_data.vendor_specific_ntf.data, p, vendor_specific_length);
+ sRange_data.vendor_specific_ntf.len = vendor_specific_length;
}
}
+
+ uwb_response.sRange_data = sRange_data;
+
+ (*uwb_cb.p_resp_cback)(UWB_RANGE_DATA_REVT, &uwb_response);
}
/*******************************************************************************