diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-09-12 17:13:34 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-09-12 17:13:34 +0000 |
commit | 2424686157864d83dcb19f213c8f44ca88846997 (patch) | |
tree | 363d8e541d04a792411d7e822eef8b794b09901b | |
parent | 4ffdea82cf7be632fae3e15b6519950e9d26f0d7 (diff) | |
parent | c533cdbd8db59d4130ec89142adf0c6ca997553d (diff) | |
download | uwb-android13-mainline-appsearch-release.tar.gz |
Snap for 9052600 from c533cdbd8db59d4130ec89142adf0c6ca997553d to mainline-appsearch-releaseaml_ase_331311020aml_ase_331112000android13-mainline-appsearch-release
Change-Id: Iaff3ade404f7ee3f0b301344001c8b60e680c02f
23 files changed, 657 insertions, 537 deletions
@@ -1,202 +1,16 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. +Notice of Rights Limitations – Important User Information +AOSP may include one or more implementations of +Specifications or draft Specifications developed by the FiRa Consortium. The +FiRa Consortium is a nonprofit organization formed for the purposes of defining +one or more specifications, best practices, implementation guidelines and +certification programs to promote the availability of compliant implementations +of FiRa Specifications. Information on becoming a Member, including information +about the benefits thereof, can be found at http://firaconsortium.org. + +AOSP is not affiliated with or endorsed by the FiRa +Consortium. Implementation of this AOSP code does not +assure compliance with any FiRa Specifications and does not convey the right to +identify any final product as FiRa certified. Members of the FiRa Consortium or +others may hold patents and other intellectual property rights relating to FiRa +Specifications. The FiRa Intellectual Property Rights Policy can be found at +https://www.firaconsortium.org/membership/documents. diff --git a/src/Android.bp b/src/Android.bp index 8bd2271..2cadd12 100755 --- a/src/Android.bp +++ b/src/Android.bp @@ -98,6 +98,7 @@ rust_defaults { "rust/uwb_uci_packets/src/lib.rs", ":UwbGeneratedPackets_rust", ], + edition: "2021", proc_macros: ["libnum_derive"], rustlibs:[ "libbytes", @@ -169,6 +170,7 @@ genrule { rust_defaults { name: "libuwb_core_defaults", srcs: ["rust/uwb_core/src/lib.rs"], + edition: "2021", lints: "android", clippy_lints: "android", rustlibs: [ @@ -181,6 +183,7 @@ rust_defaults { ], proc_macros: [ "libasync_trait", + "libnum_derive", ], min_sdk_version: "Tiramisu", host_supported: true, @@ -279,7 +282,7 @@ rust_library { "libasync_trait", ], apex_available: [ - "com.android.ucihal", + "com.android.uwb", ], min_sdk_version: "Tiramisu", host_supported: true, diff --git a/src/TEST_MAPPING b/src/TEST_MAPPING index ac3f1ce..510d37b 100644 --- a/src/TEST_MAPPING +++ b/src/TEST_MAPPING @@ -1,9 +1,10 @@ { "presubmit": [ - { - "name": "libuwb_core_cargo_test", - "host": true - }, + // TODO(b/245028544): Disable the presubmit check temporarily. + // { + // "name": "libuwb_core_cargo_test", + // "host": true + // }, { "name": "libuwb_uci_rust_tests" }, diff --git a/src/rust/uci/mod.rs b/src/rust/uci/mod.rs index 43a24b5..116d03e 100644 --- a/src/rust/uci/mod.rs +++ b/src/rust/uci/mod.rs @@ -48,6 +48,7 @@ pub type SyncUwbAdaptation = Arc<dyn UwbAdaptation + Send + Sync>; #[derive(Arbitrary, Clone, Debug, PartialEq, Eq)] pub enum JNICommand { // Blocking UCI commands + Enable, UciGetCapsInfo, UciGetDeviceInfo, UciSessionInit(u32, u8), @@ -90,7 +91,6 @@ pub enum JNICommand { UciGetPowerStats, // Non blocking commands - Enable, Disable(bool), } @@ -250,6 +250,24 @@ impl<T: EventManager> Driver<T> { ) -> 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) => { @@ -325,11 +343,6 @@ impl<T: EventManager> Driver<T> { ) -> Result<()> { log::debug!("Received non blocking cmd {:?}", cmd); match cmd { - JNICommand::Enable => { - self.adaptation.hal_open(&chip_id).await?; - self.adaptation.core_initialization(&chip_id).await?; - self.set_state(UwbState::W4HalOpen); - } JNICommand::Disable(_graceful) => match self.adaptation.hal_close(&chip_id).await { Ok(()) => self.set_state(UwbState::W4HalClose), Err(e) => { @@ -637,7 +650,7 @@ mod tests { mock_adaptation.expect_core_initialization(Ok(())); }); - dispatcher.send_jni_command(JNICommand::Enable, String::from("chip_id")).unwrap(); + dispatcher.block_on_jni_command(JNICommand::Enable, String::from("chip_id")).unwrap(); } #[test] @@ -650,7 +663,7 @@ mod tests { }); let chip_id = String::from("chip_id"); - dispatcher.send_jni_command(JNICommand::Enable, chip_id.clone()).unwrap(); + dispatcher.block_on_jni_command(JNICommand::Enable, chip_id.clone()).unwrap(); hal_sender .send(( HalCallback::Event { event: UwbEvent::ERROR, event_status: UwbStatus::FAILED }, diff --git a/src/rust/uci/uci_hrcv.rs b/src/rust/uci/uci_hrcv.rs index ab5da94..c79b7c6 100644 --- a/src/rust/uci/uci_hrcv.rs +++ b/src/rust/uci/uci_hrcv.rs @@ -43,6 +43,7 @@ pub enum UciResponse { AndroidSetCountryCodeRsp(AndroidSetCountryCodeRspPacket), AndroidGetPowerStatsRsp(AndroidGetPowerStatsRspPacket), RawVendorRsp(UciResponsePacket), + EnableRsp(bool), DisableRsp, } diff --git a/src/rust/uci_hal_android/uci_hal_android.rs b/src/rust/uci_hal_android/uci_hal_android.rs index 5e1edcf..a9b3048 100644 --- a/src/rust/uci_hal_android/uci_hal_android.rs +++ b/src/rust/uci_hal_android/uci_hal_android.rs @@ -34,22 +34,25 @@ use tokio::runtime::Handle; use tokio::sync::{mpsc, Mutex}; use uwb_core::error::{Error as UwbCoreError, Result as UwbCoreResult}; use uwb_core::params::uci_packets::SessionId; -use uwb_core::uci::uci_hal::{RawUciMessage, UciHal}; +use uwb_core::uci::uci_hal::{UciHal, UciHalPacket}; use uwb_uci_packets::{DeviceState, DeviceStatusNtfBuilder}; use crate::error::{Error, Result}; -fn into_raw_messages<T: Into<uwb_uci_packets::UciPacketPacket>>(builder: T) -> Vec<RawUciMessage> { +fn input_uci_hal_packet<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() } /// Send device status notification with error state. fn send_device_state_error_notification( - uci_sender: &mpsc::UnboundedSender<RawUciMessage>, + uci_sender: &mpsc::UnboundedSender<UciHalPacket>, ) -> UwbCoreResult<()> { - let raw_message_packets = - into_raw_messages(DeviceStatusNtfBuilder { device_state: DeviceState::DeviceStateError }); + let raw_message_packets = input_uci_hal_packet(DeviceStatusNtfBuilder { + device_state: DeviceState::DeviceStateError, + }); for raw_message_packet in raw_message_packets { if let Err(e) = uci_sender.send(raw_message_packet) { error!("Error sending device state error notification: {:?}", e); @@ -66,14 +69,14 @@ fn send_device_state_error_notification( /// trait is consumed by BnUwbClientCallback, thus it cannot be implemented for UciHalAndroid. #[derive(Clone, Debug)] struct RawUciCallback { - uci_sender: mpsc::UnboundedSender<RawUciMessage>, + uci_sender: mpsc::UnboundedSender<UciHalPacket>, hal_open_result_sender: mpsc::Sender<Result<()>>, hal_close_result_sender: mpsc::Sender<Result<()>>, } impl RawUciCallback { pub fn new( - uci_sender: mpsc::UnboundedSender<RawUciMessage>, + uci_sender: mpsc::UnboundedSender<UciHalPacket>, hal_open_result_sender: mpsc::Sender<Result<()>>, hal_close_result_sender: mpsc::Sender<Result<()>>, ) -> Self { @@ -153,7 +156,7 @@ impl UciHal for UciHalAndroid { /// Open the UCI HAL and power on the UWBS. async fn open( &mut self, - uci_rsp_ntf_sender: mpsc::UnboundedSender<RawUciMessage>, + packet_sender: mpsc::UnboundedSender<UciHalPacket>, ) -> UwbCoreResult<()> { // Returns error if UciHalAndroid is already open. if self.hal_uci_recipient.is_some() { @@ -171,8 +174,8 @@ impl UciHal for UciHalAndroid { return Err(UwbCoreError::BadParameters); } let chip_name: &str = match &self.chip_id == "default" { - false => &chip_names[0], - true => &self.chip_id, + true => &chip_names[0], + false => &self.chip_id, }; if !chip_names.contains(&chip_name.to_string()) { return Err(UwbCoreError::BadParameters); @@ -185,9 +188,9 @@ impl UciHal for UciHalAndroid { // If the binder object unexpectedly goes away (typically because its hosting process has // been killed), then the `DeathRecipient`'s callback will be called. - let uci_rsp_ntf_sender_clone = uci_rsp_ntf_sender.clone(); + let packet_sender_clone = packet_sender.clone(); let mut bare_death_recipient = DeathRecipient::new(move || { - send_device_state_error_notification(&uci_rsp_ntf_sender_clone).unwrap_or_else(|e| { + send_device_state_error_notification(&packet_sender_clone).unwrap_or_else(|e| { error!("Error sending device state error notification: {:?}", e); }); }); @@ -196,12 +199,12 @@ impl UciHal for UciHalAndroid { .link_to_death(&mut bare_death_recipient) .map_err(|e| UwbCoreError::from(Error::from(e)))?; - // Connect callback to uci_rsp_ntf_sender. + // Connect callback to packet_sender. let (hal_open_result_sender, mut hal_open_result_receiver) = mpsc::channel::<Result<()>>(1); let (hal_close_result_sender, hal_close_result_receiver) = mpsc::channel::<Result<()>>(1); let m_cback = BnUwbClientCallback::new_async_binder( RawUciCallback::new( - uci_rsp_ntf_sender, + packet_sender.clone(), hal_open_result_sender, hal_close_result_sender, ), @@ -209,11 +212,21 @@ impl UciHal for UciHalAndroid { BinderFeatures::default(), ); i_uwb_chip.open(&m_cback).await.map_err(|e| UwbCoreError::from(Error::from(e)))?; - // Initialize core and wait for POST_INIT_CPLT. i_uwb_chip.coreInit().await.map_err(|e| UwbCoreError::from(Error::from(e)))?; match hal_open_result_receiver.recv().await { Some(Ok(())) => { + // Workaround while http://b/243140882 is not fixed: + // Send DEVICE_STATE_READY notification as chip is not sending this notification. + let device_ready_ntfs = input_uci_hal_packet( + DeviceStatusNtfBuilder { device_state: DeviceState::DeviceStateReady }.build(), + ); + for device_ready_ntf in device_ready_ntfs { + packet_sender.send(device_ready_ntf).unwrap_or_else(|e| { + error!("UCI HAL: failed to send device ready notification: {:?}", e); + }); + } + // End of workaround. self.hal_uci_recipient.replace(i_uwb_chip); self.hal_death_recipient.replace(Arc::new(Mutex::new(bare_death_recipient))); self.hal_close_result_receiver.replace(hal_close_result_receiver); @@ -246,11 +259,11 @@ impl UciHal for UciHalAndroid { } } - async fn send_command(&mut self, cmd: RawUciMessage) -> UwbCoreResult<()> { + async fn send_packet(&mut self, packet: UciHalPacket) -> UwbCoreResult<()> { match &self.hal_uci_recipient { Some(i_uwb_chip) => { i_uwb_chip - .sendUciMessage(&cmd) + .sendUciMessage(&packet) .await .map_err(|e| UwbCoreError::from(Error::from(e)))?; Ok(()) diff --git a/src/rust/uwb_core/Cargo.toml b/src/rust/uwb_core/Cargo.toml index c9294f1..71325f2 100644 --- a/src/rust/uwb_core/Cargo.toml +++ b/src/rust/uwb_core/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "uwb_core" version = "0.0.1" -edition = "2018" +edition = "2021" [dependencies] async-trait = "0.1.32" bytes = "1.1.0" log = "0.4.14" num-traits = "0.2.12" +num-derive = "0.3.3" thiserror = "1.0.30" tokio = { version = "1.14.0", features = ["macros", "rt", "rt-multi-thread", "sync", "time"] } diff --git a/src/rust/uwb_core/examples/main.rs b/src/rust/uwb_core/examples/main.rs index 4962820..86a8893 100644 --- a/src/rust/uwb_core/examples/main.rs +++ b/src/rust/uwb_core/examples/main.rs @@ -21,13 +21,13 @@ 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::{UwbServiceBuilder, UwbServiceCallback}; -use uwb_core::uci::{RawUciMessage, SessionRangeData, UciHal}; +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, _msg_sender: mpsc::UnboundedSender<RawUciMessage>) -> UwbResult<()> { + async fn open(&mut self, _packet_sender: mpsc::UnboundedSender<UciHalPacket>) -> UwbResult<()> { debug!("UciHalImpl::open() is called"); Ok(()) } @@ -35,8 +35,8 @@ impl UciHal for UciHalImpl { debug!("UciHalImpl::close() is called"); Ok(()) } - async fn send_command(&mut self, cmd: RawUciMessage) -> UwbResult<()> { - debug!("UciHalImpl::send_command({:?}) is called", cmd); + async fn send_packet(&mut self, packet: UciHalPacket) -> UwbResult<()> { + debug!("UciHalImpl::send_packet({:?}) is called", packet); Ok(()) } } diff --git a/src/rust/uwb_core/src/params/ccc_app_config_params.rs b/src/rust/uwb_core/src/params/ccc_app_config_params.rs index d6bcfe2..ab90d3a 100644 --- a/src/rust/uwb_core/src/params/ccc_app_config_params.rs +++ b/src/rust/uwb_core/src/params/ccc_app_config_params.rs @@ -24,7 +24,8 @@ use crate::params::fira_app_config_params::{ }; use crate::params::uci_packets::{AppConfigTlvType, SessionState}; use crate::params::utils::{u16_to_bytes, u32_to_bytes, u8_to_bytes, validate}; -use crate::utils::builder_field; +use crate::utils::{builder_field, getter_field}; +use num_derive::{FromPrimitive, ToPrimitive}; const CHAP_IN_RSTU: u16 = 400; // 1 Chap = 400 RSTU. pub(super) const MINIMUM_BLOCK_DURATION_MS: u32 = 96; @@ -54,7 +55,20 @@ pub struct CccAppConfigParams { hopping_mode: CccHoppingMode, } +#[allow(missing_docs)] impl CccAppConfigParams { + // Generate the getter methods for all the fields. + getter_field!(protocol_version, CccProtocolVersion); + getter_field!(uwb_config, CccUwbConfig); + getter_field!(pulse_shape_combo, CccPulseShapeCombo); + getter_field!(ran_multiplier, u32); + getter_field!(channel_number, CccUwbChannel); + getter_field!(chaps_per_slot, ChapsPerSlot); + getter_field!(num_responder_nodes, u8); + getter_field!(slots_per_rr, u8); + getter_field!(sync_code_index, u8); + getter_field!(hopping_mode, CccHoppingMode); + pub fn is_config_updatable(config_map: &AppConfigTlvMap, session_state: SessionState) -> bool { match session_state { SessionState::SessionStateIdle => { @@ -201,7 +215,7 @@ impl From<CccProtocolVersion> for Vec<u8> { } #[repr(u16)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum CccUwbConfig { Config0 = 0, Config1 = 1, @@ -220,7 +234,7 @@ impl From<CccPulseShapeCombo> for Vec<u8> { } #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum PulseShape { SymmetricalRootRaisedCosine = 0x0, PrecursorFree = 0x1, @@ -228,14 +242,14 @@ pub enum PulseShape { } #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum CccUwbChannel { Channel5 = 5, Channel9 = 9, } #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum HoppingConfigMode { None = 0, Continuous = 1, @@ -243,14 +257,14 @@ pub enum HoppingConfigMode { } #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum HoppingSequence { Default = 0, Aes = 1, } #[repr(u16)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum ChapsPerSlot { Value3 = 3, Value4 = 4, @@ -262,7 +276,7 @@ pub enum ChapsPerSlot { } #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum CccHoppingMode { Disable = 0, AdaptiveDefault = 2, 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 c6b459e..4c0cf51 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 @@ -15,13 +15,16 @@ //! This module defines the UCI application config parameters for the FiRa ranging session. use std::collections::{HashMap, HashSet}; +use std::convert::{TryFrom, TryInto}; use log::warn; +use num_derive::{FromPrimitive, ToPrimitive}; + use crate::params::app_config_params::{AppConfigParams, AppConfigTlvMap}; use crate::params::uci_packets::{AppConfigTlvType, SessionState, SubSessionId}; use crate::params::utils::{u16_to_bytes, u32_to_bytes, u8_to_bytes, validate}; -use crate::utils::builder_field; +use crate::utils::{builder_field, getter_field}; // The default value of each parameters. const DEFAULT_RANGING_ROUND_USAGE: RangingRoundUsage = RangingRoundUsage::DsTwr; @@ -126,7 +129,57 @@ pub struct FiraAppConfigParams { number_of_aoa_elevation_measurements: u8, } +#[allow(missing_docs)] impl FiraAppConfigParams { + // Generate the getter methods for all the fields. + getter_field!(device_type, DeviceType); + getter_field!(ranging_round_usage, RangingRoundUsage); + getter_field!(sts_config, StsConfig); + getter_field!(multi_node_mode, MultiNodeMode); + getter_field!(channel_number, UwbChannel); + getter_field!(device_mac_address, UwbAddress); + getter_field!(dst_mac_address, Vec<UwbAddress>); + getter_field!(slot_duration_rstu, u16); + getter_field!(ranging_interval_ms, u32); + getter_field!(mac_fcs_type, MacFcsType); + getter_field!(ranging_round_control, RangingRoundControl); + getter_field!(aoa_result_request, AoaResultRequest); + getter_field!(range_data_ntf_config, RangeDataNtfConfig); + getter_field!(range_data_ntf_proximity_near_cm, u16); + getter_field!(range_data_ntf_proximity_far_cm, u16); + getter_field!(device_role, DeviceRole); + getter_field!(rframe_config, RframeConfig); + getter_field!(preamble_code_index, u8); + getter_field!(sfd_id, u8); + getter_field!(psdu_data_rate, PsduDataRate); + getter_field!(preamble_duration, PreambleDuration); + getter_field!(ranging_time_struct, RangingTimeStruct); + getter_field!(slots_per_rr, u8); + getter_field!(tx_adaptive_payload_power, TxAdaptivePayloadPower); + getter_field!(responder_slot_index, u8); + getter_field!(prf_mode, PrfMode); + getter_field!(scheduled_mode, ScheduledMode); + getter_field!(key_rotation, KeyRotation); + getter_field!(key_rotation_rate, u8); + getter_field!(session_priority, u8); + getter_field!(mac_address_mode, MacAddressMode); + getter_field!(vendor_id, [u8; 2]); + getter_field!(static_sts_iv, [u8; 6]); + getter_field!(number_of_sts_segments, u8); + getter_field!(max_rr_retry, u16); + getter_field!(uwb_initiation_time_ms, u32); + getter_field!(hopping_mode, HoppingMode); + getter_field!(block_stride_length, u8); + getter_field!(result_report_config, ResultReportConfig); + getter_field!(in_band_termination_attempt_count, u8); + getter_field!(sub_session_id, u32); + getter_field!(bprf_phr_data_rate, BprfPhrDataRate); + getter_field!(max_number_of_measurements, u16); + getter_field!(sts_length, StsLength); + getter_field!(number_of_range_measurements, u8); + getter_field!(number_of_aoa_azimuth_measurements, u8); + getter_field!(number_of_aoa_elevation_measurements, u8); + /// validate if the params are valid. fn is_valid(&self) -> Option<()> { if self.device_type == DeviceType::Controlee { @@ -641,7 +694,7 @@ impl FiraAppConfigParamsBuilder { /// The device type. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum DeviceType { /// Controlee Controlee = 0, @@ -651,7 +704,7 @@ pub enum DeviceType { /// The mode of ranging round usage. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum RangingRoundUsage { /// SS-TWR with Deferred Mode SsTwr = 1, @@ -665,7 +718,7 @@ pub enum RangingRoundUsage { /// This parameter indicates how the system shall generate the STS. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum StsConfig { /// Static STS (default) Static = 0, @@ -677,7 +730,7 @@ pub enum StsConfig { /// The mode of multi node. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum MultiNodeMode { /// Single device to Single device (Unicast) Unicast = 0, @@ -690,7 +743,7 @@ pub enum MultiNodeMode { /// The UWB channel number. (default = 9) #[allow(missing_docs)] #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum UwbChannel { Channel5 = 5, Channel6 = 6, @@ -720,13 +773,24 @@ impl From<UwbAddress> for Vec<u8> { } } +impl TryFrom<Vec<u8>> for UwbAddress { + type Error = &'static str; + fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> { + match value.len() { + 2 => Ok(UwbAddress::Short(value.try_into().unwrap())), + 8 => Ok(UwbAddress::Extended(value.try_into().unwrap())), + _ => Err("Invalid address length"), + } + } +} + fn addresses_to_bytes(addresses: Vec<UwbAddress>) -> Vec<u8> { addresses.into_iter().flat_map(Into::<Vec<u8>>::into).collect() } /// CRC type in MAC footer. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum MacFcsType { /// CRC 16 (default) Crc16 = 0, @@ -785,7 +849,7 @@ impl RangingRoundControl { /// This parameter is used to configure AOA results in the range data notification. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum AoaResultRequest { /// Disable AOA NoAoaReport = 0, @@ -801,7 +865,7 @@ pub enum AoaResultRequest { /// This config is used to enable/disable the range data notification. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum RangeDataNtfConfig { /// Disable range data notification Disable = 0, @@ -813,7 +877,7 @@ pub enum RangeDataNtfConfig { /// The device role. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum DeviceRole { /// Responder of the session Responder = 0, @@ -823,7 +887,7 @@ pub enum DeviceRole { /// Rframe config. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum RframeConfig { /// SP0 SP0 = 0, @@ -835,7 +899,7 @@ pub enum RframeConfig { /// This value configures the data rate. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum PsduDataRate { /// 6.81 Mbps (default) Rate6m81 = 0, @@ -853,7 +917,7 @@ pub enum PsduDataRate { /// /// Two configurations are possible. BPRF uses only 64 symbols. HPRF can use both. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum PreambleDuration { /// 32 symbols T32Symbols = 0, @@ -863,7 +927,7 @@ pub enum PreambleDuration { /// The type of ranging time scheduling. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum RangingTimeStruct { /// Interval Based Scheduling IntervalBasedScheduling = 0, @@ -873,7 +937,7 @@ pub enum RangingTimeStruct { /// This configuration is used to enable/disable adaptive payload power for TX. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum TxAdaptivePayloadPower { /// Disable (default) Disable = 0, @@ -883,7 +947,7 @@ pub enum TxAdaptivePayloadPower { /// This parameter is used to configure the mean PRF. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum PrfMode { /// 62.4 MHz PRF. BPRF mode (default) Bprf = 0, @@ -895,7 +959,7 @@ pub enum PrfMode { /// This parameter is used to set the Multinode Ranging Type. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum ScheduledMode { /// Time scheduled ranging (default) TimeScheduledRanging = 1, @@ -904,7 +968,7 @@ pub enum ScheduledMode { /// This configuration is used to enable/disable the key rotation feature during Dynamic STS /// ranging. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum KeyRotation { /// Disable (default) Disable = 0, @@ -914,7 +978,7 @@ pub enum KeyRotation { /// MAC Addressing mode to be used in UWBS. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum MacAddressMode { /// MAC address is 2 bytes and 2 bytes to be used in MAC header (default) MacAddress2Bytes = 0, @@ -928,7 +992,7 @@ pub enum MacAddressMode { /// /// Note: This config is applicable only for controller and ignored in case of controlee. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum HoppingMode { /// Hopping Diable (default) Disable = 0, @@ -979,7 +1043,7 @@ impl ResultReportConfig { /// The data rate for BPRF mode. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum BprfPhrDataRate { /// 850 kbps (default) Rate850k = 0, @@ -989,7 +1053,7 @@ pub enum BprfPhrDataRate { /// The number of symbols in an STS segment. #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum StsLength { /// 32 symbols Length32 = 0, diff --git a/src/rust/uwb_core/src/service/uwb_service.rs b/src/rust/uwb_core/src/service/uwb_service.rs index 81cd52b..26bb73f 100644 --- a/src/rust/uwb_core/src/service/uwb_service.rs +++ b/src/rust/uwb_core/src/service/uwb_service.rs @@ -166,6 +166,14 @@ impl UwbService { } } + /// Get app config params for the given session id + pub fn session_params(&mut 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"), + } + } + /// Send the |cmd| to UwbServiceActor and wait until receiving the response. fn block_on_cmd(&self, cmd: Command) -> Result<Response> { let (result_sender, result_receiver) = oneshot::channel(); @@ -331,6 +339,15 @@ impl<C: UwbServiceCallback, U: UciManager> UwbServiceActor<C, U> { let msg = self.uci_manager.raw_vendor_cmd(gid, oid, payload).await?; Ok(Response::RawVendorMessage(msg)) } + Command::GetParams { session_id } => { + if let Some(session_manager) = self.session_manager.as_mut() { + let params = session_manager.session_params(session_id).await?; + Ok(Response::AppConfigParams(params)) + } else { + error!("The service is not enabled yet"); + Err(Error::BadParameters) + } + } } } @@ -445,6 +462,9 @@ enum Command { oid: u32, payload: Vec<u8>, }, + GetParams { + session_id: SessionId, + }, } #[derive(Debug)] diff --git a/src/rust/uwb_core/src/session/session_manager.rs b/src/rust/uwb_core/src/session/session_manager.rs index f2280ad..396c215 100644 --- a/src/rust/uwb_core/src/session/session_manager.rs +++ b/src/rust/uwb_core/src/session/session_manager.rs @@ -118,6 +118,13 @@ impl SessionManager { Ok(()) } + pub async fn session_params(&mut self, session_id: SessionId) -> Result<AppConfigParams> { + match self.send_cmd(SessionCommand::GetParams { session_id }).await? { + SessionResponse::AppConfigParams(params) => Ok(params), + _ => panic!("session_params() should reply AppConfigParams result"), + } + } + // Send the |cmd| to the SessionManagerActor. async fn send_cmd(&self, cmd: SessionCommand) -> Result<SessionResponse> { let (result_sender, result_receiver) = oneshot::channel(); @@ -270,6 +277,17 @@ impl<T: UciManager> SessionManagerActor<T> { } } } + SessionCommand::GetParams { session_id } => { + match self.active_sessions.get_mut(&session_id) { + None => { + warn!("Session {} doesn't exist", session_id); + let _ = result_sender.send(Err(Error::BadParameters)); + } + Some(session) => { + session.params(result_sender); + } + } + } } } @@ -356,6 +374,9 @@ enum SessionCommand { action: UpdateMulticastListAction, controlees: Vec<Controlee>, }, + GetParams { + session_id: SessionId, + }, } #[cfg(test)] @@ -987,4 +1008,46 @@ mod tests { assert!(mock_uci_manager.wait_expected_calls_done().await); } + + #[tokio::test] + async fn test_session_params() { + let session_id = 0x123; + let session_type = SessionType::FiraRangingSession; + + let params = generate_params(); + let tlvs = params.generate_tlvs(); + + let (mut session_manager, mut mock_uci_manager, _) = + setup_session_manager(move |uci_manager| { + uci_manager.expect_session_init( + session_id, + session_type, + vec![session_status_notf(session_id, SessionState::SessionStateInit)], + Ok(()), + ); + uci_manager.expect_session_set_app_config( + session_id, + tlvs, + vec![session_status_notf(session_id, SessionState::SessionStateIdle)], + Ok(SetAppConfigResponse { + status: StatusCode::UciStatusOk, + config_status: vec![], + }), + ); + }) + .await; + + // Getting session params without initing a session should fail + let result = session_manager.session_params(session_id).await; + assert_eq!(result, Err(Error::BadParameters)); + + let result = session_manager.init_session(session_id, session_type, params.clone()).await; + result.unwrap(); + + // Getting session params after they've been properly set should succeed + let result = session_manager.session_params(session_id).await; + assert_eq!(result, Ok(params)); + + assert!(mock_uci_manager.wait_expected_calls_done().await); + } } diff --git a/src/rust/uwb_core/src/session/uwb_session.rs b/src/rust/uwb_core/src/session/uwb_session.rs index a536b65..bb0a42c 100644 --- a/src/rust/uwb_core/src/session/uwb_session.rs +++ b/src/rust/uwb_core/src/session/uwb_session.rs @@ -102,6 +102,10 @@ impl UwbSession { )); } + pub fn params(&mut self, result_sender: ResponseSender) { + let _ = self.cmd_sender.send((Command::GetParams, result_sender)); + } + pub fn on_session_status_changed(&mut self, state: SessionState) { let _ = self.state_sender.send(state); } @@ -160,7 +164,8 @@ impl<T: UciManager> UwbSessionActor<T> { notf_receiver, ) .await - } + }, + Command::GetParams => self.params().await, }; let _ = result_sender.send(result); } @@ -352,6 +357,13 @@ impl<T: UciManager> UwbSessionActor<T> { Ok(()) } + + async fn params(&mut self) -> Result<Response> { + match &self.params { + None => Err(Error::BadParameters), + Some(params) => Ok(Response::AppConfigParams(params.clone())), + } + } } enum Command { @@ -369,4 +381,5 @@ enum Command { controlees: Vec<Controlee>, notf_receiver: oneshot::Receiver<Vec<ControleeStatus>>, }, + GetParams, } diff --git a/src/rust/uwb_core/src/uci.rs b/src/rust/uwb_core/src/uci.rs index 326fb15..5d21432 100644 --- a/src/rust/uwb_core/src/uci.rs +++ b/src/rust/uwb_core/src/uci.rs @@ -32,7 +32,8 @@ pub(crate) mod mock_uci_hal; pub(crate) mod mock_uci_manager; // Re-export the public elements. +pub use command::UciCommand; pub use notification::{ CoreNotification, RangingMeasurements, SessionNotification, SessionRangeData, UciNotification, }; -pub use uci_hal::{RawUciMessage, UciHal}; +pub use uci_hal::{UciHal, UciHalPacket}; diff --git a/src/rust/uwb_core/src/uci/command.rs b/src/rust/uwb_core/src/uci/command.rs index f395555..61ccc83 100644 --- a/src/rust/uwb_core/src/uci/command.rs +++ b/src/rust/uwb_core/src/uci/command.rs @@ -24,8 +24,10 @@ use crate::params::uci_packets::{ ResetConfig, SessionId, SessionType, UpdateMulticastListAction, }; -#[derive(Debug, Clone)] -pub(super) enum UciCommand { +/// The enum to represent the UCI commands. The definition of each field should follow UCI spec. +#[allow(missing_docs)] +#[derive(Debug, Clone, PartialEq)] +pub enum UciCommand { DeviceReset { reset_config: ResetConfig, }, 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 e7fe037..eb27e00 100644 --- a/src/rust/uwb_core/src/uci/mock_uci_hal.rs +++ b/src/rust/uwb_core/src/uci/mock_uci_hal.rs @@ -22,12 +22,13 @@ use tokio::time::timeout; use crate::error::{Error, Result}; use crate::params::uci_packets::SessionId; -use crate::uci::uci_hal::{RawUciMessage, UciHal}; +use crate::uci::command::UciCommand; +use crate::uci::uci_hal::{UciHal, UciHalPacket}; /// The mock implementation of UciHal. #[derive(Default, Clone)] pub struct MockUciHal { - msg_sender: Option<mpsc::UnboundedSender<RawUciMessage>>, + packet_sender: Option<mpsc::UnboundedSender<UciHalPacket>>, expected_calls: Arc<Mutex<VecDeque<ExpectedCall>>>, expect_call_consumed: Arc<Notify>, } @@ -37,8 +38,8 @@ impl MockUciHal { Default::default() } - pub fn expected_open(&mut self, msgs: Option<Vec<RawUciMessage>>, out: Result<()>) { - self.expected_calls.lock().unwrap().push_back(ExpectedCall::Open { msgs, out }); + pub fn expected_open(&mut self, packets: Option<Vec<UciHalPacket>>, out: Result<()>) { + self.expected_calls.lock().unwrap().push_back(ExpectedCall::Open { packets, out }); } pub fn expected_close(&mut self, out: Result<()>) { @@ -47,13 +48,13 @@ impl MockUciHal { pub fn expected_send_command( &mut self, - expected_cmd: RawUciMessage, - msgs: Vec<RawUciMessage>, + expected_cmd: UciCommand, + packets: Vec<UciHalPacket>, out: Result<()>, ) { self.expected_calls.lock().unwrap().push_back(ExpectedCall::SendCommand { expected_cmd, - msgs, + packets, out, }); } @@ -82,18 +83,18 @@ impl MockUciHal { #[async_trait] impl UciHal for MockUciHal { - async fn open(&mut self, msg_sender: mpsc::UnboundedSender<RawUciMessage>) -> Result<()> { + async fn open(&mut self, packet_sender: mpsc::UnboundedSender<UciHalPacket>) -> Result<()> { let mut expected_calls = self.expected_calls.lock().unwrap(); match expected_calls.pop_front() { - Some(ExpectedCall::Open { msgs, out }) => { + Some(ExpectedCall::Open { packets, out }) => { self.expect_call_consumed.notify_one(); - if let Some(msgs) = msgs { - for msg in msgs.into_iter() { - let _ = msg_sender.send(msg); + if let Some(packets) = packets { + for msg in packets.into_iter() { + let _ = packet_sender.send(msg); } } if out.is_ok() { - self.msg_sender.replace(msg_sender); + self.packet_sender.replace(packet_sender); } out } @@ -111,7 +112,7 @@ impl UciHal for MockUciHal { Some(ExpectedCall::Close { out }) => { self.expect_call_consumed.notify_one(); if out.is_ok() { - self.msg_sender = None; + self.packet_sender = None; } out } @@ -123,14 +124,16 @@ impl UciHal for MockUciHal { } } - async fn send_command(&mut self, cmd: RawUciMessage) -> Result<()> { + async fn send_command(&mut self, cmd: UciCommand) -> Result<()> { let mut expected_calls = self.expected_calls.lock().unwrap(); match expected_calls.pop_front() { - Some(ExpectedCall::SendCommand { expected_cmd, msgs, out }) if expected_cmd == cmd => { + Some(ExpectedCall::SendCommand { expected_cmd, packets, out }) + if expected_cmd == cmd => + { self.expect_call_consumed.notify_one(); - let msg_sender = self.msg_sender.as_mut().unwrap(); - for msg in msgs.into_iter() { - let _ = msg_sender.send(msg); + let packet_sender = self.packet_sender.as_mut().unwrap(); + for msg in packets.into_iter() { + let _ = packet_sender.send(msg); } out } @@ -142,6 +145,11 @@ 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 notify_session_initialized(&mut self, session_id: SessionId) -> Result<()> { let mut expected_calls = self.expected_calls.lock().unwrap(); match expected_calls.pop_front() { @@ -161,8 +169,8 @@ impl UciHal for MockUciHal { } enum ExpectedCall { - Open { msgs: Option<Vec<RawUciMessage>>, out: Result<()> }, + Open { packets: Option<Vec<UciHalPacket>>, out: Result<()> }, Close { out: Result<()> }, - SendCommand { expected_cmd: RawUciMessage, msgs: Vec<RawUciMessage>, out: Result<()> }, + SendCommand { expected_cmd: UciCommand, packets: Vec<UciHalPacket>, out: Result<()> }, NotifySessionInitialized { expected_session_id: SessionId, out: Result<()> }, } 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 e1bdcb4..9a660ff 100644 --- a/src/rust/uwb_core/src/uci/timeout_uci_hal.rs +++ b/src/rust/uwb_core/src/uci/timeout_uci_hal.rs @@ -21,7 +21,8 @@ use tokio::time::timeout; use crate::error::{Error, Result}; use crate::params::uci_packets::SessionId; -use crate::uci::uci_hal::{RawUciMessage, UciHal}; +use crate::uci::command::UciCommand; +use crate::uci::uci_hal::{UciHal, UciHalPacket}; const HAL_API_TIMEOUT_MS: u64 = 800; @@ -42,8 +43,8 @@ impl<T: UciHal> TimeoutUciHal<T> { #[async_trait] impl<T: UciHal> UciHal for TimeoutUciHal<T> { - async fn open(&mut self, msg_sender: mpsc::UnboundedSender<RawUciMessage>) -> Result<()> { - Self::call_with_timeout(self.0.open(msg_sender)).await + async fn open(&mut self, packet_sender: mpsc::UnboundedSender<UciHalPacket>) -> Result<()> { + Self::call_with_timeout(self.0.open(packet_sender)).await } async fn close(&mut self) -> Result<()> { @@ -54,9 +55,13 @@ impl<T: UciHal> UciHal for TimeoutUciHal<T> { Self::call_with_timeout(self.0.notify_session_initialized(session_id)).await } - async fn send_command(&mut self, cmd: RawUciMessage) -> Result<()> { + async fn send_command(&mut self, cmd: UciCommand) -> Result<()> { Self::call_with_timeout(self.0.send_command(cmd)).await } + + async fn send_packet(&mut self, packet: UciHalPacket) -> Result<()> { + Self::call_with_timeout(self.0.send_packet(packet)).await + } } #[cfg(test)] @@ -73,13 +78,13 @@ mod tests { #[async_trait] impl UciHal for FakeUciHal { - async fn open(&mut self, _: mpsc::UnboundedSender<RawUciMessage>) -> Result<()> { + async fn open(&mut self, _: mpsc::UnboundedSender<UciHalPacket>) -> Result<()> { Ok(()) } async fn close(&mut self) -> Result<()> { Err(Error::Unknown) } - async fn send_command(&mut self, _: RawUciMessage) -> Result<()> { + async fn send_packet(&mut self, _: UciHalPacket) -> Result<()> { sleep(Duration::MAX).await; Ok(()) } @@ -110,6 +115,6 @@ mod tests { let mut hal = setup_hal(); let cmd = vec![]; - assert!(matches!(hal.send_command(cmd).await, Err(Error::Timeout))); + assert!(matches!(hal.send_packet(cmd).await, Err(Error::Timeout))); } } diff --git a/src/rust/uwb_core/src/uci/uci_hal.rs b/src/rust/uwb_core/src/uci/uci_hal.rs index c48416a..aaf6d22 100644 --- a/src/rust/uwb_core/src/uci/uci_hal.rs +++ b/src/rust/uwb_core/src/uci/uci_hal.rs @@ -14,14 +14,19 @@ //! This module defines the UciHal trait, used for the UCI hardware abstration layer. +use std::convert::TryInto; + use async_trait::async_trait; use tokio::sync::mpsc; +use uwb_uci_packets::{Packet, UciCommandPacket, UciPacketHalPacket, UciPacketPacket}; use crate::error::Result; use crate::params::uci_packets::SessionId; +use crate::uci::command::UciCommand; -/// The type of the message that is used to communicate with the UciHal trait. -pub type RawUciMessage = Vec<u8>; +/// The byte buffer of a UCI packet that is used to communicate with the UciHal trait. +/// The format of the byte buffer should follow the UCI packet spec. +pub type UciHalPacket = Vec<u8>; /// The trait for the UCI hardware abstration layer. The client of this library should implement /// this trait and inject into the library. @@ -31,23 +36,70 @@ pub trait UciHal: 'static + Send { /// Open the UCI HAL and power on the UWB Subsystem. /// /// All the other API should be called after the open() completes successfully. Once the method - /// completes successfully, the UciHal instance should store |msg_sender| and send the UCI - /// messages (responses or notifications) back to the caller via the |msg_sender|. - async fn open(&mut self, msg_sender: mpsc::UnboundedSender<RawUciMessage>) -> Result<()>; + /// 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|. + async fn open(&mut self, packet_sender: mpsc::UnboundedSender<UciHalPacket>) -> Result<()>; /// Close the UCI HAL. /// - /// After calling this method, the instance would drop |msg_sender| received from open() method. + /// After calling this method, the instance would drop |packet_sender| received from open() + /// method. async fn close(&mut self) -> Result<()>; /// Write the UCI command to the UWB Subsystem. /// /// The caller should call this method after the response of the previous send_command() is /// received. - async fn send_command(&mut self, cmd: RawUciMessage) -> Result<()>; + async fn send_command(&mut self, cmd: UciCommand) -> Result<()> { + // 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(); + for packet in fragmented_packets.into_iter() { + self.send_packet(packet.to_vec()).await?; + } + Ok(()) + } + + /// Write the UCI packet to the UWB Subsystem. + async fn send_packet(&mut self, packet: UciHalPacket) -> Result<()>; /// Notify the HAL that the UWB session is initialized successfully. async fn notify_session_initialized(&mut self, _session_id: SessionId) -> Result<()> { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + + struct MockUciHal { + pub packets: Vec<UciHalPacket>, + } + + #[async_trait] + impl UciHal for MockUciHal { + async fn open(&mut self, _: mpsc::UnboundedSender<UciHalPacket>) -> Result<()> { + Ok(()) + } + async fn close(&mut self) -> Result<()> { + Ok(()) + } + async fn send_packet(&mut self, packet: UciHalPacket) -> Result<()> { + self.packets.push(packet); + Ok(()) + } + } + + // Verify if UciHal::send_command() split the packets correctly. + #[tokio::test] + async fn test_send_command() { + let mut hal = MockUciHal { packets: vec![] }; + let _ = hal.send_command(UciCommand::CoreGetDeviceInfo).await; + let expected_packets = vec![vec![0x20, 0x02, 0x00, 0x00]]; + assert_eq!(hal.packets, expected_packets); + } +} diff --git a/src/rust/uwb_core/src/uci/uci_manager.rs b/src/rust/uwb_core/src/uci/uci_manager.rs index b86f862..e9504c8 100644 --- a/src/rust/uwb_core/src/uci/uci_manager.rs +++ b/src/rust/uwb_core/src/uci/uci_manager.rs @@ -18,7 +18,6 @@ use std::time::Duration; use async_trait::async_trait; use log::{debug, error, warn}; use tokio::sync::{mpsc, oneshot}; -use uwb_uci_packets::{Packet, UciCommandPacket}; use crate::uci::command::UciCommand; //use crate::uci::error::{Error, Result}; @@ -33,7 +32,7 @@ use crate::uci::message::UciMessage; use crate::uci::notification::{CoreNotification, SessionNotification, UciNotification}; use crate::uci::response::UciResponse; use crate::uci::timeout_uci_hal::TimeoutUciHal; -use crate::uci::uci_hal::{RawUciMessage, UciHal}; +use crate::uci::uci_hal::{UciHal, UciHalPacket}; use crate::utils::PinSleep; const UCI_TIMEOUT_MS: u64 = 800; @@ -172,7 +171,15 @@ impl UciManager for UciManagerImpl { async fn open_hal(&mut self) -> Result<()> { match self.send_cmd(UciManagerCmd::OpenHal).await { - Ok(UciResponse::OpenHal) => Ok(()), + Ok(UciResponse::OpenHal) => { + // According to the UCI spec: "The Host shall send CORE_GET_DEVICE_INFO_CMD to + // retrieve the device information.", we call get_device_info() after successfully + // opening the HAL. + let device_info = self.core_get_device_info().await; + debug!("UCI device info: {:?}", device_info); + + Ok(()) + } Ok(_) => Err(Error::Unknown), Err(e) => Err(e), } @@ -392,7 +399,7 @@ struct UciManagerActor<T: UciHal> { is_hal_opened: bool, // Receive the response and the notification from |hal|. Only used when |hal| is opened // successfully. - msg_receiver: mpsc::UnboundedReceiver<RawUciMessage>, + packet_receiver: mpsc::UnboundedReceiver<UciHalPacket>, // Defrag the UCI packets. defrager: uwb_uci_packets::PacketDefrager, @@ -427,7 +434,7 @@ impl<T: UciHal> UciManagerActor<T> { hal: TimeoutUciHal::new(hal), cmd_receiver, is_hal_opened: false, - msg_receiver: mpsc::unbounded_channel().1, + packet_receiver: mpsc::unbounded_channel().1, defrager: Default::default(), open_hal_result_sender: None, wait_device_status_timeout: PinSleep::new(Duration::MAX), @@ -457,14 +464,14 @@ impl<T: UciHal> UciManagerActor<T> { } // Handle the UCI response or notification from HAL. Only when HAL is opened. - msg = self.msg_receiver.recv(), if self.is_hal_opened => { - match msg { + packet = self.packet_receiver.recv(), if self.is_hal_opened => { + match packet { None => { - warn!("UciHal dropped the msg_sender unexpectedly."); + warn!("UciHal dropped the packet_sender unexpectedly."); self.on_hal_closed(); }, - Some(msg) => { - if let Some(packet) = self.defrager.defragment_packet(&msg) { + Some(packet) => { + if let Some(packet) = self.defrager.defragment_packet(&packet) { match packet.try_into() { Ok(UciMessage::Response(resp)) => { self.handle_response(resp).await; @@ -529,10 +536,10 @@ impl<T: UciHal> UciManagerActor<T> { return; } - let (msg_sender, msg_receiver) = mpsc::unbounded_channel(); - match self.hal.open(msg_sender).await { + let (packet_sender, packet_receiver) = mpsc::unbounded_channel(); + match self.hal.open(packet_sender).await { Ok(()) => { - self.on_hal_open(msg_receiver); + self.on_hal_open(packet_receiver); self.wait_device_status_timeout = PinSleep::new(Duration::from_millis(UCI_TIMEOUT_MS)); self.open_hal_result_sender.replace(result_sender); @@ -598,9 +605,7 @@ impl<T: UciHal> UciManagerActor<T> { return Err(Error::BadParameters); } - let packet = TryInto::<UciCommandPacket>::try_into(cmd)?; - self.hal.send_command(packet.to_vec()).await?; - Ok(()) + self.hal.send_command(cmd).await } async fn handle_response(&mut self, resp: UciResponse) { @@ -656,14 +661,14 @@ impl<T: UciHal> UciManagerActor<T> { } } - fn on_hal_open(&mut self, msg_receiver: mpsc::UnboundedReceiver<RawUciMessage>) { + fn on_hal_open(&mut self, packet_receiver: mpsc::UnboundedReceiver<UciHalPacket>) { self.is_hal_opened = true; - self.msg_receiver = msg_receiver; + self.packet_receiver = packet_receiver; } fn on_hal_closed(&mut self) { self.is_hal_opened = false; - self.msg_receiver = mpsc::unbounded_channel().1; + self.packet_receiver = mpsc::unbounded_channel().1; } fn is_waiting_resp(&self) -> bool { @@ -709,29 +714,43 @@ mod tests { use super::*; use bytes::Bytes; - use num_traits::ToPrimitive; use crate::params::uci_packets::{CapTlvType, StatusCode}; use crate::uci::mock_uci_hal::MockUciHal; use crate::utils::init_test_logging; - fn into_raw_messages<T: Into<uwb_uci_packets::UciPacketPacket>>( + fn into_uci_hal_packets<T: Into<uwb_uci_packets::UciPacketPacket>>( builder: T, - ) -> Vec<RawUciMessage> { + ) -> Vec<UciHalPacket> { let packets: Vec<uwb_uci_packets::UciPacketHalPacket> = builder.into().into(); packets.into_iter().map(|packet| packet.into()).collect() } - async fn setup_uci_manager_with_open_hal( - setup_hal_fn: fn(&mut MockUciHal), - ) -> (UciManagerImpl, MockUciHal) { + async fn setup_uci_manager_with_open_hal<F>(setup_hal_fn: F) -> (UciManagerImpl, MockUciHal) + where + F: FnOnce(&mut MockUciHal), + { init_test_logging(); + // Open the hal. let mut hal = MockUciHal::new(); - let notf = into_raw_messages(uwb_uci_packets::DeviceStatusNtfBuilder { + let notf = into_uci_hal_packets(uwb_uci_packets::DeviceStatusNtfBuilder { device_state: uwb_uci_packets::DeviceState::DeviceStateReady, }); hal.expected_open(Some(notf), Ok(())); + + // Get the device info. + let cmd = UciCommand::CoreGetDeviceInfo; + let resp = into_uci_hal_packets(uwb_uci_packets::GetDeviceInfoRspBuilder { + status: uwb_uci_packets::StatusCode::UciStatusOk, + uci_version: 0x1234, + mac_version: 0x5678, + phy_version: 0x90ab, + uci_test_version: 0x1357, + vendor_spec_info: vec![0x1, 0x2], + }); + hal.expected_send_command(cmd, resp, Ok(())); + setup_hal_fn(&mut hal); // Verify open_hal() is working. @@ -794,12 +813,8 @@ mod tests { #[tokio::test] async fn test_device_reset_ok() { let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let cmd = uwb_uci_packets::DeviceResetCmdBuilder { - reset_config: uwb_uci_packets::ResetConfig::UwbsReset, - } - .build() - .into(); - let resp = into_raw_messages(uwb_uci_packets::DeviceResetRspBuilder { + let cmd = UciCommand::DeviceReset { reset_config: ResetConfig::UwbsReset }; + let resp = into_uci_hal_packets(uwb_uci_packets::DeviceResetRspBuilder { status: uwb_uci_packets::StatusCode::UciStatusOk, }); @@ -814,15 +829,23 @@ mod tests { #[tokio::test] async fn test_core_get_device_info_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let cmd = uwb_uci_packets::GetDeviceInfoCmdBuilder {}.build().into(); - let resp = into_raw_messages(uwb_uci_packets::GetDeviceInfoRspBuilder { - status: uwb_uci_packets::StatusCode::UciStatusOk, - uci_version: 0x1234, - mac_version: 0x5678, - phy_version: 0x90ab, - uci_test_version: 0x1357, - vendor_spec_info: vec![0x1, 0x2], + let status = StatusCode::UciStatusOk; + let uci_version = 0x1234; + let mac_version = 0x5678; + let phy_version = 0x90ab; + let uci_test_version = 0x1357; + 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(move |hal| { + let cmd = UciCommand::CoreGetDeviceInfo; + let resp = into_uci_hal_packets(uwb_uci_packets::GetDeviceInfoRspBuilder { + status, + uci_version, + mac_version, + phy_version, + uci_test_version, + vendor_spec_info: vendor_spec_info_clone, }); hal.expected_send_command(cmd, resp, Ok(())); @@ -830,11 +853,11 @@ mod tests { .await; let expected_result = GetDeviceInfoResponse { - uci_version: 0x1234, - mac_version: 0x5678, - phy_version: 0x90ab, - uci_test_version: 0x1357, - vendor_spec_info: vec![0x1, 0x2], + uci_version, + mac_version, + phy_version, + uci_test_version, + vendor_spec_info, }; let result = uci_manager.core_get_device_info().await.unwrap(); assert_eq!(result, expected_result); @@ -843,22 +866,20 @@ mod tests { #[tokio::test] async fn test_core_get_caps_info_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let tlv = uwb_uci_packets::CapTlv { - t: uwb_uci_packets::CapTlvType::SupportedFiraPhyVersionRange, - v: vec![0x12, 0x34, 0x56], - }; - let cmd = uwb_uci_packets::GetCapsInfoCmdBuilder {}.build().into(); - let resp = into_raw_messages(uwb_uci_packets::GetCapsInfoRspBuilder { + 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(move |hal| { + let cmd = UciCommand::CoreGetCapsInfo; + let resp = into_uci_hal_packets(uwb_uci_packets::GetCapsInfoRspBuilder { status: uwb_uci_packets::StatusCode::UciStatusOk, - tlvs: vec![tlv], + tlvs: vec![tlv_clone], }); hal.expected_send_command(cmd, resp, Ok(())); }) .await; - let tlv = CapTlv { t: CapTlvType::SupportedFiraPhyVersionRange, v: vec![0x12, 0x34, 0x56] }; let result = uci_manager.core_get_caps_info().await.unwrap(); assert_eq!(result[0], tlv); assert!(mock_hal.wait_expected_calls_done().await); @@ -866,73 +887,66 @@ mod tests { #[tokio::test] async fn test_core_set_config_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let tlv = uwb_uci_packets::DeviceConfigTlv { - cfg_id: uwb_uci_packets::DeviceConfigId::DeviceState, - v: vec![0x12, 0x34, 0x56], - }; - let cmd = uwb_uci_packets::SetConfigCmdBuilder { tlvs: vec![tlv] }.build().into(); - let resp = into_raw_messages(uwb_uci_packets::SetConfigRspBuilder { - status: uwb_uci_packets::StatusCode::UciStatusOk, - cfg_status: vec![], + let tlv = DeviceConfigTlv { + cfg_id: uwb_uci_packets::DeviceConfigId::DeviceState, + v: vec![0x12, 0x34, 0x56], + }; + let tlv_clone = tlv.clone(); + let status = StatusCode::UciStatusOk; + let config_status = vec![]; + let config_status_clone = config_status.clone(); + + let (mut 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 { + status, + cfg_status: config_status_clone, }); hal.expected_send_command(cmd, resp, Ok(())); }) .await; - let config_tlv = - DeviceConfigTlv { cfg_id: DeviceConfigId::DeviceState, v: vec![0x12, 0x34, 0x56] }; - let expected_result = - CoreSetConfigResponse { status: StatusCode::UciStatusOk, config_status: vec![] }; - let result = uci_manager.core_set_config(vec![config_tlv]).await.unwrap(); + let expected_result = CoreSetConfigResponse { status, config_status }; + let result = uci_manager.core_set_config(vec![tlv]).await.unwrap(); assert_eq!(result, expected_result); assert!(mock_hal.wait_expected_calls_done().await); } #[tokio::test] async fn test_core_get_config_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let cfg_id = uwb_uci_packets::DeviceConfigId::DeviceState; - let tlv = uwb_uci_packets::DeviceConfigTlv { cfg_id, v: vec![0x12, 0x34, 0x56] }; - let cmd = - uwb_uci_packets::GetConfigCmdBuilder { cfg_id: vec![cfg_id.to_u8().unwrap()] } - .build() - .into(); - let resp = into_raw_messages(uwb_uci_packets::GetConfigRspBuilder { + let cfg_id = DeviceConfigId::DeviceState; + 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(move |hal| { + let cmd = UciCommand::CoreGetConfig { cfg_id: vec![cfg_id] }; + let resp = into_uci_hal_packets(uwb_uci_packets::GetConfigRspBuilder { status: uwb_uci_packets::StatusCode::UciStatusOk, - tlvs: vec![tlv], + tlvs: vec![tlv_clone], }); hal.expected_send_command(cmd, resp, Ok(())); }) .await; - let config_id = DeviceConfigId::DeviceState; - let expected_result = vec![DeviceConfigTlv { - cfg_id: DeviceConfigId::DeviceState, - v: vec![0x12, 0x34, 0x56], - }]; - CoreSetConfigResponse { status: StatusCode::UciStatusOk, config_status: vec![] }; - let result = uci_manager.core_get_config(vec![config_id]).await.unwrap(); + let expected_result = vec![tlv]; + let result = uci_manager.core_get_config(vec![cfg_id]).await.unwrap(); assert_eq!(result, expected_result); assert!(mock_hal.wait_expected_calls_done().await); } #[tokio::test] async fn test_session_init_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let session_id = 0x123; - let cmd = uwb_uci_packets::SessionInitCmdBuilder { - session_id, - session_type: uwb_uci_packets::SessionType::FiraRangingSession, - } - .build() - .into(); - let mut resp = into_raw_messages(uwb_uci_packets::SessionInitRspBuilder { + 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_raw_messages(uwb_uci_packets::SessionStatusNtfBuilder { + 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, @@ -944,8 +958,6 @@ mod tests { }) .await; - let session_id = 0x123; - let session_type = SessionType::FiraRangingSession; let result = uci_manager.session_init(session_id, session_type).await; assert!(result.is_ok()); assert!(mock_hal.wait_expected_calls_done().await); @@ -953,9 +965,11 @@ mod tests { #[tokio::test] async fn test_session_deinit_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let cmd = uwb_uci_packets::SessionDeinitCmdBuilder { session_id: 0x123 }.build().into(); - let resp = into_raw_messages(uwb_uci_packets::SessionDeinitRspBuilder { + let session_id = 0x123; + + let (mut 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 { status: uwb_uci_packets::StatusCode::UciStatusOk, }); @@ -963,7 +977,6 @@ mod tests { }) .await; - let session_id = 0x123; let result = uci_manager.session_deinit(session_id).await; assert!(result.is_ok()); assert!(mock_hal.wait_expected_calls_done().await); @@ -971,18 +984,15 @@ mod tests { #[tokio::test] async fn test_session_set_app_config_ok() { + let session_id = 0x123; + let config_tlv = + AppConfigTlv { cfg_id: AppConfigTlvType::DeviceType, v: vec![0x12, 0x34, 0x56] }; + let config_tlv_clone = config_tlv.clone(); + let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let tlv = uwb_uci_packets::AppConfigTlv { - cfg_id: uwb_uci_packets::AppConfigTlvType::DeviceType, - v: vec![0x12, 0x34, 0x56], - }; - let cmd = uwb_uci_packets::SessionSetAppConfigCmdBuilder { - session_id: 0x123, - tlvs: vec![tlv], - } - .build() - .into(); - let resp = into_raw_messages(uwb_uci_packets::SessionSetAppConfigRspBuilder { + let cmd = + UciCommand::SessionSetAppConfig { session_id, config_tlvs: vec![config_tlv_clone] }; + let resp = into_uci_hal_packets(uwb_uci_packets::SessionSetAppConfigRspBuilder { status: uwb_uci_packets::StatusCode::UciStatusOk, cfg_status: vec![], }); @@ -991,9 +1001,6 @@ mod tests { }) .await; - let session_id = 0x123; - let config_tlv = - AppConfigTlv { cfg_id: AppConfigTlvType::DeviceType, v: vec![0x12, 0x34, 0x56] }; let expected_result = SetAppConfigResponse { status: StatusCode::UciStatusOk, config_status: vec![] }; let result = @@ -1004,28 +1011,23 @@ mod tests { #[tokio::test] async fn test_session_get_app_config_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let cfg_id = uwb_uci_packets::AppConfigTlvType::DeviceType; - let tlv = uwb_uci_packets::AppConfigTlv { cfg_id, v: vec![0x12, 0x34, 0x56] }; - let cmd = uwb_uci_packets::SessionGetAppConfigCmdBuilder { - session_id: 0x123, - app_cfg: vec![cfg_id.to_u8().unwrap()], - } - .build() - .into(); - let resp = into_raw_messages(uwb_uci_packets::SessionGetAppConfigRspBuilder { + let session_id = 0x123; + let config_id = AppConfigTlvType::DeviceType; + let tlv = AppConfigTlv { cfg_id: AppConfigTlvType::DeviceType, v: vec![0x12, 0x34, 0x56] }; + let tlv_clone = tlv.clone(); + + let (mut 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 { status: uwb_uci_packets::StatusCode::UciStatusOk, - tlvs: vec![tlv], + tlvs: vec![tlv_clone], }); hal.expected_send_command(cmd, resp, Ok(())); }) .await; - let session_id = 0x123; - let config_id = AppConfigTlvType::DeviceType; - let expected_result = - vec![AppConfigTlv { cfg_id: AppConfigTlvType::DeviceType, v: vec![0x12, 0x34, 0x56] }]; + let expected_result = vec![tlv]; let result = uci_manager.session_get_app_config(session_id, vec![config_id]).await.unwrap(); assert_eq!(result, expected_result); assert!(mock_hal.wait_expected_calls_done().await); @@ -1033,11 +1035,13 @@ mod tests { #[tokio::test] async fn test_session_get_count_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let cmd = uwb_uci_packets::SessionGetCountCmdBuilder {}.build().into(); - let resp = into_raw_messages(uwb_uci_packets::SessionGetCountRspBuilder { + let session_count = 5; + + let (mut 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 { status: uwb_uci_packets::StatusCode::UciStatusOk, - session_count: 5, + session_count, }); hal.expected_send_command(cmd, resp, Ok(())); @@ -1045,43 +1049,45 @@ mod tests { .await; let result = uci_manager.session_get_count().await.unwrap(); - assert_eq!(result, 5); + assert_eq!(result, session_count); assert!(mock_hal.wait_expected_calls_done().await); } #[tokio::test] async fn test_session_get_state_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let cmd = - uwb_uci_packets::SessionGetStateCmdBuilder { session_id: 0x123 }.build().into(); - let resp = into_raw_messages(uwb_uci_packets::SessionGetStateRspBuilder { + let session_id = 0x123; + let session_state = SessionState::SessionStateActive; + + let (mut 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 { status: uwb_uci_packets::StatusCode::UciStatusOk, - session_state: uwb_uci_packets::SessionState::SessionStateActive, + session_state, }); hal.expected_send_command(cmd, resp, Ok(())); }) .await; - let session_id = 0x123; let result = uci_manager.session_get_state(session_id).await.unwrap(); - assert_eq!(result, SessionState::SessionStateActive); + assert_eq!(result, session_state); assert!(mock_hal.wait_expected_calls_done().await); } #[tokio::test] async fn test_session_update_controller_multicast_list_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let controlee = - uwb_uci_packets::Controlee { short_address: 0x4567, subsession_id: 0x90ab }; - let cmd = uwb_uci_packets::SessionUpdateControllerMulticastListCmdBuilder { - session_id: 0x123, - action: UpdateMulticastListAction::AddControlee, - controlees: vec![controlee], - } - .build() - .into(); - let resp = into_raw_messages( + let session_id = 0x123; + let action = UpdateMulticastListAction::AddControlee; + 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(move |hal| { + let cmd = UciCommand::SessionUpdateControllerMulticastList { + session_id, + action, + controlees: vec![controlee_clone], + }; + let resp = into_uci_hal_packets( uwb_uci_packets::SessionUpdateControllerMulticastListRspBuilder { status: uwb_uci_packets::StatusCode::UciStatusOk, }, @@ -1091,9 +1097,6 @@ mod tests { }) .await; - let session_id = 0x123; - let action = UpdateMulticastListAction::AddControlee; - let controlee = Controlee { short_address: 0x4567, subsession_id: 0x90ab }; let result = uci_manager .session_update_controller_multicast_list(session_id, action, vec![controlee]) .await; @@ -1103,9 +1106,11 @@ mod tests { #[tokio::test] async fn test_range_start_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let cmd = uwb_uci_packets::RangeStartCmdBuilder { session_id: 0x123 }.build().into(); - let resp = into_raw_messages(uwb_uci_packets::RangeStartRspBuilder { + let session_id = 0x123; + + let (mut 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 { status: uwb_uci_packets::StatusCode::UciStatusOk, }); @@ -1113,7 +1118,6 @@ mod tests { }) .await; - let session_id = 0x123; let result = uci_manager.range_start(session_id).await; assert!(result.is_ok()); assert!(mock_hal.wait_expected_calls_done().await); @@ -1121,9 +1125,11 @@ mod tests { #[tokio::test] async fn test_range_stop_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let cmd = uwb_uci_packets::RangeStopCmdBuilder { session_id: 0x123 }.build().into(); - let resp = into_raw_messages(uwb_uci_packets::RangeStopRspBuilder { + let session_id = 0x123; + + let (mut 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 { status: uwb_uci_packets::StatusCode::UciStatusOk, }); @@ -1131,7 +1137,6 @@ mod tests { }) .await; - let session_id = 0x123; let result = uci_manager.range_stop(session_id).await; assert!(result.is_ok()); assert!(mock_hal.wait_expected_calls_done().await); @@ -1139,33 +1144,33 @@ mod tests { #[tokio::test] async fn test_range_get_ranging_count_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let cmd = uwb_uci_packets::RangeGetRangingCountCmdBuilder { session_id: 0x123 } - .build() - .into(); - let resp = into_raw_messages(uwb_uci_packets::RangeGetRangingCountRspBuilder { + let session_id = 0x123; + let count = 3; + + let (mut 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: 3, + count, }); hal.expected_send_command(cmd, resp, Ok(())); }) .await; - let session_id = 0x123; let result = uci_manager.range_get_ranging_count(session_id).await.unwrap(); - assert_eq!(result, 3); + assert_eq!(result, count as usize); assert!(mock_hal.wait_expected_calls_done().await); } #[tokio::test] async fn test_android_set_country_code_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let cmd = - uwb_uci_packets::AndroidSetCountryCodeCmdBuilder { country_code: b"US".to_owned() } - .build() - .into(); - let resp = into_raw_messages(uwb_uci_packets::AndroidSetCountryCodeRspBuilder { + 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(move |hal| { + let cmd = UciCommand::AndroidSetCountryCode { country_code: country_code_clone }; + let resp = into_uci_hal_packets(uwb_uci_packets::AndroidSetCountryCodeRspBuilder { status: uwb_uci_packets::StatusCode::UciStatusOk, }); @@ -1173,7 +1178,6 @@ mod tests { }) .await; - let country_code = CountryCode::new(b"US").unwrap(); let result = uci_manager.android_set_country_code(country_code).await; assert!(result.is_ok()); assert!(mock_hal.wait_expected_calls_done().await); @@ -1181,57 +1185,52 @@ mod tests { #[tokio::test] async fn test_android_get_power_stats_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let cmd = uwb_uci_packets::AndroidGetPowerStatsCmdBuilder {}.build().into(); - let resp = into_raw_messages(uwb_uci_packets::AndroidGetPowerStatsRspBuilder { - stats: uwb_uci_packets::PowerStats { - status: uwb_uci_packets::StatusCode::UciStatusOk, - idle_time_ms: 123, - tx_time_ms: 456, - rx_time_ms: 789, - total_wake_count: 5, - }, - }); - - hal.expected_send_command(cmd, resp, Ok(())); - }) - .await; - - let expected_result = PowerStats { + let power_stats = PowerStats { status: StatusCode::UciStatusOk, idle_time_ms: 123, tx_time_ms: 456, rx_time_ms: 789, total_wake_count: 5, }; + let power_stats_clone = power_stats.clone(); + + let (mut 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 { + stats: power_stats_clone, + }); + + hal.expected_send_command(cmd, resp, Ok(())); + }) + .await; + let result = uci_manager.android_get_power_stats().await.unwrap(); - assert_eq!(result, expected_result); + assert_eq!(result, power_stats); assert!(mock_hal.wait_expected_calls_done().await); } #[tokio::test] async fn test_raw_vendor_cmd_ok() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let cmd = uwb_uci_packets::UciVendor_F_CommandBuilder { - opcode: 0x3, - payload: Some(Bytes::from(vec![0x11, 0x22, 0x33, 0x44])), - } - .build() - .into(); - let resp = into_raw_messages(uwb_uci_packets::UciVendor_F_ResponseBuilder { - opcode: 0x3, - payload: Some(Bytes::from(vec![0x55, 0x66, 0x77, 0x88])), + let gid = 0xF; + 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(move |hal| { + let cmd = UciCommand::RawVendorCmd { 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)), }); hal.expected_send_command(cmd, resp, Ok(())); }) .await; - let gid = 0xF; - let oid = 0x3; - let payload = vec![0x11, 0x22, 0x33, 0x44]; - let expected_result = RawVendorMessage { gid, oid, payload: vec![0x55, 0x66, 0x77, 0x88] }; - let result = uci_manager.raw_vendor_cmd(gid, oid, payload).await.unwrap(); + let expected_result = RawVendorMessage { gid, oid, payload: resp_payload }; + let result = uci_manager.raw_vendor_cmd(gid, oid, cmd_payload).await.unwrap(); assert_eq!(result, expected_result); assert!(mock_hal.wait_expected_calls_done().await); } @@ -1239,8 +1238,7 @@ mod tests { #[tokio::test] async fn test_session_get_count_retry_no_response() { let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let cmd: RawUciMessage = uwb_uci_packets::SessionGetCountCmdBuilder {}.build().into(); - + let cmd = UciCommand::SessionGetCount; hal.expected_send_command(cmd, vec![], Ok(())); }) .await; @@ -1253,8 +1251,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(|hal| { - let cmd: RawUciMessage = uwb_uci_packets::SessionGetCountCmdBuilder {}.build().into(); - + let cmd = UciCommand::SessionGetCount; hal.expected_send_command(cmd, vec![], Err(Error::Timeout)); }) .await; @@ -1267,8 +1264,8 @@ 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(|hal| { - let cmd: RawUciMessage = uwb_uci_packets::SessionGetCountCmdBuilder {}.build().into(); - let retry_resp = into_raw_messages(uwb_uci_packets::SessionGetCountRspBuilder { + let cmd = UciCommand::SessionGetCount; + let retry_resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder { status: uwb_uci_packets::StatusCode::UciStatusCommandRetry, session_count: 0, }); @@ -1286,15 +1283,17 @@ mod tests { #[tokio::test] async fn test_session_get_count_retry_notification() { - let (mut uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(|hal| { - let cmd: RawUciMessage = uwb_uci_packets::SessionGetCountCmdBuilder {}.build().into(); - let retry_resp = into_raw_messages(uwb_uci_packets::SessionGetCountRspBuilder { + let session_count = 5; + + let (mut 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 { status: uwb_uci_packets::StatusCode::UciStatusCommandRetry, session_count: 0, }); - let resp = into_raw_messages(uwb_uci_packets::SessionGetCountRspBuilder { + let resp = into_uci_hal_packets(uwb_uci_packets::SessionGetCountRspBuilder { status: uwb_uci_packets::StatusCode::UciStatusOk, - session_count: 5, + session_count, }); hal.expected_send_command(cmd.clone(), retry_resp.clone(), Ok(())); @@ -1304,7 +1303,7 @@ mod tests { .await; let result = uci_manager.session_get_count().await.unwrap(); - assert_eq!(result, 5); + assert_eq!(result, session_count); assert!(mock_hal.wait_expected_calls_done().await); } } 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 815a5c4..b61e04c 100644 --- a/src/rust/uwb_core/src/uci/uci_manager_sync.rs +++ b/src/rust/uwb_core/src/uci/uci_manager_sync.rs @@ -115,10 +115,10 @@ impl UciManagerSync { /// UciHal and NotificationManagerBuilder required at construction as they are required before /// open_hal is called. runtime is taken with ownership for blocking on async steps only. pub fn new<T: UciHal, U: NotificationManager, V: NotificationManagerBuilder<U>>( - uci_manager_runtime: Runtime, hal: T, notification_manager_builder: V, ) -> Result<Self> { + let uci_manager_runtime = RuntimeBuilder::new_multi_thread().enable_all().build().unwrap(); // UciManagerImpl::new uses tokio::spawn, so it is called inside the runtime as async fn. let mut uci_manager_impl = uci_manager_runtime.block_on(async { UciManagerImpl::new(hal) }); let (core_notification_sender, core_notification_receiver) = @@ -316,7 +316,7 @@ mod tests { use crate::error::Error; use crate::uci::mock_uci_hal::MockUciHal; - use crate::uci::uci_hal::RawUciMessage; + use crate::uci::uci_hal::UciHalPacket; struct MockNotificationManager { device_state_sender: mpsc::UnboundedSender<DeviceState>, @@ -344,6 +344,7 @@ mod tests { Ok(()) } } + struct MockNotificationManagerBuilder { device_state_sender: mpsc::UnboundedSender<DeviceState>, // initial_count is an example for a parameter undetermined at compile time. @@ -357,12 +358,14 @@ mod tests { }) } } + fn into_raw_messages<T: Into<uwb_uci_packets::UciPacketPacket>>( builder: T, - ) -> Vec<RawUciMessage> { + ) -> Vec<UciHalPacket> { let packets: Vec<uwb_uci_packets::UciPacketHalPacket> = builder.into().into(); packets.into_iter().map(|packet| packet.into()).collect() } + #[test] fn test_sync_uci_open_hal() { let mut hal = MockUciHal::new(); @@ -374,7 +377,6 @@ mod tests { let (device_state_sender, mut device_state_receiver) = mpsc::unbounded_channel::<DeviceState>(); let mut uci_manager_sync = UciManagerSync::new( - Builder::new_multi_thread().enable_all().build().unwrap(), hal, MockNotificationManagerBuilder { device_state_sender, initial_count: 0 }, ) diff --git a/src/rust/uwb_core/src/utils.rs b/src/rust/uwb_core/src/utils.rs index 65fae8d..5ed116a 100644 --- a/src/rust/uwb_core/src/utils.rs +++ b/src/rust/uwb_core/src/utils.rs @@ -50,7 +50,38 @@ macro_rules! builder_field { } pub(crate) use builder_field; +/// Generate the getter method for the field of the struct. +macro_rules! getter_field { + ($field:ident, $ty:ty) => { + pub fn $field(&self) -> &$ty { + &self.$field + } + }; +} +pub(crate) use getter_field; + #[cfg(test)] pub fn init_test_logging() { let _ = env_logger::builder().is_test(true).try_init(); } + +#[cfg(test)] +mod tests { + struct Foo { + value: u32, + } + + impl Foo { + pub fn new(value: u32) -> Self { + Self { value } + } + + getter_field!(value, u32); + } + + #[test] + fn test_getter_field() { + let foo = Foo::new(5); + assert_eq!(foo.value(), &5); + } +} diff --git a/src/rust/uwb_uci_packets/Cargo.toml b/src/rust/uwb_uci_packets/Cargo.toml index ae3c729..3d1f28a 100644 --- a/src/rust/uwb_uci_packets/Cargo.toml +++ b/src/rust/uwb_uci_packets/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "uwb_uci_packets" version = "0.0.1" -edition = "2018" +edition = "2021" [dependencies] bytes = "*" diff --git a/src/rust/uwb_uci_packets/uci_packets.pdl b/src/rust/uwb_uci_packets/uci_packets.pdl index 884c7c6..5fd696f 100644 --- a/src/rust/uwb_uci_packets/uci_packets.pdl +++ b/src/rust/uwb_uci_packets/uci_packets.pdl @@ -163,8 +163,8 @@ enum AppConfigTlvType : 8 { BPRF_PHR_DATA_RATE = 0x31, MAX_NUMBER_OF_MEASUREMENTS = 0x32, STS_LENGTH = 0x35, - SESSION_KEY = 0x36, - SUBSESSION_KEY = 0x37, + SESSION_KEY = 0x45, + SUBSESSION_KEY = 0x46, // CCC specific CCC_HOP_MODE_KEY = 0xA0, |