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