blob: f097958bb415af444761c0b675fe5757c905668d [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 crate::prelude::*;
use fidl_fuchsia_lowpan_experimental::{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<i8>,
}
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(),
..Default::default()
})
}
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_experimental_device_extra()
.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 = item
.identity
.as_ref()
.map(|x| x.raw_name.as_ref().map(Vec::as_slice))
.flatten()
.map(|x| {
std::str::from_utf8(x)
.map(|x| format!("{:?}", x))
.unwrap_or_else(|_| hex::encode(x))
})
.unwrap_or_else(|| String::new());
let panid = item
.identity
.as_ref()
.map(|x| x.panid)
.flatten()
.map(|x| format!("{:#04X}", x))
.unwrap_or_else(|| "N/A".to_string());
let ch = item
.identity
.as_ref()
.map(|x| x.channel)
.flatten()
.map(|x| x.to_string())
.unwrap_or_else(|| "N/A".to_string());
let xpanid = item
.identity
.and_then(|fidl_fuchsia_lowpan_device::Identity { xpanid, .. }| xpanid)
.map(hex::encode)
.unwrap_or_else(|| "N/A".to_string());
let hwaddr = item
.address
.as_ref()
.map(|fidl_fuchsia_lowpan::MacAddress { octets }| octets)
.map(hex::encode)
.unwrap_or_else(|| "N/A".to_string());
let rssi = item.rssi.map(|x| x.to_string()).unwrap_or_else(|| "N/A".to_string());
println!(
"| {:^17} | {:^6} | {:^2} | {:^16} | {:^16} | {:^9} |",
network_name, panid, ch, xpanid, hwaddr, rssi
);
}
}
Ok(())
}
}