1*cf78ab8cSAndroid Build Coastguard Worker // Copyright 2022 Google LLC 2*cf78ab8cSAndroid Build Coastguard Worker // 3*cf78ab8cSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); 4*cf78ab8cSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License. 5*cf78ab8cSAndroid Build Coastguard Worker // You may obtain a copy of the License at 6*cf78ab8cSAndroid Build Coastguard Worker // 7*cf78ab8cSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0 8*cf78ab8cSAndroid Build Coastguard Worker // 9*cf78ab8cSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software 10*cf78ab8cSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, 11*cf78ab8cSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*cf78ab8cSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and 13*cf78ab8cSAndroid Build Coastguard Worker // limitations under the License. 14*cf78ab8cSAndroid Build Coastguard Worker 15*cf78ab8cSAndroid Build Coastguard Worker use crate::ffi::frontend_client_ffi::{FrontendClient, GrpcMethod}; 16*cf78ab8cSAndroid Build Coastguard Worker use clap::builder::{PossibleValue, TypedValueParser}; 17*cf78ab8cSAndroid Build Coastguard Worker use clap::{Args, Parser, Subcommand, ValueEnum}; 18*cf78ab8cSAndroid Build Coastguard Worker use hex::{decode as hex_to_bytes, FromHexError}; 19*cf78ab8cSAndroid Build Coastguard Worker use netsim_common::util::time_display::TimeDisplay; 20*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::common::ChipKind; 21*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::frontend; 22*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::frontend::patch_capture_request::PatchCapture as PatchCaptureProto; 23*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::frontend::patch_device_request::PatchDeviceFields as PatchDeviceFieldsProto; 24*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::model::chip::ble_beacon::advertise_settings::{ 25*cf78ab8cSAndroid Build Coastguard Worker AdvertiseMode as AdvertiseModeProto, AdvertiseTxPower as AdvertiseTxPowerProto, 26*cf78ab8cSAndroid Build Coastguard Worker Interval as IntervalProto, Tx_power as TxPowerProto, 27*cf78ab8cSAndroid Build Coastguard Worker }; 28*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::model::chip::ble_beacon::{ 29*cf78ab8cSAndroid Build Coastguard Worker AdvertiseData as AdvertiseDataProto, AdvertiseSettings as AdvertiseSettingsProto, 30*cf78ab8cSAndroid Build Coastguard Worker }; 31*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::model::chip::{ 32*cf78ab8cSAndroid Build Coastguard Worker BleBeacon as Chip_Ble_Beacon, Bluetooth as Chip_Bluetooth, Chip as Chip_Type, 33*cf78ab8cSAndroid Build Coastguard Worker Radio as Chip_Radio, 34*cf78ab8cSAndroid Build Coastguard Worker }; 35*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::model::{ 36*cf78ab8cSAndroid Build Coastguard Worker self, chip_create, Chip, ChipCreate as ChipCreateProto, DeviceCreate as DeviceCreateProto, 37*cf78ab8cSAndroid Build Coastguard Worker Position, 38*cf78ab8cSAndroid Build Coastguard Worker }; 39*cf78ab8cSAndroid Build Coastguard Worker use protobuf::{Message, MessageField}; 40*cf78ab8cSAndroid Build Coastguard Worker use std::fmt; 41*cf78ab8cSAndroid Build Coastguard Worker use std::iter; 42*cf78ab8cSAndroid Build Coastguard Worker use std::str::FromStr; 43*cf78ab8cSAndroid Build Coastguard Worker use tracing::error; 44*cf78ab8cSAndroid Build Coastguard Worker 45*cf78ab8cSAndroid Build Coastguard Worker pub type BinaryProtobuf = Vec<u8>; 46*cf78ab8cSAndroid Build Coastguard Worker 47*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Parser)] 48*cf78ab8cSAndroid Build Coastguard Worker pub struct NetsimArgs { 49*cf78ab8cSAndroid Build Coastguard Worker #[command(subcommand)] 50*cf78ab8cSAndroid Build Coastguard Worker pub command: Command, 51*cf78ab8cSAndroid Build Coastguard Worker /// Set verbose mode 52*cf78ab8cSAndroid Build Coastguard Worker #[arg(short, long)] 53*cf78ab8cSAndroid Build Coastguard Worker pub verbose: bool, 54*cf78ab8cSAndroid Build Coastguard Worker /// Set custom grpc port 55*cf78ab8cSAndroid Build Coastguard Worker #[arg(short, long)] 56*cf78ab8cSAndroid Build Coastguard Worker pub port: Option<i32>, 57*cf78ab8cSAndroid Build Coastguard Worker /// Set netsimd instance number to connect 58*cf78ab8cSAndroid Build Coastguard Worker #[arg(short, long)] 59*cf78ab8cSAndroid Build Coastguard Worker pub instance: Option<u16>, 60*cf78ab8cSAndroid Build Coastguard Worker /// Set vsock cid:port pair 61*cf78ab8cSAndroid Build Coastguard Worker #[arg(long)] 62*cf78ab8cSAndroid Build Coastguard Worker pub vsock: Option<String>, 63*cf78ab8cSAndroid Build Coastguard Worker } 64*cf78ab8cSAndroid Build Coastguard Worker 65*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Subcommand)] 66*cf78ab8cSAndroid Build Coastguard Worker #[command(infer_subcommands = true)] 67*cf78ab8cSAndroid Build Coastguard Worker pub enum Command { 68*cf78ab8cSAndroid Build Coastguard Worker /// Print Netsim version information 69*cf78ab8cSAndroid Build Coastguard Worker Version, 70*cf78ab8cSAndroid Build Coastguard Worker /// Control the radio state of a device 71*cf78ab8cSAndroid Build Coastguard Worker Radio(Radio), 72*cf78ab8cSAndroid Build Coastguard Worker /// Set the device location 73*cf78ab8cSAndroid Build Coastguard Worker Move(Move), 74*cf78ab8cSAndroid Build Coastguard Worker /// Display device(s) information 75*cf78ab8cSAndroid Build Coastguard Worker Devices(Devices), 76*cf78ab8cSAndroid Build Coastguard Worker /// Reset Netsim device scene 77*cf78ab8cSAndroid Build Coastguard Worker Reset, 78*cf78ab8cSAndroid Build Coastguard Worker /// Open netsim Web UI 79*cf78ab8cSAndroid Build Coastguard Worker Gui, 80*cf78ab8cSAndroid Build Coastguard Worker /// Control the packet capture functionalities with commands: list, patch, get 81*cf78ab8cSAndroid Build Coastguard Worker #[command(subcommand, visible_alias("pcap"))] 82*cf78ab8cSAndroid Build Coastguard Worker Capture(Capture), 83*cf78ab8cSAndroid Build Coastguard Worker /// Opens netsim artifacts directory (log, pcaps) 84*cf78ab8cSAndroid Build Coastguard Worker Artifact, 85*cf78ab8cSAndroid Build Coastguard Worker /// A chip that sends advertisements at a set interval 86*cf78ab8cSAndroid Build Coastguard Worker #[command(subcommand)] 87*cf78ab8cSAndroid Build Coastguard Worker Beacon(Beacon), 88*cf78ab8cSAndroid Build Coastguard Worker /// Open Bumble Hive Web Page 89*cf78ab8cSAndroid Build Coastguard Worker Bumble, 90*cf78ab8cSAndroid Build Coastguard Worker } 91*cf78ab8cSAndroid Build Coastguard Worker 92*cf78ab8cSAndroid Build Coastguard Worker impl Command { 93*cf78ab8cSAndroid Build Coastguard Worker /// Return the generated request protobuf as a byte vector 94*cf78ab8cSAndroid Build Coastguard Worker /// The parsed command parameters are used to construct the request protobuf which is 95*cf78ab8cSAndroid Build Coastguard Worker /// returned as a byte vector that can be sent to the server. get_request_bytes(&self) -> BinaryProtobuf96*cf78ab8cSAndroid Build Coastguard Worker pub fn get_request_bytes(&self) -> BinaryProtobuf { 97*cf78ab8cSAndroid Build Coastguard Worker match self { 98*cf78ab8cSAndroid Build Coastguard Worker Command::Version => Vec::new(), 99*cf78ab8cSAndroid Build Coastguard Worker Command::Radio(cmd) => { 100*cf78ab8cSAndroid Build Coastguard Worker let mut chip = Chip { ..Default::default() }; 101*cf78ab8cSAndroid Build Coastguard Worker let chip_state = match cmd.status { 102*cf78ab8cSAndroid Build Coastguard Worker UpDownStatus::Up => true, 103*cf78ab8cSAndroid Build Coastguard Worker UpDownStatus::Down => false, 104*cf78ab8cSAndroid Build Coastguard Worker }; 105*cf78ab8cSAndroid Build Coastguard Worker if cmd.radio_type == RadioType::Wifi { 106*cf78ab8cSAndroid Build Coastguard Worker let mut wifi_chip = Chip_Radio::new(); 107*cf78ab8cSAndroid Build Coastguard Worker wifi_chip.state = chip_state.into(); 108*cf78ab8cSAndroid Build Coastguard Worker chip.set_wifi(wifi_chip); 109*cf78ab8cSAndroid Build Coastguard Worker chip.kind = ChipKind::WIFI.into(); 110*cf78ab8cSAndroid Build Coastguard Worker } else if cmd.radio_type == RadioType::Uwb { 111*cf78ab8cSAndroid Build Coastguard Worker let mut uwb_chip = Chip_Radio::new(); 112*cf78ab8cSAndroid Build Coastguard Worker uwb_chip.state = chip_state.into(); 113*cf78ab8cSAndroid Build Coastguard Worker chip.set_uwb(uwb_chip); 114*cf78ab8cSAndroid Build Coastguard Worker chip.kind = ChipKind::UWB.into(); 115*cf78ab8cSAndroid Build Coastguard Worker } else { 116*cf78ab8cSAndroid Build Coastguard Worker let mut bt_chip = Chip_Bluetooth::new(); 117*cf78ab8cSAndroid Build Coastguard Worker let mut bt_chip_radio = Chip_Radio::new(); 118*cf78ab8cSAndroid Build Coastguard Worker bt_chip_radio.state = chip_state.into(); 119*cf78ab8cSAndroid Build Coastguard Worker if cmd.radio_type == RadioType::Ble { 120*cf78ab8cSAndroid Build Coastguard Worker bt_chip.low_energy = Some(bt_chip_radio).into(); 121*cf78ab8cSAndroid Build Coastguard Worker } else { 122*cf78ab8cSAndroid Build Coastguard Worker bt_chip.classic = Some(bt_chip_radio).into(); 123*cf78ab8cSAndroid Build Coastguard Worker } 124*cf78ab8cSAndroid Build Coastguard Worker chip.kind = ChipKind::BLUETOOTH.into(); 125*cf78ab8cSAndroid Build Coastguard Worker chip.set_bt(bt_chip); 126*cf78ab8cSAndroid Build Coastguard Worker } 127*cf78ab8cSAndroid Build Coastguard Worker let mut result = frontend::PatchDeviceRequest::new(); 128*cf78ab8cSAndroid Build Coastguard Worker let mut device = PatchDeviceFieldsProto::new(); 129*cf78ab8cSAndroid Build Coastguard Worker device.name = Some(cmd.name.clone()); 130*cf78ab8cSAndroid Build Coastguard Worker device.chips.push(chip); 131*cf78ab8cSAndroid Build Coastguard Worker result.device = Some(device).into(); 132*cf78ab8cSAndroid Build Coastguard Worker result.write_to_bytes().unwrap() 133*cf78ab8cSAndroid Build Coastguard Worker } 134*cf78ab8cSAndroid Build Coastguard Worker Command::Move(cmd) => { 135*cf78ab8cSAndroid Build Coastguard Worker let mut result = frontend::PatchDeviceRequest::new(); 136*cf78ab8cSAndroid Build Coastguard Worker let mut device = PatchDeviceFieldsProto::new(); 137*cf78ab8cSAndroid Build Coastguard Worker let position = Position { 138*cf78ab8cSAndroid Build Coastguard Worker x: cmd.x, 139*cf78ab8cSAndroid Build Coastguard Worker y: cmd.y, 140*cf78ab8cSAndroid Build Coastguard Worker z: cmd.z.unwrap_or_default(), 141*cf78ab8cSAndroid Build Coastguard Worker ..Default::default() 142*cf78ab8cSAndroid Build Coastguard Worker }; 143*cf78ab8cSAndroid Build Coastguard Worker device.name = Some(cmd.name.clone()); 144*cf78ab8cSAndroid Build Coastguard Worker device.position = Some(position).into(); 145*cf78ab8cSAndroid Build Coastguard Worker result.device = Some(device).into(); 146*cf78ab8cSAndroid Build Coastguard Worker result.write_to_bytes().unwrap() 147*cf78ab8cSAndroid Build Coastguard Worker } 148*cf78ab8cSAndroid Build Coastguard Worker Command::Devices(_) => Vec::new(), 149*cf78ab8cSAndroid Build Coastguard Worker Command::Reset => Vec::new(), 150*cf78ab8cSAndroid Build Coastguard Worker Command::Gui => { 151*cf78ab8cSAndroid Build Coastguard Worker unimplemented!("get_request_bytes is not implemented for Gui Command."); 152*cf78ab8cSAndroid Build Coastguard Worker } 153*cf78ab8cSAndroid Build Coastguard Worker Command::Capture(cmd) => match cmd { 154*cf78ab8cSAndroid Build Coastguard Worker Capture::List(_) => Vec::new(), 155*cf78ab8cSAndroid Build Coastguard Worker Capture::Get(_) => { 156*cf78ab8cSAndroid Build Coastguard Worker unimplemented!("get_request_bytes not implemented for Capture Get command. Use get_requests instead.") 157*cf78ab8cSAndroid Build Coastguard Worker } 158*cf78ab8cSAndroid Build Coastguard Worker Capture::Patch(_) => { 159*cf78ab8cSAndroid Build Coastguard Worker unimplemented!("get_request_bytes not implemented for Capture Patch command. Use get_requests instead.") 160*cf78ab8cSAndroid Build Coastguard Worker } 161*cf78ab8cSAndroid Build Coastguard Worker }, 162*cf78ab8cSAndroid Build Coastguard Worker Command::Artifact => { 163*cf78ab8cSAndroid Build Coastguard Worker unimplemented!("get_request_bytes is not implemented for Artifact Command."); 164*cf78ab8cSAndroid Build Coastguard Worker } 165*cf78ab8cSAndroid Build Coastguard Worker Command::Beacon(action) => match action { 166*cf78ab8cSAndroid Build Coastguard Worker Beacon::Create(kind) => match kind { 167*cf78ab8cSAndroid Build Coastguard Worker BeaconCreate::Ble(args) => { 168*cf78ab8cSAndroid Build Coastguard Worker let device = MessageField::some(DeviceCreateProto { 169*cf78ab8cSAndroid Build Coastguard Worker name: args.device_name.clone().unwrap_or_default(), 170*cf78ab8cSAndroid Build Coastguard Worker chips: vec![ChipCreateProto { 171*cf78ab8cSAndroid Build Coastguard Worker name: args.chip_name.clone().unwrap_or_default(), 172*cf78ab8cSAndroid Build Coastguard Worker kind: ChipKind::BLUETOOTH_BEACON.into(), 173*cf78ab8cSAndroid Build Coastguard Worker chip: Some(chip_create::Chip::BleBeacon( 174*cf78ab8cSAndroid Build Coastguard Worker chip_create::BleBeaconCreate { 175*cf78ab8cSAndroid Build Coastguard Worker address: args.address.clone().unwrap_or_default(), 176*cf78ab8cSAndroid Build Coastguard Worker settings: MessageField::some((&args.settings).into()), 177*cf78ab8cSAndroid Build Coastguard Worker adv_data: MessageField::some((&args.advertise_data).into()), 178*cf78ab8cSAndroid Build Coastguard Worker scan_response: MessageField::some( 179*cf78ab8cSAndroid Build Coastguard Worker (&args.scan_response_data).into(), 180*cf78ab8cSAndroid Build Coastguard Worker ), 181*cf78ab8cSAndroid Build Coastguard Worker ..Default::default() 182*cf78ab8cSAndroid Build Coastguard Worker }, 183*cf78ab8cSAndroid Build Coastguard Worker )), 184*cf78ab8cSAndroid Build Coastguard Worker ..Default::default() 185*cf78ab8cSAndroid Build Coastguard Worker }], 186*cf78ab8cSAndroid Build Coastguard Worker ..Default::default() 187*cf78ab8cSAndroid Build Coastguard Worker }); 188*cf78ab8cSAndroid Build Coastguard Worker 189*cf78ab8cSAndroid Build Coastguard Worker let result = frontend::CreateDeviceRequest { device, ..Default::default() }; 190*cf78ab8cSAndroid Build Coastguard Worker result.write_to_bytes().unwrap() 191*cf78ab8cSAndroid Build Coastguard Worker } 192*cf78ab8cSAndroid Build Coastguard Worker }, 193*cf78ab8cSAndroid Build Coastguard Worker Beacon::Patch(kind) => match kind { 194*cf78ab8cSAndroid Build Coastguard Worker BeaconPatch::Ble(args) => { 195*cf78ab8cSAndroid Build Coastguard Worker let device = MessageField::some(PatchDeviceFieldsProto { 196*cf78ab8cSAndroid Build Coastguard Worker name: Some(args.device_name.clone()), 197*cf78ab8cSAndroid Build Coastguard Worker chips: vec![Chip { 198*cf78ab8cSAndroid Build Coastguard Worker name: args.chip_name.clone(), 199*cf78ab8cSAndroid Build Coastguard Worker kind: ChipKind::BLUETOOTH_BEACON.into(), 200*cf78ab8cSAndroid Build Coastguard Worker chip: Some(Chip_Type::BleBeacon(Chip_Ble_Beacon { 201*cf78ab8cSAndroid Build Coastguard Worker bt: MessageField::some(Chip_Bluetooth::new()), 202*cf78ab8cSAndroid Build Coastguard Worker address: args.address.clone().unwrap_or_default(), 203*cf78ab8cSAndroid Build Coastguard Worker settings: MessageField::some((&args.settings).into()), 204*cf78ab8cSAndroid Build Coastguard Worker adv_data: MessageField::some((&args.advertise_data).into()), 205*cf78ab8cSAndroid Build Coastguard Worker scan_response: MessageField::some( 206*cf78ab8cSAndroid Build Coastguard Worker (&args.scan_response_data).into(), 207*cf78ab8cSAndroid Build Coastguard Worker ), 208*cf78ab8cSAndroid Build Coastguard Worker ..Default::default() 209*cf78ab8cSAndroid Build Coastguard Worker })), 210*cf78ab8cSAndroid Build Coastguard Worker ..Default::default() 211*cf78ab8cSAndroid Build Coastguard Worker }], 212*cf78ab8cSAndroid Build Coastguard Worker ..Default::default() 213*cf78ab8cSAndroid Build Coastguard Worker }); 214*cf78ab8cSAndroid Build Coastguard Worker 215*cf78ab8cSAndroid Build Coastguard Worker let result = frontend::PatchDeviceRequest { device, ..Default::default() }; 216*cf78ab8cSAndroid Build Coastguard Worker result.write_to_bytes().unwrap() 217*cf78ab8cSAndroid Build Coastguard Worker } 218*cf78ab8cSAndroid Build Coastguard Worker }, 219*cf78ab8cSAndroid Build Coastguard Worker Beacon::Remove(_) => Vec::new(), 220*cf78ab8cSAndroid Build Coastguard Worker }, 221*cf78ab8cSAndroid Build Coastguard Worker Command::Bumble => { 222*cf78ab8cSAndroid Build Coastguard Worker unimplemented!("get_request_bytes is not implemented for Bumble Command."); 223*cf78ab8cSAndroid Build Coastguard Worker } 224*cf78ab8cSAndroid Build Coastguard Worker } 225*cf78ab8cSAndroid Build Coastguard Worker } 226*cf78ab8cSAndroid Build Coastguard Worker 227*cf78ab8cSAndroid Build Coastguard Worker /// Create and return the request protobuf(s) for the command. 228*cf78ab8cSAndroid Build Coastguard Worker /// In the case of a command with pattern argument(s) there may be multiple gRPC requests. 229*cf78ab8cSAndroid Build Coastguard Worker /// The parsed command parameters are used to construct the request protobuf. 230*cf78ab8cSAndroid Build Coastguard Worker /// The client is used to send gRPC call(s) to retrieve information needed for request protobufs. get_requests(&mut self, client: &cxx::UniquePtr<FrontendClient>) -> Vec<BinaryProtobuf>231*cf78ab8cSAndroid Build Coastguard Worker pub fn get_requests(&mut self, client: &cxx::UniquePtr<FrontendClient>) -> Vec<BinaryProtobuf> { 232*cf78ab8cSAndroid Build Coastguard Worker match self { 233*cf78ab8cSAndroid Build Coastguard Worker Command::Capture(Capture::Patch(cmd)) => { 234*cf78ab8cSAndroid Build Coastguard Worker let mut reqs = Vec::new(); 235*cf78ab8cSAndroid Build Coastguard Worker let filtered_captures = Self::get_filtered_captures(client, &cmd.patterns); 236*cf78ab8cSAndroid Build Coastguard Worker // Create a request for each capture 237*cf78ab8cSAndroid Build Coastguard Worker for capture in &filtered_captures { 238*cf78ab8cSAndroid Build Coastguard Worker let mut result = frontend::PatchCaptureRequest::new(); 239*cf78ab8cSAndroid Build Coastguard Worker result.id = capture.id; 240*cf78ab8cSAndroid Build Coastguard Worker let capture_state = match cmd.state { 241*cf78ab8cSAndroid Build Coastguard Worker OnOffState::On => true, 242*cf78ab8cSAndroid Build Coastguard Worker OnOffState::Off => false, 243*cf78ab8cSAndroid Build Coastguard Worker }; 244*cf78ab8cSAndroid Build Coastguard Worker let mut patch_capture = PatchCaptureProto::new(); 245*cf78ab8cSAndroid Build Coastguard Worker patch_capture.state = capture_state.into(); 246*cf78ab8cSAndroid Build Coastguard Worker result.patch = Some(patch_capture).into(); 247*cf78ab8cSAndroid Build Coastguard Worker reqs.push(result.write_to_bytes().unwrap()) 248*cf78ab8cSAndroid Build Coastguard Worker } 249*cf78ab8cSAndroid Build Coastguard Worker reqs 250*cf78ab8cSAndroid Build Coastguard Worker } 251*cf78ab8cSAndroid Build Coastguard Worker Command::Capture(Capture::Get(cmd)) => { 252*cf78ab8cSAndroid Build Coastguard Worker let mut reqs = Vec::new(); 253*cf78ab8cSAndroid Build Coastguard Worker let filtered_captures = Self::get_filtered_captures(client, &cmd.patterns); 254*cf78ab8cSAndroid Build Coastguard Worker // Create a request for each capture 255*cf78ab8cSAndroid Build Coastguard Worker for capture in &filtered_captures { 256*cf78ab8cSAndroid Build Coastguard Worker let mut result = frontend::GetCaptureRequest::new(); 257*cf78ab8cSAndroid Build Coastguard Worker result.id = capture.id; 258*cf78ab8cSAndroid Build Coastguard Worker reqs.push(result.write_to_bytes().unwrap()); 259*cf78ab8cSAndroid Build Coastguard Worker let time_display = TimeDisplay::new( 260*cf78ab8cSAndroid Build Coastguard Worker capture.timestamp.get_or_default().seconds, 261*cf78ab8cSAndroid Build Coastguard Worker capture.timestamp.get_or_default().nanos as u32, 262*cf78ab8cSAndroid Build Coastguard Worker ); 263*cf78ab8cSAndroid Build Coastguard Worker let file_extension = "pcap"; 264*cf78ab8cSAndroid Build Coastguard Worker cmd.filenames.push(format!( 265*cf78ab8cSAndroid Build Coastguard Worker "netsim-{:?}-{}-{}-{}.{}", 266*cf78ab8cSAndroid Build Coastguard Worker capture.id, 267*cf78ab8cSAndroid Build Coastguard Worker capture.device_name.to_owned().replace(' ', "_"), 268*cf78ab8cSAndroid Build Coastguard Worker Self::chip_kind_to_string(capture.chip_kind.enum_value_or_default()), 269*cf78ab8cSAndroid Build Coastguard Worker time_display.utc_display(), 270*cf78ab8cSAndroid Build Coastguard Worker file_extension 271*cf78ab8cSAndroid Build Coastguard Worker )); 272*cf78ab8cSAndroid Build Coastguard Worker } 273*cf78ab8cSAndroid Build Coastguard Worker reqs 274*cf78ab8cSAndroid Build Coastguard Worker } 275*cf78ab8cSAndroid Build Coastguard Worker _ => { 276*cf78ab8cSAndroid Build Coastguard Worker unimplemented!( 277*cf78ab8cSAndroid Build Coastguard Worker "get_requests not implemented for this command. Use get_request_bytes instead." 278*cf78ab8cSAndroid Build Coastguard Worker ) 279*cf78ab8cSAndroid Build Coastguard Worker } 280*cf78ab8cSAndroid Build Coastguard Worker } 281*cf78ab8cSAndroid Build Coastguard Worker } 282*cf78ab8cSAndroid Build Coastguard Worker get_filtered_captures( client: &cxx::UniquePtr<FrontendClient>, patterns: &[String], ) -> Vec<model::Capture>283*cf78ab8cSAndroid Build Coastguard Worker fn get_filtered_captures( 284*cf78ab8cSAndroid Build Coastguard Worker client: &cxx::UniquePtr<FrontendClient>, 285*cf78ab8cSAndroid Build Coastguard Worker patterns: &[String], 286*cf78ab8cSAndroid Build Coastguard Worker ) -> Vec<model::Capture> { 287*cf78ab8cSAndroid Build Coastguard Worker // Get list of captures 288*cf78ab8cSAndroid Build Coastguard Worker let result = client.send_grpc(&GrpcMethod::ListCapture, &Vec::new()); 289*cf78ab8cSAndroid Build Coastguard Worker if !result.is_ok() { 290*cf78ab8cSAndroid Build Coastguard Worker error!("ListCapture Grpc call error: {}", result.err()); 291*cf78ab8cSAndroid Build Coastguard Worker return Vec::new(); 292*cf78ab8cSAndroid Build Coastguard Worker } 293*cf78ab8cSAndroid Build Coastguard Worker let mut response = 294*cf78ab8cSAndroid Build Coastguard Worker frontend::ListCaptureResponse::parse_from_bytes(result.byte_vec().as_slice()).unwrap(); 295*cf78ab8cSAndroid Build Coastguard Worker if !patterns.is_empty() { 296*cf78ab8cSAndroid Build Coastguard Worker // Filter out list of captures with matching patterns 297*cf78ab8cSAndroid Build Coastguard Worker Self::filter_captures(&mut response.captures, patterns) 298*cf78ab8cSAndroid Build Coastguard Worker } 299*cf78ab8cSAndroid Build Coastguard Worker response.captures 300*cf78ab8cSAndroid Build Coastguard Worker } 301*cf78ab8cSAndroid Build Coastguard Worker } 302*cf78ab8cSAndroid Build Coastguard Worker 303*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Args)] 304*cf78ab8cSAndroid Build Coastguard Worker pub struct Radio { 305*cf78ab8cSAndroid Build Coastguard Worker /// Radio type 306*cf78ab8cSAndroid Build Coastguard Worker #[arg(value_enum, ignore_case = true)] 307*cf78ab8cSAndroid Build Coastguard Worker pub radio_type: RadioType, 308*cf78ab8cSAndroid Build Coastguard Worker /// Radio status 309*cf78ab8cSAndroid Build Coastguard Worker #[arg(value_enum, ignore_case = true)] 310*cf78ab8cSAndroid Build Coastguard Worker pub status: UpDownStatus, 311*cf78ab8cSAndroid Build Coastguard Worker /// Device name 312*cf78ab8cSAndroid Build Coastguard Worker pub name: String, 313*cf78ab8cSAndroid Build Coastguard Worker } 314*cf78ab8cSAndroid Build Coastguard Worker 315*cf78ab8cSAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)] 316*cf78ab8cSAndroid Build Coastguard Worker pub enum RadioType { 317*cf78ab8cSAndroid Build Coastguard Worker Ble, 318*cf78ab8cSAndroid Build Coastguard Worker Classic, 319*cf78ab8cSAndroid Build Coastguard Worker Wifi, 320*cf78ab8cSAndroid Build Coastguard Worker Uwb, 321*cf78ab8cSAndroid Build Coastguard Worker } 322*cf78ab8cSAndroid Build Coastguard Worker 323*cf78ab8cSAndroid Build Coastguard Worker impl fmt::Display for RadioType { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result324*cf78ab8cSAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 325*cf78ab8cSAndroid Build Coastguard Worker write!(f, "{:?}", self) 326*cf78ab8cSAndroid Build Coastguard Worker } 327*cf78ab8cSAndroid Build Coastguard Worker } 328*cf78ab8cSAndroid Build Coastguard Worker 329*cf78ab8cSAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)] 330*cf78ab8cSAndroid Build Coastguard Worker pub enum UpDownStatus { 331*cf78ab8cSAndroid Build Coastguard Worker Up, 332*cf78ab8cSAndroid Build Coastguard Worker Down, 333*cf78ab8cSAndroid Build Coastguard Worker } 334*cf78ab8cSAndroid Build Coastguard Worker 335*cf78ab8cSAndroid Build Coastguard Worker impl fmt::Display for UpDownStatus { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result336*cf78ab8cSAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 337*cf78ab8cSAndroid Build Coastguard Worker write!(f, "{:?}", self) 338*cf78ab8cSAndroid Build Coastguard Worker } 339*cf78ab8cSAndroid Build Coastguard Worker } 340*cf78ab8cSAndroid Build Coastguard Worker 341*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Args)] 342*cf78ab8cSAndroid Build Coastguard Worker pub struct Move { 343*cf78ab8cSAndroid Build Coastguard Worker /// Device name 344*cf78ab8cSAndroid Build Coastguard Worker pub name: String, 345*cf78ab8cSAndroid Build Coastguard Worker /// x position of device 346*cf78ab8cSAndroid Build Coastguard Worker pub x: f32, 347*cf78ab8cSAndroid Build Coastguard Worker /// y position of device 348*cf78ab8cSAndroid Build Coastguard Worker pub y: f32, 349*cf78ab8cSAndroid Build Coastguard Worker /// Optional z position of device 350*cf78ab8cSAndroid Build Coastguard Worker pub z: Option<f32>, 351*cf78ab8cSAndroid Build Coastguard Worker } 352*cf78ab8cSAndroid Build Coastguard Worker 353*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Args)] 354*cf78ab8cSAndroid Build Coastguard Worker pub struct Devices { 355*cf78ab8cSAndroid Build Coastguard Worker /// Continuously print device(s) information every second 356*cf78ab8cSAndroid Build Coastguard Worker #[arg(short, long)] 357*cf78ab8cSAndroid Build Coastguard Worker pub continuous: bool, 358*cf78ab8cSAndroid Build Coastguard Worker } 359*cf78ab8cSAndroid Build Coastguard Worker 360*cf78ab8cSAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)] 361*cf78ab8cSAndroid Build Coastguard Worker pub enum OnOffState { 362*cf78ab8cSAndroid Build Coastguard Worker On, 363*cf78ab8cSAndroid Build Coastguard Worker Off, 364*cf78ab8cSAndroid Build Coastguard Worker } 365*cf78ab8cSAndroid Build Coastguard Worker 366*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Subcommand)] 367*cf78ab8cSAndroid Build Coastguard Worker pub enum Beacon { 368*cf78ab8cSAndroid Build Coastguard Worker /// Create a beacon chip 369*cf78ab8cSAndroid Build Coastguard Worker #[command(subcommand)] 370*cf78ab8cSAndroid Build Coastguard Worker Create(BeaconCreate), 371*cf78ab8cSAndroid Build Coastguard Worker /// Modify a beacon chip 372*cf78ab8cSAndroid Build Coastguard Worker #[command(subcommand)] 373*cf78ab8cSAndroid Build Coastguard Worker Patch(BeaconPatch), 374*cf78ab8cSAndroid Build Coastguard Worker /// Remove a beacon chip 375*cf78ab8cSAndroid Build Coastguard Worker Remove(BeaconRemove), 376*cf78ab8cSAndroid Build Coastguard Worker } 377*cf78ab8cSAndroid Build Coastguard Worker 378*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Subcommand)] 379*cf78ab8cSAndroid Build Coastguard Worker pub enum BeaconCreate { 380*cf78ab8cSAndroid Build Coastguard Worker /// Create a Bluetooth low-energy beacon chip 381*cf78ab8cSAndroid Build Coastguard Worker Ble(BeaconCreateBle), 382*cf78ab8cSAndroid Build Coastguard Worker } 383*cf78ab8cSAndroid Build Coastguard Worker 384*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Args)] 385*cf78ab8cSAndroid Build Coastguard Worker pub struct BeaconCreateBle { 386*cf78ab8cSAndroid Build Coastguard Worker /// Name of the device to create 387*cf78ab8cSAndroid Build Coastguard Worker pub device_name: Option<String>, 388*cf78ab8cSAndroid Build Coastguard Worker /// Name of the beacon chip to create within the new device. May only be specified if device_name is specified 389*cf78ab8cSAndroid Build Coastguard Worker pub chip_name: Option<String>, 390*cf78ab8cSAndroid Build Coastguard Worker /// Bluetooth address of the beacon. Must be a 6-byte hexadecimal string with each byte separated by a colon. Will be generated if not provided 391*cf78ab8cSAndroid Build Coastguard Worker #[arg(long)] 392*cf78ab8cSAndroid Build Coastguard Worker pub address: Option<String>, 393*cf78ab8cSAndroid Build Coastguard Worker #[command(flatten)] 394*cf78ab8cSAndroid Build Coastguard Worker pub settings: BeaconBleSettings, 395*cf78ab8cSAndroid Build Coastguard Worker #[command(flatten)] 396*cf78ab8cSAndroid Build Coastguard Worker pub advertise_data: BeaconBleAdvertiseData, 397*cf78ab8cSAndroid Build Coastguard Worker #[command(flatten)] 398*cf78ab8cSAndroid Build Coastguard Worker pub scan_response_data: BeaconBleScanResponseData, 399*cf78ab8cSAndroid Build Coastguard Worker } 400*cf78ab8cSAndroid Build Coastguard Worker 401*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Subcommand)] 402*cf78ab8cSAndroid Build Coastguard Worker pub enum BeaconPatch { 403*cf78ab8cSAndroid Build Coastguard Worker /// Modify a Bluetooth low-energy beacon chip 404*cf78ab8cSAndroid Build Coastguard Worker Ble(BeaconPatchBle), 405*cf78ab8cSAndroid Build Coastguard Worker } 406*cf78ab8cSAndroid Build Coastguard Worker 407*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Args)] 408*cf78ab8cSAndroid Build Coastguard Worker pub struct BeaconPatchBle { 409*cf78ab8cSAndroid Build Coastguard Worker /// Name of the device that contains the chip 410*cf78ab8cSAndroid Build Coastguard Worker pub device_name: String, 411*cf78ab8cSAndroid Build Coastguard Worker /// Name of the beacon chip to modify 412*cf78ab8cSAndroid Build Coastguard Worker pub chip_name: String, 413*cf78ab8cSAndroid Build Coastguard Worker /// Bluetooth address of the beacon. Must be a 6-byte hexadecimal string with each byte separated by a colon 414*cf78ab8cSAndroid Build Coastguard Worker #[arg(long)] 415*cf78ab8cSAndroid Build Coastguard Worker pub address: Option<String>, 416*cf78ab8cSAndroid Build Coastguard Worker #[command(flatten)] 417*cf78ab8cSAndroid Build Coastguard Worker pub settings: BeaconBleSettings, 418*cf78ab8cSAndroid Build Coastguard Worker #[command(flatten)] 419*cf78ab8cSAndroid Build Coastguard Worker pub advertise_data: BeaconBleAdvertiseData, 420*cf78ab8cSAndroid Build Coastguard Worker #[command(flatten)] 421*cf78ab8cSAndroid Build Coastguard Worker pub scan_response_data: BeaconBleScanResponseData, 422*cf78ab8cSAndroid Build Coastguard Worker } 423*cf78ab8cSAndroid Build Coastguard Worker 424*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Args)] 425*cf78ab8cSAndroid Build Coastguard Worker pub struct BeaconRemove { 426*cf78ab8cSAndroid Build Coastguard Worker /// Name of the device to remove 427*cf78ab8cSAndroid Build Coastguard Worker pub device_name: String, 428*cf78ab8cSAndroid Build Coastguard Worker /// Name of the beacon chip to remove. Can be omitted if the device has exactly 1 chip 429*cf78ab8cSAndroid Build Coastguard Worker pub chip_name: Option<String>, 430*cf78ab8cSAndroid Build Coastguard Worker } 431*cf78ab8cSAndroid Build Coastguard Worker 432*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Args)] 433*cf78ab8cSAndroid Build Coastguard Worker pub struct BeaconBleAdvertiseData { 434*cf78ab8cSAndroid Build Coastguard Worker /// Whether the device name should be included in the advertise packet 435*cf78ab8cSAndroid Build Coastguard Worker #[arg(long, required = false)] 436*cf78ab8cSAndroid Build Coastguard Worker pub include_device_name: bool, 437*cf78ab8cSAndroid Build Coastguard Worker /// Whether the transmission power level should be included in the advertise packet 438*cf78ab8cSAndroid Build Coastguard Worker #[arg(long, required = false)] 439*cf78ab8cSAndroid Build Coastguard Worker pub include_tx_power_level: bool, 440*cf78ab8cSAndroid Build Coastguard Worker /// Manufacturer-specific data given as bytes in hexadecimal 441*cf78ab8cSAndroid Build Coastguard Worker #[arg(long)] 442*cf78ab8cSAndroid Build Coastguard Worker pub manufacturer_data: Option<ParsableBytes>, 443*cf78ab8cSAndroid Build Coastguard Worker } 444*cf78ab8cSAndroid Build Coastguard Worker 445*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Clone)] 446*cf78ab8cSAndroid Build Coastguard Worker pub struct ParsableBytes(Vec<u8>); 447*cf78ab8cSAndroid Build Coastguard Worker 448*cf78ab8cSAndroid Build Coastguard Worker impl ParsableBytes { unwrap(self) -> Vec<u8>449*cf78ab8cSAndroid Build Coastguard Worker fn unwrap(self) -> Vec<u8> { 450*cf78ab8cSAndroid Build Coastguard Worker self.0 451*cf78ab8cSAndroid Build Coastguard Worker } 452*cf78ab8cSAndroid Build Coastguard Worker } 453*cf78ab8cSAndroid Build Coastguard Worker 454*cf78ab8cSAndroid Build Coastguard Worker impl FromStr for ParsableBytes { 455*cf78ab8cSAndroid Build Coastguard Worker type Err = FromHexError; from_str(s: &str) -> Result<Self, Self::Err>456*cf78ab8cSAndroid Build Coastguard Worker fn from_str(s: &str) -> Result<Self, Self::Err> { 457*cf78ab8cSAndroid Build Coastguard Worker hex_to_bytes(s.strip_prefix("0x").unwrap_or(s)).map(ParsableBytes) 458*cf78ab8cSAndroid Build Coastguard Worker } 459*cf78ab8cSAndroid Build Coastguard Worker } 460*cf78ab8cSAndroid Build Coastguard Worker 461*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Args)] 462*cf78ab8cSAndroid Build Coastguard Worker pub struct BeaconBleScanResponseData { 463*cf78ab8cSAndroid Build Coastguard Worker /// Whether the device name should be included in the scan response packet 464*cf78ab8cSAndroid Build Coastguard Worker #[arg(long, required = false)] 465*cf78ab8cSAndroid Build Coastguard Worker pub scan_response_include_device_name: bool, 466*cf78ab8cSAndroid Build Coastguard Worker /// Whether the transmission power level should be included in the scan response packet 467*cf78ab8cSAndroid Build Coastguard Worker #[arg(long, required = false)] 468*cf78ab8cSAndroid Build Coastguard Worker pub scan_response_include_tx_power_level: bool, 469*cf78ab8cSAndroid Build Coastguard Worker /// Manufacturer-specific data to include in the scan response packet given as bytes in hexadecimal 470*cf78ab8cSAndroid Build Coastguard Worker #[arg(long, value_name = "MANUFACTURER_DATA")] 471*cf78ab8cSAndroid Build Coastguard Worker pub scan_response_manufacturer_data: Option<ParsableBytes>, 472*cf78ab8cSAndroid Build Coastguard Worker } 473*cf78ab8cSAndroid Build Coastguard Worker 474*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Args)] 475*cf78ab8cSAndroid Build Coastguard Worker pub struct BeaconBleSettings { 476*cf78ab8cSAndroid Build Coastguard Worker /// Set advertise mode to control the advertising latency 477*cf78ab8cSAndroid Build Coastguard Worker #[arg(long, value_parser = IntervalParser)] 478*cf78ab8cSAndroid Build Coastguard Worker pub advertise_mode: Option<Interval>, 479*cf78ab8cSAndroid Build Coastguard Worker /// Set advertise TX power level to control the beacon's transmission power 480*cf78ab8cSAndroid Build Coastguard Worker #[arg(long, value_parser = TxPowerParser, allow_hyphen_values = true)] 481*cf78ab8cSAndroid Build Coastguard Worker pub tx_power_level: Option<TxPower>, 482*cf78ab8cSAndroid Build Coastguard Worker /// Set whether the beacon will respond to scan requests 483*cf78ab8cSAndroid Build Coastguard Worker #[arg(long)] 484*cf78ab8cSAndroid Build Coastguard Worker pub scannable: bool, 485*cf78ab8cSAndroid Build Coastguard Worker /// Limit advertising to an amount of time given in milliseconds 486*cf78ab8cSAndroid Build Coastguard Worker #[arg(long, value_name = "MS")] 487*cf78ab8cSAndroid Build Coastguard Worker pub timeout: Option<u64>, 488*cf78ab8cSAndroid Build Coastguard Worker } 489*cf78ab8cSAndroid Build Coastguard Worker 490*cf78ab8cSAndroid Build Coastguard Worker #[derive(Clone, Debug)] 491*cf78ab8cSAndroid Build Coastguard Worker pub enum Interval { 492*cf78ab8cSAndroid Build Coastguard Worker Mode(AdvertiseMode), 493*cf78ab8cSAndroid Build Coastguard Worker Milliseconds(u64), 494*cf78ab8cSAndroid Build Coastguard Worker } 495*cf78ab8cSAndroid Build Coastguard Worker 496*cf78ab8cSAndroid Build Coastguard Worker #[derive(Clone)] 497*cf78ab8cSAndroid Build Coastguard Worker struct IntervalParser; 498*cf78ab8cSAndroid Build Coastguard Worker 499*cf78ab8cSAndroid Build Coastguard Worker impl TypedValueParser for IntervalParser { 500*cf78ab8cSAndroid Build Coastguard Worker type Value = Interval; 501*cf78ab8cSAndroid Build Coastguard Worker parse_ref( &self, cmd: &clap::Command, arg: Option<&clap::Arg>, value: &std::ffi::OsStr, ) -> Result<Self::Value, clap::Error>502*cf78ab8cSAndroid Build Coastguard Worker fn parse_ref( 503*cf78ab8cSAndroid Build Coastguard Worker &self, 504*cf78ab8cSAndroid Build Coastguard Worker cmd: &clap::Command, 505*cf78ab8cSAndroid Build Coastguard Worker arg: Option<&clap::Arg>, 506*cf78ab8cSAndroid Build Coastguard Worker value: &std::ffi::OsStr, 507*cf78ab8cSAndroid Build Coastguard Worker ) -> Result<Self::Value, clap::Error> { 508*cf78ab8cSAndroid Build Coastguard Worker let millis_parser = clap::value_parser!(u64); 509*cf78ab8cSAndroid Build Coastguard Worker let mode_parser = clap::value_parser!(AdvertiseMode); 510*cf78ab8cSAndroid Build Coastguard Worker 511*cf78ab8cSAndroid Build Coastguard Worker mode_parser 512*cf78ab8cSAndroid Build Coastguard Worker .parse_ref(cmd, arg, value) 513*cf78ab8cSAndroid Build Coastguard Worker .map(Self::Value::Mode) 514*cf78ab8cSAndroid Build Coastguard Worker .or(millis_parser.parse_ref(cmd, arg, value).map(Self::Value::Milliseconds)) 515*cf78ab8cSAndroid Build Coastguard Worker } 516*cf78ab8cSAndroid Build Coastguard Worker possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>>517*cf78ab8cSAndroid Build Coastguard Worker fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> { 518*cf78ab8cSAndroid Build Coastguard Worker Some(Box::new( 519*cf78ab8cSAndroid Build Coastguard Worker AdvertiseMode::value_variants().iter().map(|v| v.to_possible_value().unwrap()).chain( 520*cf78ab8cSAndroid Build Coastguard Worker iter::once( 521*cf78ab8cSAndroid Build Coastguard Worker PossibleValue::new("<MS>").help("An exact advertise interval in milliseconds"), 522*cf78ab8cSAndroid Build Coastguard Worker ), 523*cf78ab8cSAndroid Build Coastguard Worker ), 524*cf78ab8cSAndroid Build Coastguard Worker )) 525*cf78ab8cSAndroid Build Coastguard Worker } 526*cf78ab8cSAndroid Build Coastguard Worker } 527*cf78ab8cSAndroid Build Coastguard Worker 528*cf78ab8cSAndroid Build Coastguard Worker #[derive(Clone, Debug)] 529*cf78ab8cSAndroid Build Coastguard Worker pub enum TxPower { 530*cf78ab8cSAndroid Build Coastguard Worker Level(TxPowerLevel), 531*cf78ab8cSAndroid Build Coastguard Worker Dbm(i8), 532*cf78ab8cSAndroid Build Coastguard Worker } 533*cf78ab8cSAndroid Build Coastguard Worker 534*cf78ab8cSAndroid Build Coastguard Worker #[derive(Clone)] 535*cf78ab8cSAndroid Build Coastguard Worker struct TxPowerParser; 536*cf78ab8cSAndroid Build Coastguard Worker 537*cf78ab8cSAndroid Build Coastguard Worker impl TypedValueParser for TxPowerParser { 538*cf78ab8cSAndroid Build Coastguard Worker type Value = TxPower; 539*cf78ab8cSAndroid Build Coastguard Worker parse_ref( &self, cmd: &clap::Command, arg: Option<&clap::Arg>, value: &std::ffi::OsStr, ) -> Result<Self::Value, clap::Error>540*cf78ab8cSAndroid Build Coastguard Worker fn parse_ref( 541*cf78ab8cSAndroid Build Coastguard Worker &self, 542*cf78ab8cSAndroid Build Coastguard Worker cmd: &clap::Command, 543*cf78ab8cSAndroid Build Coastguard Worker arg: Option<&clap::Arg>, 544*cf78ab8cSAndroid Build Coastguard Worker value: &std::ffi::OsStr, 545*cf78ab8cSAndroid Build Coastguard Worker ) -> Result<Self::Value, clap::Error> { 546*cf78ab8cSAndroid Build Coastguard Worker let dbm_parser = clap::value_parser!(i8); 547*cf78ab8cSAndroid Build Coastguard Worker let level_parser = clap::value_parser!(TxPowerLevel); 548*cf78ab8cSAndroid Build Coastguard Worker 549*cf78ab8cSAndroid Build Coastguard Worker level_parser 550*cf78ab8cSAndroid Build Coastguard Worker .parse_ref(cmd, arg, value) 551*cf78ab8cSAndroid Build Coastguard Worker .map(Self::Value::Level) 552*cf78ab8cSAndroid Build Coastguard Worker .or(dbm_parser.parse_ref(cmd, arg, value).map(Self::Value::Dbm)) 553*cf78ab8cSAndroid Build Coastguard Worker } 554*cf78ab8cSAndroid Build Coastguard Worker possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>>555*cf78ab8cSAndroid Build Coastguard Worker fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> { 556*cf78ab8cSAndroid Build Coastguard Worker Some(Box::new( 557*cf78ab8cSAndroid Build Coastguard Worker TxPowerLevel::value_variants().iter().map(|v| v.to_possible_value().unwrap()).chain( 558*cf78ab8cSAndroid Build Coastguard Worker iter::once( 559*cf78ab8cSAndroid Build Coastguard Worker PossibleValue::new("<DBM>").help("An exact transmit power level in dBm"), 560*cf78ab8cSAndroid Build Coastguard Worker ), 561*cf78ab8cSAndroid Build Coastguard Worker ), 562*cf78ab8cSAndroid Build Coastguard Worker )) 563*cf78ab8cSAndroid Build Coastguard Worker } 564*cf78ab8cSAndroid Build Coastguard Worker } 565*cf78ab8cSAndroid Build Coastguard Worker 566*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Clone, ValueEnum)] 567*cf78ab8cSAndroid Build Coastguard Worker pub enum AdvertiseMode { 568*cf78ab8cSAndroid Build Coastguard Worker /// Lowest power consumption, preferred advertising mode 569*cf78ab8cSAndroid Build Coastguard Worker LowPower, 570*cf78ab8cSAndroid Build Coastguard Worker /// Balanced between advertising frequency and power consumption 571*cf78ab8cSAndroid Build Coastguard Worker Balanced, 572*cf78ab8cSAndroid Build Coastguard Worker /// Highest power consumption 573*cf78ab8cSAndroid Build Coastguard Worker LowLatency, 574*cf78ab8cSAndroid Build Coastguard Worker } 575*cf78ab8cSAndroid Build Coastguard Worker 576*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Clone, ValueEnum)] 577*cf78ab8cSAndroid Build Coastguard Worker pub enum TxPowerLevel { 578*cf78ab8cSAndroid Build Coastguard Worker /// Lowest transmission power level 579*cf78ab8cSAndroid Build Coastguard Worker UltraLow, 580*cf78ab8cSAndroid Build Coastguard Worker /// Low transmission power level 581*cf78ab8cSAndroid Build Coastguard Worker Low, 582*cf78ab8cSAndroid Build Coastguard Worker /// Medium transmission power level 583*cf78ab8cSAndroid Build Coastguard Worker Medium, 584*cf78ab8cSAndroid Build Coastguard Worker /// High transmission power level 585*cf78ab8cSAndroid Build Coastguard Worker High, 586*cf78ab8cSAndroid Build Coastguard Worker } 587*cf78ab8cSAndroid Build Coastguard Worker 588*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Subcommand)] 589*cf78ab8cSAndroid Build Coastguard Worker pub enum Capture { 590*cf78ab8cSAndroid Build Coastguard Worker /// List currently available Captures (packet captures) 591*cf78ab8cSAndroid Build Coastguard Worker List(ListCapture), 592*cf78ab8cSAndroid Build Coastguard Worker /// Patch a Capture source to turn packet capture on/off 593*cf78ab8cSAndroid Build Coastguard Worker Patch(PatchCapture), 594*cf78ab8cSAndroid Build Coastguard Worker /// Download the packet capture content 595*cf78ab8cSAndroid Build Coastguard Worker Get(GetCapture), 596*cf78ab8cSAndroid Build Coastguard Worker } 597*cf78ab8cSAndroid Build Coastguard Worker 598*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Args)] 599*cf78ab8cSAndroid Build Coastguard Worker pub struct ListCapture { 600*cf78ab8cSAndroid Build Coastguard Worker /// Optional strings of pattern for captures to list. Possible filter fields include Capture ID, Device Name, and Chip Kind 601*cf78ab8cSAndroid Build Coastguard Worker pub patterns: Vec<String>, 602*cf78ab8cSAndroid Build Coastguard Worker /// Continuously print Capture information every second 603*cf78ab8cSAndroid Build Coastguard Worker #[arg(short, long)] 604*cf78ab8cSAndroid Build Coastguard Worker pub continuous: bool, 605*cf78ab8cSAndroid Build Coastguard Worker } 606*cf78ab8cSAndroid Build Coastguard Worker 607*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Args)] 608*cf78ab8cSAndroid Build Coastguard Worker pub struct PatchCapture { 609*cf78ab8cSAndroid Build Coastguard Worker /// Packet capture state 610*cf78ab8cSAndroid Build Coastguard Worker #[arg(value_enum, ignore_case = true)] 611*cf78ab8cSAndroid Build Coastguard Worker pub state: OnOffState, 612*cf78ab8cSAndroid Build Coastguard Worker /// Optional strings of pattern for captures to patch. Possible filter fields include Capture ID, Device Name, and Chip Kind 613*cf78ab8cSAndroid Build Coastguard Worker pub patterns: Vec<String>, 614*cf78ab8cSAndroid Build Coastguard Worker } 615*cf78ab8cSAndroid Build Coastguard Worker 616*cf78ab8cSAndroid Build Coastguard Worker #[derive(Debug, Args)] 617*cf78ab8cSAndroid Build Coastguard Worker pub struct GetCapture { 618*cf78ab8cSAndroid Build Coastguard Worker /// Optional strings of pattern for captures to get. Possible filter fields include Capture ID, Device Name, and Chip Kind 619*cf78ab8cSAndroid Build Coastguard Worker pub patterns: Vec<String>, 620*cf78ab8cSAndroid Build Coastguard Worker /// Directory to store downloaded capture file(s) 621*cf78ab8cSAndroid Build Coastguard Worker #[arg(short = 'o', long)] 622*cf78ab8cSAndroid Build Coastguard Worker pub location: Option<String>, 623*cf78ab8cSAndroid Build Coastguard Worker #[arg(skip)] 624*cf78ab8cSAndroid Build Coastguard Worker pub filenames: Vec<String>, 625*cf78ab8cSAndroid Build Coastguard Worker #[arg(skip)] 626*cf78ab8cSAndroid Build Coastguard Worker pub current_file: String, 627*cf78ab8cSAndroid Build Coastguard Worker } 628*cf78ab8cSAndroid Build Coastguard Worker 629*cf78ab8cSAndroid Build Coastguard Worker impl From<&BeaconBleSettings> for AdvertiseSettingsProto { from(value: &BeaconBleSettings) -> Self630*cf78ab8cSAndroid Build Coastguard Worker fn from(value: &BeaconBleSettings) -> Self { 631*cf78ab8cSAndroid Build Coastguard Worker AdvertiseSettingsProto { 632*cf78ab8cSAndroid Build Coastguard Worker interval: value.advertise_mode.as_ref().map(IntervalProto::from), 633*cf78ab8cSAndroid Build Coastguard Worker tx_power: value.tx_power_level.as_ref().map(TxPowerProto::from), 634*cf78ab8cSAndroid Build Coastguard Worker scannable: value.scannable, 635*cf78ab8cSAndroid Build Coastguard Worker timeout: value.timeout.unwrap_or_default(), 636*cf78ab8cSAndroid Build Coastguard Worker ..Default::default() 637*cf78ab8cSAndroid Build Coastguard Worker } 638*cf78ab8cSAndroid Build Coastguard Worker } 639*cf78ab8cSAndroid Build Coastguard Worker } 640*cf78ab8cSAndroid Build Coastguard Worker 641*cf78ab8cSAndroid Build Coastguard Worker impl From<&Interval> for IntervalProto { from(value: &Interval) -> Self642*cf78ab8cSAndroid Build Coastguard Worker fn from(value: &Interval) -> Self { 643*cf78ab8cSAndroid Build Coastguard Worker match value { 644*cf78ab8cSAndroid Build Coastguard Worker Interval::Mode(mode) => IntervalProto::AdvertiseMode( 645*cf78ab8cSAndroid Build Coastguard Worker match mode { 646*cf78ab8cSAndroid Build Coastguard Worker AdvertiseMode::LowPower => AdvertiseModeProto::LOW_POWER, 647*cf78ab8cSAndroid Build Coastguard Worker AdvertiseMode::Balanced => AdvertiseModeProto::BALANCED, 648*cf78ab8cSAndroid Build Coastguard Worker AdvertiseMode::LowLatency => AdvertiseModeProto::LOW_LATENCY, 649*cf78ab8cSAndroid Build Coastguard Worker } 650*cf78ab8cSAndroid Build Coastguard Worker .into(), 651*cf78ab8cSAndroid Build Coastguard Worker ), 652*cf78ab8cSAndroid Build Coastguard Worker Interval::Milliseconds(ms) => IntervalProto::Milliseconds(*ms), 653*cf78ab8cSAndroid Build Coastguard Worker } 654*cf78ab8cSAndroid Build Coastguard Worker } 655*cf78ab8cSAndroid Build Coastguard Worker } 656*cf78ab8cSAndroid Build Coastguard Worker 657*cf78ab8cSAndroid Build Coastguard Worker impl From<&TxPower> for TxPowerProto { from(value: &TxPower) -> Self658*cf78ab8cSAndroid Build Coastguard Worker fn from(value: &TxPower) -> Self { 659*cf78ab8cSAndroid Build Coastguard Worker match value { 660*cf78ab8cSAndroid Build Coastguard Worker TxPower::Level(level) => TxPowerProto::TxPowerLevel( 661*cf78ab8cSAndroid Build Coastguard Worker match level { 662*cf78ab8cSAndroid Build Coastguard Worker TxPowerLevel::UltraLow => AdvertiseTxPowerProto::ULTRA_LOW, 663*cf78ab8cSAndroid Build Coastguard Worker TxPowerLevel::Low => AdvertiseTxPowerProto::LOW, 664*cf78ab8cSAndroid Build Coastguard Worker TxPowerLevel::Medium => AdvertiseTxPowerProto::MEDIUM, 665*cf78ab8cSAndroid Build Coastguard Worker TxPowerLevel::High => AdvertiseTxPowerProto::HIGH, 666*cf78ab8cSAndroid Build Coastguard Worker } 667*cf78ab8cSAndroid Build Coastguard Worker .into(), 668*cf78ab8cSAndroid Build Coastguard Worker ), 669*cf78ab8cSAndroid Build Coastguard Worker TxPower::Dbm(dbm) => TxPowerProto::Dbm((*dbm).into()), 670*cf78ab8cSAndroid Build Coastguard Worker } 671*cf78ab8cSAndroid Build Coastguard Worker } 672*cf78ab8cSAndroid Build Coastguard Worker } 673*cf78ab8cSAndroid Build Coastguard Worker 674*cf78ab8cSAndroid Build Coastguard Worker impl From<&BeaconBleAdvertiseData> for AdvertiseDataProto { from(value: &BeaconBleAdvertiseData) -> Self675*cf78ab8cSAndroid Build Coastguard Worker fn from(value: &BeaconBleAdvertiseData) -> Self { 676*cf78ab8cSAndroid Build Coastguard Worker AdvertiseDataProto { 677*cf78ab8cSAndroid Build Coastguard Worker include_device_name: value.include_device_name, 678*cf78ab8cSAndroid Build Coastguard Worker include_tx_power_level: value.include_tx_power_level, 679*cf78ab8cSAndroid Build Coastguard Worker manufacturer_data: value 680*cf78ab8cSAndroid Build Coastguard Worker .manufacturer_data 681*cf78ab8cSAndroid Build Coastguard Worker .clone() 682*cf78ab8cSAndroid Build Coastguard Worker .map(ParsableBytes::unwrap) 683*cf78ab8cSAndroid Build Coastguard Worker .unwrap_or_default(), 684*cf78ab8cSAndroid Build Coastguard Worker ..Default::default() 685*cf78ab8cSAndroid Build Coastguard Worker } 686*cf78ab8cSAndroid Build Coastguard Worker } 687*cf78ab8cSAndroid Build Coastguard Worker } 688*cf78ab8cSAndroid Build Coastguard Worker 689*cf78ab8cSAndroid Build Coastguard Worker impl From<&BeaconBleScanResponseData> for AdvertiseDataProto { from(value: &BeaconBleScanResponseData) -> Self690*cf78ab8cSAndroid Build Coastguard Worker fn from(value: &BeaconBleScanResponseData) -> Self { 691*cf78ab8cSAndroid Build Coastguard Worker AdvertiseDataProto { 692*cf78ab8cSAndroid Build Coastguard Worker include_device_name: value.scan_response_include_device_name, 693*cf78ab8cSAndroid Build Coastguard Worker include_tx_power_level: value.scan_response_include_tx_power_level, 694*cf78ab8cSAndroid Build Coastguard Worker manufacturer_data: value 695*cf78ab8cSAndroid Build Coastguard Worker .scan_response_manufacturer_data 696*cf78ab8cSAndroid Build Coastguard Worker .clone() 697*cf78ab8cSAndroid Build Coastguard Worker .map(ParsableBytes::unwrap) 698*cf78ab8cSAndroid Build Coastguard Worker .unwrap_or_default(), 699*cf78ab8cSAndroid Build Coastguard Worker ..Default::default() 700*cf78ab8cSAndroid Build Coastguard Worker } 701*cf78ab8cSAndroid Build Coastguard Worker } 702*cf78ab8cSAndroid Build Coastguard Worker } 703*cf78ab8cSAndroid Build Coastguard Worker 704*cf78ab8cSAndroid Build Coastguard Worker #[cfg(test)] 705*cf78ab8cSAndroid Build Coastguard Worker mod tests { 706*cf78ab8cSAndroid Build Coastguard Worker use super::*; 707*cf78ab8cSAndroid Build Coastguard Worker 708*cf78ab8cSAndroid Build Coastguard Worker #[test] test_hex_parser_succeeds()709*cf78ab8cSAndroid Build Coastguard Worker fn test_hex_parser_succeeds() { 710*cf78ab8cSAndroid Build Coastguard Worker let hex = ParsableBytes::from_str("beef1234"); 711*cf78ab8cSAndroid Build Coastguard Worker assert!(hex.is_ok(), "{}", hex.unwrap_err()); 712*cf78ab8cSAndroid Build Coastguard Worker let hex = hex.unwrap().unwrap(); 713*cf78ab8cSAndroid Build Coastguard Worker 714*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(vec![0xbeu8, 0xef, 0x12, 0x34], hex); 715*cf78ab8cSAndroid Build Coastguard Worker } 716*cf78ab8cSAndroid Build Coastguard Worker 717*cf78ab8cSAndroid Build Coastguard Worker #[test] test_hex_parser_prefix_succeeds()718*cf78ab8cSAndroid Build Coastguard Worker fn test_hex_parser_prefix_succeeds() { 719*cf78ab8cSAndroid Build Coastguard Worker let hex = ParsableBytes::from_str("0xabcd"); 720*cf78ab8cSAndroid Build Coastguard Worker assert!(hex.is_ok(), "{}", hex.unwrap_err()); 721*cf78ab8cSAndroid Build Coastguard Worker let hex = hex.unwrap().unwrap(); 722*cf78ab8cSAndroid Build Coastguard Worker 723*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(vec![0xabu8, 0xcd], hex); 724*cf78ab8cSAndroid Build Coastguard Worker } 725*cf78ab8cSAndroid Build Coastguard Worker 726*cf78ab8cSAndroid Build Coastguard Worker #[test] test_hex_parser_empty_str_succeeds()727*cf78ab8cSAndroid Build Coastguard Worker fn test_hex_parser_empty_str_succeeds() { 728*cf78ab8cSAndroid Build Coastguard Worker let hex = ParsableBytes::from_str(""); 729*cf78ab8cSAndroid Build Coastguard Worker assert!(hex.is_ok(), "{}", hex.unwrap_err()); 730*cf78ab8cSAndroid Build Coastguard Worker let hex = hex.unwrap().unwrap(); 731*cf78ab8cSAndroid Build Coastguard Worker 732*cf78ab8cSAndroid Build Coastguard Worker assert_eq!(Vec::<u8>::new(), hex); 733*cf78ab8cSAndroid Build Coastguard Worker } 734*cf78ab8cSAndroid Build Coastguard Worker 735*cf78ab8cSAndroid Build Coastguard Worker #[test] test_hex_parser_bad_digit_fails()736*cf78ab8cSAndroid Build Coastguard Worker fn test_hex_parser_bad_digit_fails() { 737*cf78ab8cSAndroid Build Coastguard Worker assert!(ParsableBytes::from_str("0xabcdefg").is_err()); 738*cf78ab8cSAndroid Build Coastguard Worker } 739*cf78ab8cSAndroid Build Coastguard Worker } 740