blob: 8e8a709cb6671b0e6814d7cd32175cf7ce2d2604 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::context::LowpanCtlContext;
use anyhow::{Context, Error};
use argh::FromArgs;
use fidl::endpoints::create_endpoints;
use fidl_fuchsia_lowpan_device::{BeaconInfoStreamMarker, NetworkScanParameters};
/// Contains the arguments decoded for the `network-scan` command.
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "network-scan")]
pub struct NetworkScanCommand {
/// subset of channels to scan.
///
/// if unspecified, all channels will be scanned.
#[argh(option)]
pub channels: Option<String>,
/// transmit power (in dBm to the antenna) for transmitting
/// beacon requests.
///
/// note that hardware limitations may cause the actual
/// used transmit power to differ from what is specified.
/// In that case the used transmit power will always be
/// the highest available transmit power that is less than
/// the specified transmit power. If the desired transmit
/// power is lower than the lowest transmit power supported
/// by the hardware, then that will be used instead.
#[argh(option)]
pub tx_power_dbm: Option<i32>,
}
impl NetworkScanCommand {
fn get_channels_vec_from_str(&self) -> Result<Option<Vec<u16>>, Error> {
self.channels
.as_ref()
.map(|value| {
let chans = value.split(",");
let mut res_vec: Vec<u16> = Vec::new();
for chan in chans {
let res = u16::from_str_radix(chan, 10)?;
res_vec.push(res);
}
Ok(res_vec)
})
.transpose()
}
fn get_network_scan_params(&self) -> Result<NetworkScanParameters, Error> {
Ok(NetworkScanParameters {
channels: self.get_channels_vec_from_str()?,
tx_power_dbm: self.tx_power_dbm.clone(),
..NetworkScanParameters::EMPTY
})
}
fn get_hex_string(&self, vec: &Vec<u8>) -> String {
let mut string = String::from("");
for item in vec {
string.push_str(&format!("{:02x}", item)[..]);
}
string
}
pub async fn exec(&self, context: &mut LowpanCtlContext) -> Result<(), Error> {
let network_scan_marker = self.get_network_scan_params()?;
let (_, device_extra, _) =
context.get_default_device_proxies().await.context("Unable to get device instance")?;
let (client_end, server_end) = create_endpoints::<BeaconInfoStreamMarker>()?;
let result_stream = client_end.into_proxy()?;
device_extra
.start_network_scan(network_scan_marker, server_end)
.context("Unable to send start network scan command")?;
println!("result(s):");
println!(
"|-------------------+--------+----+------------------+------------------+-----------|"
);
println!(
"| NetworkName | PAN ID | Ch | XPanID | HWAddr | RSSI |"
);
loop {
let vec = result_stream.next().await?;
if vec.is_empty() {
println!("|-------------------+--------+----+------------------+------------------+-----------|");
break;
}
println!("|-------------------+--------+----+------------------+------------------+-----------|");
for item in vec {
let network_name_vec = match item.identity.raw_name {
Some(x) => x,
None => Vec::new(),
};
let network_name = match std::str::from_utf8(&network_name_vec) {
Ok(x) => format!("{:?}", x),
Err(_) => format!("{:?}", self.get_hex_string(&network_name_vec)),
};
let panid = format!(
"{:^6}",
match item.identity.panid {
Some(num) => format_args!("{:#04X}", num).to_string(),
None => format_args!("N/A").to_string(),
}
);
let ch = format!(
"{:^2}",
match item.identity.channel {
Some(num) => num.to_string(),
None => format_args!("N/A").to_string(),
}
);
let xpanid_vec = match item.identity.xpanid {
Some(x) => x,
None => Vec::new(),
};
let xpanid = format!("{:^16}", self.get_hex_string(&xpanid_vec));
let hwaddr = format!("{:^16}", self.get_hex_string(&item.address));
let rssi = format!("{:^9}", item.rssi);
println!(
"| {:^17} | {} | {} | {} | {} | {} |",
network_name, panid, ch, xpanid, hwaddr, rssi
);
}
}
Ok(())
}
}