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 lazy_static::lazy_static;
24 use netsim_proto::common::ChipKind as ProtoChipKind;
25 use netsim_proto::configuration::Controller as ProtoController;
26 use netsim_proto::model::Chip as ProtoChip;
27 use netsim_proto::stats::NetsimRadioStats as ProtoRadioStats;
28 use protobuf::EnumOrUnknown;
29 use std::collections::HashMap;
30 use std::fmt;
31 use std::sync::atomic::{AtomicU32, Ordering};
32 use std::sync::{Arc, RwLock};
33 use std::time::Instant;
34 
35 use super::device::DeviceIdentifier;
36 
37 #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialOrd, PartialEq)]
38 pub struct ChipIdentifier(pub u32);
39 #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialOrd, PartialEq)]
40 pub struct FacadeIdentifier(pub u32);
41 
42 impl fmt::Display for ChipIdentifier {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result43     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44         write!(f, "{}", self.0)
45     }
46 }
47 
48 impl fmt::Display for FacadeIdentifier {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result49     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50         write!(f, "{}", self.0)
51     }
52 }
53 
54 const INITIAL_CHIP_ID: u32 = 1000;
55 
56 struct ChipManager {
57     ids: AtomicU32,
58     chips: RwLock<HashMap<ChipIdentifier, Arc<Chip>>>,
59 }
60 
61 lazy_static! {
62     static ref CHIP_MANAGER: ChipManager = ChipManager::new(INITIAL_CHIP_ID);
63 }
64 
65 pub struct CreateParams {
66     pub kind: ProtoChipKind,
67     pub address: String,
68     pub name: Option<String>,
69     pub manufacturer: String,
70     pub product_name: String,
71     pub bt_properties: Option<ProtoController>, // TODO: move to wireless_adaptor CreateParams
72 }
73 
74 /// Chip contains the common information for each Chip/Controller.
75 /// Radio-specific information is contained in the wireless_adaptor.
76 pub struct Chip {
77     pub id: ChipIdentifier,
78     pub device_id: DeviceIdentifier,
79     pub wireless_adaptor: WirelessAdaptorImpl,
80     pub kind: ProtoChipKind,
81     pub address: String,
82     pub name: String,
83     // TODO: may not be necessary
84     pub device_name: String,
85     // These are patchable
86     pub manufacturer: RwLock<String>,
87     pub product_name: RwLock<String>,
88     pub start: Instant,
89 }
90 
91 impl ChipManager {
new(start: u32) -> Self92     fn new(start: u32) -> Self {
93         ChipManager { ids: AtomicU32::new(start), chips: RwLock::new(HashMap::new()) }
94     }
95 
next_id(&self) -> ChipIdentifier96     fn next_id(&self) -> ChipIdentifier {
97         ChipIdentifier(self.ids.fetch_add(1, Ordering::SeqCst))
98     }
99 }
100 
101 impl Chip {
new( id: ChipIdentifier, device_id: DeviceIdentifier, device_name: &str, create_params: &CreateParams, wireless_adaptor: WirelessAdaptorImpl, ) -> Self102     fn new(
103         id: ChipIdentifier,
104         device_id: DeviceIdentifier,
105         device_name: &str,
106         create_params: &CreateParams,
107         wireless_adaptor: WirelessAdaptorImpl,
108     ) -> Self {
109         Self {
110             id,
111             device_id,
112             wireless_adaptor,
113             kind: create_params.kind,
114             address: create_params.address.clone(),
115             name: create_params.name.clone().unwrap_or(format!("chip-{}", id.0)),
116             device_name: device_name.to_string(),
117             manufacturer: RwLock::new(create_params.manufacturer.clone()),
118             product_name: RwLock::new(create_params.product_name.clone()),
119             start: Instant::now(),
120         }
121     }
122 
123     // Get the stats protobuf for a chip controller instance.
124     //
125     // This currently wraps the chip "get" facade method because the
126     // counts are phy level. We need a vec since Bluetooth reports
127     // stats for BLE and CLASSIC.
get_stats(&self) -> Vec<ProtoRadioStats>128     pub fn get_stats(&self) -> Vec<ProtoRadioStats> {
129         self.wireless_adaptor.get_stats(self.start.elapsed().as_secs())
130     }
131 
132     /// Create the model protobuf
get(&self) -> Result<ProtoChip, String>133     pub fn get(&self) -> Result<ProtoChip, String> {
134         let mut proto_chip = self.wireless_adaptor.get();
135         proto_chip.kind = EnumOrUnknown::new(self.kind);
136         proto_chip.id = self.id.0;
137         proto_chip.name.clone_from(&self.name);
138         proto_chip.manufacturer.clone_from(&self.manufacturer.read().unwrap());
139         proto_chip.product_name.clone_from(&self.product_name.read().unwrap());
140         Ok(proto_chip)
141     }
142 
143     /// Patch processing for the chip. Validate and move state from the patch
144     /// into the chip changing the ChipFacade as needed.
patch(&self, patch: &ProtoChip) -> Result<(), String>145     pub fn patch(&self, patch: &ProtoChip) -> Result<(), String> {
146         if !patch.manufacturer.is_empty() {
147             self.manufacturer.write().unwrap().clone_from(&patch.manufacturer);
148         }
149         if !patch.product_name.is_empty() {
150             self.product_name.write().unwrap().clone_from(&patch.product_name);
151         }
152         self.wireless_adaptor.patch(patch);
153         Ok(())
154     }
155 
reset(&self) -> Result<(), String>156     pub fn reset(&self) -> Result<(), String> {
157         self.wireless_adaptor.reset();
158         Ok(())
159     }
160 }
161 
162 /// Obtains a Chip with given chip_id
get_chip(chip_id: &ChipIdentifier) -> Option<Arc<Chip>>163 pub fn get_chip(chip_id: &ChipIdentifier) -> Option<Arc<Chip>> {
164     CHIP_MANAGER.get_chip(chip_id)
165 }
166 
167 /// Remove a Chip with given chip_id
remove_chip(chip_id: &ChipIdentifier) -> Option<Arc<Chip>>168 pub fn remove_chip(chip_id: &ChipIdentifier) -> Option<Arc<Chip>> {
169     CHIP_MANAGER.remove_chip(chip_id)
170 }
171 
next_id() -> ChipIdentifier172 pub fn next_id() -> ChipIdentifier {
173     CHIP_MANAGER.next_id()
174 }
175 
176 /// Allocates a new chip.
new( id: ChipIdentifier, device_id: DeviceIdentifier, device_name: &str, create_params: &CreateParams, wireless_adaptor: WirelessAdaptorImpl, ) -> Result<Arc<Chip>, String>177 pub fn new(
178     id: ChipIdentifier,
179     device_id: DeviceIdentifier,
180     device_name: &str,
181     create_params: &CreateParams,
182     wireless_adaptor: WirelessAdaptorImpl,
183 ) -> Result<Arc<Chip>, String> {
184     CHIP_MANAGER.new_chip(id, device_id, device_name, create_params, wireless_adaptor)
185 }
186 
187 impl ChipManager {
new_chip( &self, id: ChipIdentifier, device_id: DeviceIdentifier, device_name: &str, create_params: &CreateParams, wireless_adaptor: WirelessAdaptorImpl, ) -> Result<Arc<Chip>, String>188     fn new_chip(
189         &self,
190         id: ChipIdentifier,
191         device_id: DeviceIdentifier,
192         device_name: &str,
193         create_params: &CreateParams,
194         wireless_adaptor: WirelessAdaptorImpl,
195     ) -> Result<Arc<Chip>, String> {
196         let chip = Arc::new(Chip::new(id, device_id, device_name, create_params, wireless_adaptor));
197         self.chips.write().unwrap().insert(id, Arc::clone(&chip));
198         Ok(chip)
199     }
200 
get_chip(&self, chip_id: &ChipIdentifier) -> Option<Arc<Chip>>201     fn get_chip(&self, chip_id: &ChipIdentifier) -> Option<Arc<Chip>> {
202         self.chips.read().unwrap().get(chip_id).cloned()
203     }
204 
remove_chip(&self, chip_id: &ChipIdentifier) -> Option<Arc<Chip>>205     fn remove_chip(&self, chip_id: &ChipIdentifier) -> Option<Arc<Chip>> {
206         self.chips.write().unwrap().remove(chip_id)
207     }
208 }
209 
210 #[cfg(test)]
211 mod tests {
212     use netsim_proto::stats::netsim_radio_stats;
213 
214     use crate::wireless::mocked;
215 
216     use super::*;
217 
218     const DEVICE_ID: DeviceIdentifier = DeviceIdentifier(0);
219     const CHIP_ID: ChipIdentifier = ChipIdentifier(1000);
220     const DEVICE_NAME: &str = "device";
221     const CHIP_KIND: ProtoChipKind = ProtoChipKind::UNSPECIFIED;
222     const ADDRESS: &str = "address";
223     const MANUFACTURER: &str = "manufacturer";
224     const PRODUCT_NAME: &str = "product_name";
225 
226     impl ChipManager {
new_test_chip(&self, wireless_adaptor: WirelessAdaptorImpl) -> Arc<Chip>227         fn new_test_chip(&self, wireless_adaptor: WirelessAdaptorImpl) -> Arc<Chip> {
228             let create_params = CreateParams {
229                 kind: CHIP_KIND,
230                 address: ADDRESS.to_string(),
231                 name: None,
232                 manufacturer: MANUFACTURER.to_string(),
233                 product_name: PRODUCT_NAME.to_string(),
234                 bt_properties: None,
235             };
236             self.new_chip(CHIP_ID, DEVICE_ID, DEVICE_NAME, &create_params, wireless_adaptor)
237                 .unwrap()
238         }
239     }
240 
241     #[test]
test_new_and_get_with_singleton()242     fn test_new_and_get_with_singleton() {
243         let mocked_adaptor = mocked::new(
244             &mocked::CreateParams { chip_kind: ProtoChipKind::UNSPECIFIED },
245             ChipIdentifier(0),
246         );
247         let chip_manager = ChipManager::new(INITIAL_CHIP_ID);
248         let chip = chip_manager.new_test_chip(mocked_adaptor);
249 
250         // Check if the Chip has been successfully inserted
251         let chip_id = chip.id;
252         assert!(chip_manager.chips.read().unwrap().contains_key(&chip_id));
253 
254         // Check if the chip_manager can successfully fetch the chip
255         let chip_result = chip_manager.get_chip(&chip_id);
256         assert!(chip_result.is_some());
257 
258         // Check if the fields are correctly populated
259         let chip = chip_result.unwrap();
260         assert_eq!(chip.device_id, DEVICE_ID);
261         assert_eq!(chip.device_name, DEVICE_NAME);
262         assert_eq!(chip.kind, CHIP_KIND);
263         assert_eq!(chip.address, ADDRESS);
264         assert_eq!(chip.name, format!("chip-{chip_id}"));
265         assert_eq!(chip.manufacturer.read().unwrap().to_string(), MANUFACTURER);
266         assert_eq!(chip.product_name.read().unwrap().to_string(), PRODUCT_NAME);
267     }
268 
269     #[test]
test_chip_get_stats()270     fn test_chip_get_stats() {
271         // When wireless_adaptor is constructed
272         let mocked_adaptor = mocked::new(
273             &mocked::CreateParams { chip_kind: ProtoChipKind::UNSPECIFIED },
274             ChipIdentifier(0),
275         );
276         let chip_manager = ChipManager::new(INITIAL_CHIP_ID);
277 
278         let chip = chip_manager.new_test_chip(mocked_adaptor);
279         assert_eq!(netsim_radio_stats::Kind::UNSPECIFIED, chip.get_stats().first().unwrap().kind());
280     }
281 
282     #[test]
test_chip_get()283     fn test_chip_get() {
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         let chip = chip_manager.new_test_chip(mocked_adaptor);
290 
291         // Obtain actual chip.get()
292         let actual = chip.get().unwrap();
293 
294         // Construct expected ProtoChip
295         let mut expected = chip.wireless_adaptor.get();
296         expected.kind = EnumOrUnknown::new(chip.kind);
297         expected.id = chip.id.0;
298         expected.name.clone_from(&chip.name);
299         expected.manufacturer.clone_from(&chip.manufacturer.read().unwrap());
300         expected.product_name.clone_from(&chip.product_name.read().unwrap());
301 
302         // Compare
303         assert_eq!(expected, actual);
304     }
305 
306     #[test]
test_chip_patch()307     fn test_chip_patch() {
308         let mocked_adaptor = mocked::new(
309             &mocked::CreateParams { chip_kind: ProtoChipKind::UNSPECIFIED },
310             ChipIdentifier(0),
311         );
312         let chip_manager = ChipManager::new(INITIAL_CHIP_ID);
313         let chip = chip_manager.new_test_chip(mocked_adaptor);
314 
315         // Construct the patch body for modifying manufacturer and product_name
316         let mut patch_body = ProtoChip::new();
317         patch_body.manufacturer = "patched_manufacturer".to_string();
318         patch_body.product_name = "patched_product_name".to_string();
319 
320         // Perform Patch
321         assert!(chip.patch(&patch_body).is_ok());
322 
323         // Check if fields of chip has been patched
324         assert_eq!(patch_body.manufacturer, chip.manufacturer.read().unwrap().to_string());
325         assert_eq!(patch_body.product_name, chip.product_name.read().unwrap().to_string());
326     }
327 
328     // TODO (b/309529194)
329     // Implement wireless/mocked.rs to test wireless_adaptor level of patch and resets.
330 }
331