uwb_core: add CccStartedAppConfigParams

This CL adds CccStartedAppConfigParams, which defines parameters for
CCC start reports.

Bug: 228136039
Test: cargo test
Test: cargo clippy
Change-Id: I47c09c13756b70845e74ac94a2d3ec11fffaa261
diff --git a/src/rust/uwb_core/src/session/params.rs b/src/rust/uwb_core/src/session/params.rs
index ac8239b..31b2acc 100644
--- a/src/rust/uwb_core/src/session/params.rs
+++ b/src/rust/uwb_core/src/session/params.rs
@@ -13,22 +13,27 @@
 // limitations under the License.
 
 pub mod ccc_app_config_params;
+pub mod ccc_started_app_config_params;
 pub mod fira_app_config_params;
 mod utils;
 
 use std::collections::HashMap;
 
 use crate::session::params::ccc_app_config_params::CccAppConfigParams;
+use crate::session::params::ccc_started_app_config_params::CccStartedAppConfigParams;
 use crate::session::params::fira_app_config_params::FiraAppConfigParams;
 use crate::uci::params::{AppConfigTlv, AppConfigTlvType, SessionState, SessionType};
 
 type AppConfigTlvMap = HashMap<AppConfigTlvType, Vec<u8>>;
 
-/// The parameters of the UWB session.
+/// 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)]
 pub enum AppConfigParams {
     Fira(FiraAppConfigParams),
     Ccc(CccAppConfigParams),
+    CccStarted(CccStartedAppConfigParams),
 }
 
 impl AppConfigParams {
@@ -56,6 +61,7 @@
         match self {
             Self::Fira(params) => params.generate_config_map(),
             Self::Ccc(params) => params.generate_config_map(),
+            _ => HashMap::new(),
         }
     }
 
@@ -94,7 +100,7 @@
                 session_type == SessionType::FiraDataTransfer
                     || session_type == SessionType::FiraRangingSession
             }
-            Self::Ccc(_) => session_type == SessionType::Ccc,
+            Self::Ccc(_) | Self::CccStarted(_) => session_type == SessionType::Ccc,
         }
     }
 
diff --git a/src/rust/uwb_core/src/session/params/ccc_app_config_params.rs b/src/rust/uwb_core/src/session/params/ccc_app_config_params.rs
index db7dd01..4d4d56e 100644
--- a/src/rust/uwb_core/src/session/params/ccc_app_config_params.rs
+++ b/src/rust/uwb_core/src/session/params/ccc_app_config_params.rs
@@ -25,7 +25,7 @@
 use crate::utils::builder_field;
 
 const CHAP_IN_RSTU: u16 = 400; // 1 Chap = 400 RSTU.
-const MINIMUM_BLOCK_DURATION_MS: u32 = 96;
+pub(super) const MINIMUM_BLOCK_DURATION_MS: u32 = 96;
 
 // The constant AppConfigTlv values for CCC.
 const CCC_DEVICE_TYPE: DeviceType = DeviceType::Controlee;
diff --git a/src/rust/uwb_core/src/session/params/ccc_started_app_config_params.rs b/src/rust/uwb_core/src/session/params/ccc_started_app_config_params.rs
new file mode 100644
index 0000000..b680a04
--- /dev/null
+++ b/src/rust/uwb_core/src/session/params/ccc_started_app_config_params.rs
@@ -0,0 +1,76 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, item 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::session::params::ccc_app_config_params::MINIMUM_BLOCK_DURATION_MS;
+use crate::session::params::utils::{bytes_to_u32, bytes_to_u64, bytes_to_u8};
+use crate::session::params::AppConfigTlvMap;
+use crate::uci::params::AppConfigTlvType;
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct CccStartedAppConfigParams {
+    pub sts_index: u32,
+    pub hop_mode_key: u32,
+    pub uwb_time0: u64,
+    pub ran_multiplier: u32,
+    pub sync_code_index: u8,
+}
+
+impl CccStartedAppConfigParams {
+    pub fn from_config_map(mut config_map: AppConfigTlvMap) -> Option<Self> {
+        Some(Self {
+            sts_index: bytes_to_u32(config_map.remove(&AppConfigTlvType::StsIndex)?)?,
+            hop_mode_key: bytes_to_u32(config_map.remove(&AppConfigTlvType::CccHopModeKey)?)?,
+            uwb_time0: bytes_to_u64(config_map.remove(&AppConfigTlvType::CccUwbTime0)?)?,
+            ran_multiplier: bytes_to_u32(config_map.remove(&AppConfigTlvType::RangingInterval)?)?
+                / MINIMUM_BLOCK_DURATION_MS,
+            sync_code_index: bytes_to_u8(config_map.remove(&AppConfigTlvType::PreambleCodeIndex)?)?,
+        })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use std::collections::HashMap;
+
+    use crate::session::params::utils::{u32_to_bytes, u64_to_bytes, u8_to_bytes};
+
+    #[test]
+    fn test_from_config_map() {
+        let sts_index = 3;
+        let hop_mode_key = 5;
+        let uwb_time0 = 7;
+        let ran_multiplier = 4;
+        let sync_code_index = 9;
+
+        let config_map = HashMap::from([
+            (AppConfigTlvType::StsIndex, u32_to_bytes(sts_index)),
+            (AppConfigTlvType::CccHopModeKey, u32_to_bytes(hop_mode_key)),
+            (AppConfigTlvType::CccUwbTime0, u64_to_bytes(uwb_time0)),
+            (
+                AppConfigTlvType::RangingInterval,
+                u32_to_bytes(ran_multiplier * MINIMUM_BLOCK_DURATION_MS),
+            ),
+            (AppConfigTlvType::PreambleCodeIndex, u8_to_bytes(sync_code_index)),
+        ]);
+        let params = CccStartedAppConfigParams::from_config_map(config_map).unwrap();
+
+        assert_eq!(params.sts_index, sts_index);
+        assert_eq!(params.hop_mode_key, hop_mode_key);
+        assert_eq!(params.uwb_time0, uwb_time0);
+        assert_eq!(params.ran_multiplier, ran_multiplier);
+        assert_eq!(params.sync_code_index, sync_code_index);
+    }
+}
diff --git a/src/rust/uwb_core/src/session/params/utils.rs b/src/rust/uwb_core/src/session/params/utils.rs
index 5b93411..af65536 100644
--- a/src/rust/uwb_core/src/session/params/utils.rs
+++ b/src/rust/uwb_core/src/session/params/utils.rs
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+use std::convert::TryInto;
+
 use log::error;
 
 pub(super) fn u8_to_bytes(value: u8) -> Vec<u8> {
@@ -26,6 +28,26 @@
     value.to_le_bytes().to_vec()
 }
 
+pub(super) fn u64_to_bytes(value: u64) -> Vec<u8> {
+    value.to_le_bytes().to_vec()
+}
+
+pub(super) fn bytes_to_u8(value: Vec<u8>) -> Option<u8> {
+    Some(u8::from_le_bytes(value.try_into().ok()?))
+}
+
+pub(super) fn bytes_to_u16(value: Vec<u8>) -> Option<u16> {
+    Some(u16::from_le_bytes(value.try_into().ok()?))
+}
+
+pub(super) fn bytes_to_u32(value: Vec<u8>) -> Option<u32> {
+    Some(u32::from_le_bytes(value.try_into().ok()?))
+}
+
+pub(super) fn bytes_to_u64(value: Vec<u8>) -> Option<u64> {
+    Some(u64::from_le_bytes(value.try_into().ok()?))
+}
+
 pub(super) fn validate(value: bool, err_msg: &str) -> Option<()> {
     match value {
         true => Some(()),
@@ -35,3 +57,44 @@
         }
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_convert_u8_bytes() {
+        let value: u8 = 0x57;
+        let arr = u8_to_bytes(value);
+
+        assert_eq!(arr, vec![0x57]);
+        assert_eq!(bytes_to_u8(arr), Some(value));
+    }
+
+    #[test]
+    fn test_convert_u16_bytes() {
+        let value: u16 = 0x1357;
+        let arr = u16_to_bytes(value);
+
+        assert_eq!(arr, vec![0x57, 0x13]);
+        assert_eq!(bytes_to_u16(arr), Some(value));
+    }
+
+    #[test]
+    fn test_convert_u32_bytes() {
+        let value: u32 = 0x12345678;
+        let arr = u32_to_bytes(value);
+
+        assert_eq!(arr, vec![0x78, 0x56, 0x34, 0x12]);
+        assert_eq!(bytes_to_u32(arr), Some(value));
+    }
+
+    #[test]
+    fn test_convert_u64_bytes() {
+        let value: u64 = 0x0123456789ABCDEF;
+        let arr = u64_to_bytes(value);
+
+        assert_eq!(arr, vec![0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01]);
+        assert_eq!(bytes_to_u64(arr), Some(value));
+    }
+}