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 use netsim_proto::frontend::ListDeviceResponse; 16 use netsim_proto::model::{ 17 self, 18 chip::ble_beacon::advertise_settings, 19 chip::ble_beacon::{AdvertiseData, AdvertiseSettings}, 20 }; 21 use protobuf::MessageField; 22 use std::fmt; 23 24 const INDENT_WIDTH: usize = 2; 25 26 /// Displayer for model protobufs. Implements fmt::Display. 27 /// # Invariants 28 /// Displayed values **do not** end in a newline. 29 pub struct Displayer<T> { 30 value: T, 31 verbose: bool, 32 indent: usize, 33 } 34 35 impl<T> Displayer<T> { 36 /// Returns a new displayer for values of the provided type. new(value: T, verbose: bool) -> Self37 pub fn new(value: T, verbose: bool) -> Self { 38 Displayer { value, verbose, indent: 0 } 39 } 40 41 /// Indent the displayed string by a given amount. Returns `self`. indent(&mut self, current_indent: usize) -> &Self42 pub fn indent(&mut self, current_indent: usize) -> &Self { 43 self.indent = current_indent + INDENT_WIDTH; 44 self 45 } 46 } 47 48 impl fmt::Display for Displayer<ListDeviceResponse> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 50 let indent = self.indent; 51 52 let mut devices = self.value.devices.iter().peekable(); 53 while let Some(device) = devices.next() { 54 write!(f, "{:indent$}{}", "", Displayer::new(device, self.verbose))?; 55 if devices.peek().is_some() { 56 // We print the newline here instead of in the Device displayer because we don't want a newline before the very first device. 57 writeln!(f)?; 58 } 59 } 60 61 Ok(()) 62 } 63 } 64 65 impl fmt::Display for Displayer<&model::Device> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 67 let indent = self.indent; 68 let width = 9; 69 70 write!( 71 f, 72 "{:indent$}{:width$} {}", 73 "", 74 self.value.name, 75 Displayer::new(self.value.position.as_ref().unwrap_or_default(), self.verbose) 76 )?; 77 78 for chip in self.value.chips.iter() { 79 write!(f, "{:indent$}{}", "", Displayer::new(chip, self.verbose).indent(self.indent))?; 80 } 81 82 Ok(()) 83 } 84 } 85 86 impl fmt::Display for Displayer<&model::Chip> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 88 let indent = self.indent; 89 let width = 9; 90 91 match self.value.chip.as_ref() { 92 Some(model::chip::Chip::BleBeacon(ble_beacon)) => { 93 let radio = ble_beacon.bt.low_energy.as_ref().unwrap_or_default(); 94 let beacon_width = 16 + width; 95 96 if self.verbose || !radio.state.unwrap_or_default() { 97 writeln!(f)?; 98 write!( 99 f, 100 "{:indent$}{:beacon_width$} {}", 101 "", 102 format!("beacon-ble ({}):", self.value.name), 103 Displayer::new(radio, self.verbose), 104 )?; 105 } 106 107 if self.verbose { 108 writeln!(f)?; 109 write!(f, "{}", Displayer::new(ble_beacon, self.verbose).indent(self.indent))?; 110 } 111 } 112 Some(model::chip::Chip::Bt(bt)) => { 113 if let Some(ble) = bt.low_energy.as_ref() { 114 if self.verbose || !ble.state.unwrap_or_default() { 115 writeln!(f)?; 116 write!( 117 f, 118 "{:indent$}{:width$}{}", 119 "", 120 "ble: ", 121 Displayer::new(ble, self.verbose), 122 )?; 123 } 124 }; 125 126 if let Some(classic) = bt.classic.as_ref() { 127 if self.verbose || !classic.state.unwrap_or_default() { 128 writeln!(f)?; 129 write!( 130 f, 131 "{:indent$}{:width$}{}", 132 "", 133 "classic: ", 134 Displayer::new(classic, self.verbose), 135 )?; 136 } 137 }; 138 } 139 Some(model::chip::Chip::Wifi(wifi)) => { 140 if self.verbose || !wifi.state.unwrap_or_default() { 141 writeln!(f)?; 142 write!( 143 f, 144 "{:indent$}{:width$}{}", 145 "", 146 "wifi: ", 147 Displayer::new(wifi, self.verbose) 148 )?; 149 } 150 } 151 Some(model::chip::Chip::Uwb(uwb)) => { 152 if self.verbose || !uwb.state.unwrap_or_default() { 153 writeln!(f)?; 154 write!( 155 f, 156 "{:indent$}{:width$}{}", 157 "", 158 "uwb: ", 159 Displayer::new(uwb, self.verbose) 160 )?; 161 } 162 } 163 _ => { 164 if self.verbose { 165 writeln!(f)?; 166 write!(f, "{:indent$}Unknown chip", "")? 167 } 168 } 169 } 170 171 Ok(()) 172 } 173 } 174 175 impl fmt::Display for Displayer<&model::chip::BleBeacon> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 177 let indent = self.indent; 178 let address_width = 16; 179 write!(f, "{:indent$}address: {:address_width$}", "", self.value.address)?; 180 181 if self.value.settings.is_some() 182 && self.value.settings != MessageField::some(AdvertiseSettings::default()) 183 { 184 writeln!(f)?; 185 write!( 186 f, 187 "{:indent$}advertise settings:{}", 188 "", 189 Displayer::new(self.value.settings.as_ref().unwrap_or_default(), self.verbose) 190 .indent(self.indent) 191 )?; 192 } 193 194 if self.value.adv_data.is_some() 195 && self.value.adv_data != MessageField::some(AdvertiseData::default()) 196 { 197 writeln!(f)?; 198 write!( 199 f, 200 "{:indent$}advertise packet data:{}", 201 "", 202 Displayer::new(self.value.adv_data.as_ref().unwrap_or_default(), self.verbose) 203 .indent(self.indent) 204 )?; 205 } 206 207 // TODO(jmes): Add scan response data. 208 209 Ok(()) 210 } 211 } 212 213 impl fmt::Display for Displayer<&model::Position> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result214 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 215 let indent = self.indent; 216 let precision = 2; 217 218 if self.verbose 219 || (self.value.x != f32::default() 220 || self.value.y != f32::default() 221 || self.value.z != f32::default()) 222 { 223 write!( 224 f, 225 "{:indent$} position: {:.precision$}, {:.precision$}, {:.precision$}", 226 "", self.value.x, self.value.y, self.value.z, 227 )?; 228 } 229 230 Ok(()) 231 } 232 } 233 234 impl fmt::Display for Displayer<&model::chip::ble_beacon::AdvertiseSettings> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 236 let indent = self.indent; 237 let width = 25; 238 239 if let Some(tx_power) = self.value.tx_power.as_ref() { 240 writeln!(f)?; 241 write!(f, "{:indent$}{}", "", Displayer::new(tx_power, self.verbose))?; 242 } 243 244 if let Some(interval) = self.value.interval.as_ref() { 245 writeln!(f)?; 246 write!(f, "{:indent$}{}", "", Displayer::new(interval, self.verbose))?; 247 } 248 249 if self.value.scannable { 250 writeln!(f)?; 251 write!(f, "{:indent$}{:width$}: {}", "", "scannable", self.value.scannable)?; 252 } 253 254 if self.value.timeout != u64::default() { 255 writeln!(f)?; 256 write!(f, "{:indent$}{:width$}: {} ms", "", "timeout", self.value.timeout)?; 257 } 258 259 Ok(()) 260 } 261 } 262 263 impl fmt::Display for Displayer<&model::chip::ble_beacon::AdvertiseData> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result264 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 265 let indent = self.indent; 266 let width = 25; 267 268 if self.value.include_device_name != bool::default() { 269 writeln!(f)?; 270 write!( 271 f, 272 "{:indent$}{:width$}: {}", 273 "", "include device name", self.value.include_device_name 274 )?; 275 } 276 277 if self.value.include_tx_power_level != bool::default() { 278 writeln!(f)?; 279 write!( 280 f, 281 "{:indent$}{:width$}: {}", 282 "", "include tx power level", self.value.include_tx_power_level 283 )?; 284 } 285 286 if self.value.manufacturer_data != Vec::<u8>::default() { 287 writeln!(f)?; 288 write!( 289 f, 290 "{:indent$}{:width$}: {}", 291 "", 292 "manufacturer data bytes", 293 self.value.manufacturer_data.len() 294 )?; 295 } 296 297 Ok(()) 298 } 299 } 300 301 impl fmt::Display for Displayer<&advertise_settings::Interval> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result302 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 303 let indent = self.indent; 304 let width = 25; 305 306 match self.value { 307 advertise_settings::Interval::Milliseconds(interval) => { 308 write!(f, "{:indent$}{:width$}: {} ms", "", "interval", interval) 309 } 310 advertise_settings::Interval::AdvertiseMode(mode) => { 311 write!(f, "{:indent$}{:width$}: {:?}", "", "advertise mode", mode) 312 } 313 _ => Err(fmt::Error), 314 } 315 } 316 } 317 318 impl fmt::Display for Displayer<&advertise_settings::Tx_power> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result319 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 320 let indent = self.indent; 321 let width = 25; 322 323 match self.value { 324 advertise_settings::Tx_power::Dbm(dbm) => { 325 write!(f, "{:indent$}{:width$}: {} dBm", "", "tx power", dbm) 326 } 327 advertise_settings::Tx_power::TxPowerLevel(level) => { 328 write!(f, "{:indent$}{:width$}: {:?}", "", "tx power level", level) 329 } 330 _ => Err(fmt::Error), 331 } 332 } 333 } 334 335 impl fmt::Display for Displayer<&model::chip::Radio> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result336 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 337 let indent = self.indent; 338 let count_width = 9; 339 write!(f, "{:indent$}{}", "", Displayer::new(&self.value.state, self.verbose),)?; 340 341 if self.verbose { 342 write!( 343 f, 344 "| rx_count: {:count_width$} | tx_count: {:count_width$}", 345 self.value.rx_count, self.value.tx_count 346 )? 347 } 348 349 Ok(()) 350 } 351 } 352 353 impl fmt::Display for Displayer<&Option<bool>> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result354 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 355 let indent = self.indent; 356 let width = 9; 357 358 write!( 359 f, 360 "{:indent$}{:width$}", 361 "", 362 match self.value { 363 Some(true) => "up", 364 Some(false) => "down", 365 None => "unknown", 366 } 367 ) 368 } 369 } 370