xref: /aosp_15_r20/tools/netsim/rust/daemon/src/devices/chip.rs (revision cf78ab8cffb8fc9207af348f23af247fb04370a6)
1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 /// A `Chip` is a generic struct that wraps a radio specific
16 /// WirelessAdaptor.` The Chip layer provides for common operations and
17 /// data.
18 ///
19 /// The emulated chip facade is a library that implements the
20 /// controller protocol.
21 ///
22 use crate::wireless::WirelessAdaptorImpl;
23 use netsim_proto::common::ChipKind as ProtoChipKind;
24 use netsim_proto::model::Chip as ProtoChip;
25 use netsim_proto::stats::NetsimRadioStats as ProtoRadioStats;
26 use protobuf::EnumOrUnknown;
27 use std::collections::HashMap;
28 use std::fmt;
29 use std::sync::atomic::{AtomicU32, Ordering};
30 use std::sync::{Arc, OnceLock, RwLock};
31 use std::time::Instant;
32 
33 use super::device::DeviceIdentifier;
34 
35 #[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialOrd, PartialEq)]
36 pub struct ChipIdentifier(pub u32);
37 #[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialOrd, PartialEq)]
38 pub struct FacadeIdentifier(pub u32);
39 
40 impl fmt::Display for ChipIdentifier {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result41     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42         write!(f, "{}", self.0)
43     }
44 }
45 
46 impl fmt::Debug for ChipIdentifier {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result47     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48         write!(f, "{}", self.0)
49     }
50 }
51 
52 impl fmt::Display for FacadeIdentifier {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result53     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54         write!(f, "{}", self.0)
55     }
56 }
57 
58 impl fmt::Debug for FacadeIdentifier {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result59     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60         write!(f, "{}", self.0)
61     }
62 }
63 
64 const INITIAL_CHIP_ID: u32 = 1000;
65 
66 struct ChipManager {
67     ids: AtomicU32,
68     chips: RwLock<HashMap<ChipIdentifier, Arc<Chip>>>,
69 }
70 
71 static CHIP_MANAGER: OnceLock<ChipManager> = OnceLock::new();
72 
get_chip_manager() -> &'static ChipManager73 fn get_chip_manager() -> &'static ChipManager {
74     CHIP_MANAGER.get_or_init(|| ChipManager::new(INITIAL_CHIP_ID))
75 }
76 
77 pub struct CreateParams {
78     pub kind: ProtoChipKind,
79     pub address: String,
80     pub name: Option<String>,
81     pub manufacturer: String,
82     pub product_name: String,
83 }
84 
85 /// Chip contains the common information for each Chip/Controller.
86 /// Radio-specific information is contained in the wireless_adaptor.
87 pub struct Chip {
88     pub id: ChipIdentifier,
89     pub device_id: DeviceIdentifier,
90     pub wireless_adaptor: WirelessAdaptorImpl,
91     pub kind: ProtoChipKind,
92     #[allow(dead_code)]
93     pub address: String,
94     pub name: String,
95     // TODO: may not be necessary
96     #[allow(dead_code)]
97     pub device_name: String,
98     // These are patchable
99     pub manufacturer: RwLock<String>,
100     pub product_name: RwLock<String>,
101     pub start: Instant,
102 }
103 
104 impl ChipManager {
new(start: u32) -> Self105     fn new(start: u32) -> Self {
106         ChipManager { ids: AtomicU32::new(start), chips: RwLock::new(HashMap::new()) }
107     }
108 
next_id(&self) -> ChipIdentifier109     fn next_id(&self) -> ChipIdentifier {
110         ChipIdentifier(self.ids.fetch_add(1, Ordering::SeqCst))
111     }
112 }
113 
114 impl Chip {
new( id: ChipIdentifier, device_id: DeviceIdentifier, device_name: &str, create_params: &CreateParams, wireless_adaptor: WirelessAdaptorImpl, ) -> Self115     fn new(
116         id: ChipIdentifier,
117         device_id: DeviceIdentifier,
118         device_name: &str,
119         create_params: &CreateParams,
120         wireless_adaptor: WirelessAdaptorImpl,
121     ) -> Self {
122         Self {
123             id,
124             device_id,
125             wireless_adaptor,
126             kind: create_params.kind,
127             address: create_params.address.clone(),
128             name: create_params.name.clone().unwrap_or(format!("chip-{}", id.0)),
129             device_name: device_name.to_string(),
130             manufacturer: RwLock::new(create_params.manufacturer.clone()),
131             product_name: RwLock::new(create_params.product_name.clone()),
132             start: Instant::now(),
133         }
134     }
135 
136     // Get the stats protobuf for a chip controller instance.
137     //
138     // This currently wraps the chip "get" facade method because the
139     // counts are phy level. We need a vec since Bluetooth reports
140     // stats for BLE and CLASSIC.
get_stats(&self) -> Vec<ProtoRadioStats>141     pub fn get_stats(&self) -> Vec<ProtoRadioStats> {
142         self.wireless_adaptor.get_stats(self.start.elapsed().as_secs())
143     }
144 
145     /// Create the model protobuf
get(&self) -> Result<ProtoChip, String>146     pub fn get(&self) -> Result<ProtoChip, String> {
147         let mut proto_chip = self.wireless_adaptor.get();
148         proto_chip.kind = EnumOrUnknown::new(self.kind);
149         proto_chip.id = self.id.0;
150         proto_chip.name.clone_from(&self.name);
151         proto_chip.manufacturer.clone_from(&self.manufacturer.read().unwrap());
152         proto_chip.product_name.clone_from(&self.product_name.read().unwrap());
153         Ok(proto_chip)
154     }
155 
156     /// Patch processing for the chip. Validate and move state from the patch
157     /// into the chip changing the ChipFacade as needed.
patch(&self, patch: &ProtoChip) -> Result<(), String>158     pub fn patch(&self, patch: &ProtoChip) -> Result<(), String> {
159         if !patch.manufacturer.is_empty() {
160             self.manufacturer.write().unwrap().clone_from(&patch.manufacturer);
161         }
162         if !patch.product_name.is_empty() {
163             self.product_name.write().unwrap().clone_from(&patch.product_name);
164         }
165         self.wireless_adaptor.patch(patch);
166         Ok(())
167     }
168 
reset(&self) -> Result<(), String>169     pub fn reset(&self) -> Result<(), String> {
170         self.wireless_adaptor.reset();
171         Ok(())
172     }
173 }
174 
175 /// Obtains a Chip with given chip_id
get_chip(chip_id: &ChipIdentifier) -> Option<Arc<Chip>>176 pub fn get_chip(chip_id: &ChipIdentifier) -> Option<Arc<Chip>> {
177     get_chip_manager().get_chip(chip_id)
178 }
179 
180 /// Remove a Chip with given chip_id
remove_chip(chip_id: &ChipIdentifier) -> Option<Arc<Chip>>181 pub fn remove_chip(chip_id: &ChipIdentifier) -> Option<Arc<Chip>> {
182     get_chip_manager().remove_chip(chip_id)
183 }
184 
next_id() -> ChipIdentifier185 pub fn next_id() -> ChipIdentifier {
186     get_chip_manager().next_id()
187 }
188 
189 /// Allocates a new chip.
new( id: ChipIdentifier, device_id: DeviceIdentifier, device_name: &str, create_params: &CreateParams, wireless_adaptor: WirelessAdaptorImpl, ) -> Result<Arc<Chip>, String>190 pub fn new(
191     id: ChipIdentifier,
192     device_id: DeviceIdentifier,
193     device_name: &str,
194     create_params: &CreateParams,
195     wireless_adaptor: WirelessAdaptorImpl,
196 ) -> Result<Arc<Chip>, String> {
197     get_chip_manager().new_chip(id, device_id, device_name, create_params, wireless_adaptor)
198 }
199 
200 impl ChipManager {
new_chip( &self, id: ChipIdentifier, device_id: DeviceIdentifier, device_name: &str, create_params: &CreateParams, wireless_adaptor: WirelessAdaptorImpl, ) -> Result<Arc<Chip>, String>201     fn new_chip(
202         &self,
203         id: ChipIdentifier,
204         device_id: DeviceIdentifier,
205         device_name: &str,
206         create_params: &CreateParams,
207         wireless_adaptor: WirelessAdaptorImpl,
208     ) -> Result<Arc<Chip>, String> {
209         let chip = Arc::new(Chip::new(id, device_id, device_name, create_params, wireless_adaptor));
210         self.chips.write().unwrap().insert(id, Arc::clone(&chip));
211         Ok(chip)
212     }
213 
get_chip(&self, chip_id: &ChipIdentifier) -> Option<Arc<Chip>>214     fn get_chip(&self, chip_id: &ChipIdentifier) -> Option<Arc<Chip>> {
215         self.chips.read().unwrap().get(chip_id).cloned()
216     }
217 
remove_chip(&self, chip_id: &ChipIdentifier) -> Option<Arc<Chip>>218     fn remove_chip(&self, chip_id: &ChipIdentifier) -> Option<Arc<Chip>> {
219         self.chips.write().unwrap().remove(chip_id)
220     }
221 }
222 
223 #[cfg(test)]
224 mod tests {
225     use netsim_proto::stats::netsim_radio_stats;
226 
227     use crate::wireless::mocked;
228 
229     use super::*;
230 
231     const DEVICE_ID: DeviceIdentifier = DeviceIdentifier(0);
232     const CHIP_ID: ChipIdentifier = ChipIdentifier(1000);
233     const DEVICE_NAME: &str = "device";
234     const CHIP_KIND: ProtoChipKind = ProtoChipKind::UNSPECIFIED;
235     const ADDRESS: &str = "address";
236     const MANUFACTURER: &str = "manufacturer";
237     const PRODUCT_NAME: &str = "product_name";
238 
239     impl ChipManager {
new_test_chip(&self, wireless_adaptor: WirelessAdaptorImpl) -> Arc<Chip>240         fn new_test_chip(&self, wireless_adaptor: WirelessAdaptorImpl) -> Arc<Chip> {
241             let create_params = CreateParams {
242                 kind: CHIP_KIND,
243                 address: ADDRESS.to_string(),
244                 name: None,
245                 manufacturer: MANUFACTURER.to_string(),
246                 product_name: PRODUCT_NAME.to_string(),
247             };
248             self.new_chip(CHIP_ID, DEVICE_ID, DEVICE_NAME, &create_params, wireless_adaptor)
249                 .unwrap()
250         }
251     }
252 
253     #[test]
test_new_and_get_with_singleton()254     fn test_new_and_get_with_singleton() {
255         let mocked_adaptor = mocked::new(
256             &mocked::CreateParams { chip_kind: ProtoChipKind::UNSPECIFIED },
257             ChipIdentifier(0),
258         );
259         let chip_manager = ChipManager::new(INITIAL_CHIP_ID);
260         let chip = chip_manager.new_test_chip(mocked_adaptor);
261 
262         // Check if the Chip has been successfully inserted
263         let chip_id = chip.id;
264         assert!(chip_manager.chips.read().unwrap().contains_key(&chip_id));
265 
266         // Check if the chip_manager can successfully fetch the chip
267         let chip_result = chip_manager.get_chip(&chip_id);
268         assert!(chip_result.is_some());
269 
270         // Check if the fields are correctly populated
271         let chip = chip_result.unwrap();
272         assert_eq!(chip.device_id, DEVICE_ID);
273         assert_eq!(chip.device_name, DEVICE_NAME);
274         assert_eq!(chip.kind, CHIP_KIND);
275         assert_eq!(chip.address, ADDRESS);
276         assert_eq!(chip.name, format!("chip-{chip_id}"));
277         assert_eq!(chip.manufacturer.read().unwrap().to_string(), MANUFACTURER);
278         assert_eq!(chip.product_name.read().unwrap().to_string(), PRODUCT_NAME);
279     }
280 
281     #[test]
test_chip_get_stats()282     fn test_chip_get_stats() {
283         // When wireless_adaptor is constructed
284         let mocked_adaptor = mocked::new(
285             &mocked::CreateParams { chip_kind: ProtoChipKind::UNSPECIFIED },
286             ChipIdentifier(0),
287         );
288         let chip_manager = ChipManager::new(INITIAL_CHIP_ID);
289 
290         let chip = chip_manager.new_test_chip(mocked_adaptor);
291         assert_eq!(netsim_radio_stats::Kind::UNSPECIFIED, chip.get_stats().first().unwrap().kind());
292     }
293 
294     #[test]
test_chip_get()295     fn test_chip_get() {
296         let mocked_adaptor = mocked::new(
297             &mocked::CreateParams { chip_kind: ProtoChipKind::UNSPECIFIED },
298             ChipIdentifier(0),
299         );
300         let chip_manager = ChipManager::new(INITIAL_CHIP_ID);
301         let chip = chip_manager.new_test_chip(mocked_adaptor);
302 
303         // Obtain actual chip.get()
304         let actual = chip.get().unwrap();
305 
306         // Construct expected ProtoChip
307         let mut expected = chip.wireless_adaptor.get();
308         expected.kind = EnumOrUnknown::new(chip.kind);
309         expected.id = chip.id.0;
310         expected.name.clone_from(&chip.name);
311         expected.manufacturer.clone_from(&chip.manufacturer.read().unwrap());
312         expected.product_name.clone_from(&chip.product_name.read().unwrap());
313 
314         // Compare
315         assert_eq!(expected, actual);
316     }
317 
318     #[test]
test_chip_patch()319     fn test_chip_patch() {
320         let mocked_adaptor = mocked::new(
321             &mocked::CreateParams { chip_kind: ProtoChipKind::UNSPECIFIED },
322             ChipIdentifier(0),
323         );
324         let chip_manager = ChipManager::new(INITIAL_CHIP_ID);
325         let chip = chip_manager.new_test_chip(mocked_adaptor);
326 
327         // Construct the patch body for modifying manufacturer and product_name
328         let mut patch_body = ProtoChip::new();
329         patch_body.manufacturer = "patched_manufacturer".to_string();
330         patch_body.product_name = "patched_product_name".to_string();
331 
332         // Perform Patch
333         assert!(chip.patch(&patch_body).is_ok());
334 
335         // Check if fields of chip has been patched
336         assert_eq!(patch_body.manufacturer, chip.manufacturer.read().unwrap().to_string());
337         assert_eq!(patch_body.product_name, chip.product_name.read().unwrap().to_string());
338     }
339 
340     // TODO (b/309529194)
341     // Implement wireless/mocked.rs to test wireless_adaptor level of patch and resets.
342 }
343