Skip to main content

driver_tools/subcommands/list_devices/
mod.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5pub mod args;
6
7use crate::common::{node_property_key_to_string, node_property_value_to_string};
8use anyhow::{Result, anyhow};
9use args::ListDevicesCommand;
10use fidl_fuchsia_component_decl as fdecl;
11use flex_fuchsia_driver_development as fdd;
12use flex_fuchsia_driver_framework as fdf;
13use fuchsia_driver_dev::Device;
14#[cfg(feature = "fdomain")]
15use fuchsia_driver_dev_fdomain as fuchsia_driver_dev;
16use itertools::Itertools;
17
18trait DevicePrinter {
19    fn print(&self) -> Result<()>;
20    fn print_verbose(&self) -> Result<()>;
21}
22
23impl DevicePrinter for Device {
24    fn print(&self) -> Result<()> {
25        println!("{}", self.get_moniker()?);
26        Ok(())
27    }
28
29    fn print_verbose(&self) -> Result<()> {
30        let moniker = self.get_moniker().expect("Node does not have a moniker");
31        let (_, name) = moniker.rsplit_once('.').unwrap_or(("", &moniker));
32        let topological_path = self.0.topological_path.as_deref().unwrap_or("None");
33        println!("{0: <9}: {1}", "Name", name);
34        println!("{0: <9}: {1}", "Moniker", moniker);
35        println!("{0: <9}: {1}", "Topology", topological_path);
36
37        if self.0.quarantined == Some(true)
38            && self.0.bound_driver_url != Some("unbound".to_string())
39        {
40            println!(
41                "{0: <9}: {1} (quarantined)",
42                "Driver",
43                self.0.bound_driver_url.as_deref().unwrap_or("None")
44            );
45        } else {
46            println!(
47                "{0: <9}: {1}",
48                "Driver",
49                self.0.bound_driver_url.as_deref().unwrap_or("None")
50            );
51        }
52
53        if let Some(ref bus_topology) = self.0.bus_topology {
54            if !bus_topology.is_empty() {
55                println!("\n{0: <9} {1: <9} {2}", "Bus Type", "Stability", "Address",);
56            }
57            for segment in bus_topology {
58                let address = match &segment.address {
59                    Some(fdf::DeviceAddress::IntValue(val)) => format!("{val:02X}"),
60                    Some(fdf::DeviceAddress::ArrayIntValue(val)) => {
61                        val.iter().map(|v| format!("{v:02X}")).join(":")
62                    }
63                    Some(fdf::DeviceAddress::CharIntValue(val)) => val.to_string(),
64                    Some(fdf::DeviceAddress::ArrayCharIntValue(val)) => {
65                        val.iter().map(|v| v.to_string()).join(":")
66                    }
67                    Some(fdf::DeviceAddress::StringValue(val)) => val.to_string(),
68                    None => "None".to_string(),
69                    _ => "Unknown".to_string(),
70                };
71                println!(
72                    "{0: <9} {1: <9} {2}",
73                    segment
74                        .bus
75                        .map(|s| format!("{s:?}").to_uppercase())
76                        .unwrap_or_else(|| "Unknown".to_string()),
77                    segment
78                        .address_stability
79                        .map(|s| format!("{s:?}"))
80                        .unwrap_or_else(|| "Unknown".to_string()),
81                    address,
82                );
83            }
84            if !bus_topology.is_empty() {
85                println!("");
86            }
87        }
88
89        if let Some(ref node_property_list) = self.0.node_property_list {
90            println!("{} Properties", node_property_list.len());
91            for i in 0..node_property_list.len() {
92                let node_property = &node_property_list[i];
93                println!(
94                    "[{:>2}/ {:>2}] : Key {:30} Value {}",
95                    i + 1,
96                    node_property_list.len(),
97                    node_property_key_to_string(&node_property.key),
98                    node_property_value_to_string(&node_property.value),
99                );
100            }
101        } else {
102            println!("0 Properties");
103        }
104
105        if let Some(ref offer_list) = self.0.offer_list {
106            println!("{} Offers", offer_list.len());
107            for i in 0..offer_list.len() {
108                if let fdecl::Offer::Service(service) = &offer_list[i] {
109                    println!("Service: {}", service.target_name.as_deref().unwrap_or("<unknown>"));
110                    if let Some(fdecl::Ref::Child(source)) = service.source.as_ref() {
111                        println!("  Source: {}", source.name);
112                    }
113                    if let Some(filter) = &service.source_instance_filter {
114                        println!("  Instances: {}", filter.join(" "));
115                    }
116                }
117            }
118        } else {
119            println!("0 Offers");
120        }
121        println!("");
122        Ok(())
123    }
124}
125
126pub async fn list_devices(
127    cmd: ListDevicesCommand,
128    driver_development_proxy: fdd::ManagerProxy,
129) -> Result<()> {
130    let devices: Vec<Device> = match cmd.device {
131        Some(device) => {
132            fuchsia_driver_dev::get_device_info(&driver_development_proxy, &[device], cmd.exact)
133                .await?
134        }
135        None => {
136            fuchsia_driver_dev::get_device_info(&driver_development_proxy, &[], cmd.exact).await?
137        }
138    }
139    .into_iter()
140    .filter(|d| !cmd.unbound || d.bound_driver_url == Some("unbound".to_string()))
141    .map(|device_info| Device::from(device_info))
142    .collect();
143
144    if !devices.is_empty() {
145        if cmd.verbose {
146            for device in devices {
147                device.print_verbose()?;
148            }
149        } else {
150            for device in devices {
151                device.print()?;
152            }
153        }
154    } else {
155        if cmd.fail_on_missing {
156            return Err(anyhow!("No devices found."));
157        } else {
158            println!("No devices found.");
159        }
160    }
161
162    Ok(())
163}