| // Copyright 2022 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 anyhow::{Context, Error}; |
| use async_trait::async_trait; |
| use fidl_fuchsia_hardware_light::{Info, LightError, LightMarker, LightProxy}; |
| use fuchsia_component::client::connect_to_named_protocol_at_dir_root; |
| use fuchsia_fs::{directory::open_in_namespace, OpenFlags}; |
| use futures::TryStreamExt; |
| |
| async fn open_light() -> Result<LightProxy, Error> { |
| eprintln!("Opening light"); |
| // Wait for the first node. |
| const LIGHT_PATH: &str = "/dev/class/light"; |
| let dir = open_in_namespace(LIGHT_PATH, OpenFlags::empty()) |
| .with_context(|| format!("Opening {}", LIGHT_PATH))?; |
| let path = device_watcher::watch_for_files(&dir) |
| .await |
| .with_context(|| format!("Watching for files in {}", LIGHT_PATH))? |
| .try_next() |
| .await |
| .with_context(|| format!("Getting a file from {}", LIGHT_PATH))?; |
| let path = path.ok_or(anyhow::anyhow!("Could not find {}", LIGHT_PATH))?; |
| let path = |
| path.to_str().ok_or(anyhow::anyhow!("Could not find a valid str for {}", LIGHT_PATH))?; |
| connect_to_named_protocol_at_dir_root::<LightMarker>(&dir, path) |
| .context("Failed to connect built-in service") |
| } |
| |
| pub struct Led { |
| proxy: LightProxy, |
| } |
| |
| impl Led { |
| pub async fn new() -> Result<Led, Error> { |
| tracing::info!("Opening LEDs"); |
| let proxy = open_light().await?; |
| |
| Ok(Led { proxy }) |
| } |
| } |
| |
| #[async_trait] |
| pub trait LedControl: Send { |
| async fn set_brightness( |
| &mut self, |
| index: u32, |
| value: f64, |
| ) -> Result<Result<(), LightError>, fidl::Error>; |
| async fn get_num_lights(&mut self) -> Result<u32, fidl::Error>; |
| async fn get_info(&self, index: u32) -> Result<Result<Info, LightError>, fidl::Error>; |
| } |
| |
| #[async_trait] |
| impl LedControl for Led { |
| async fn set_brightness( |
| &mut self, |
| index: u32, |
| value: f64, |
| ) -> Result<Result<(), LightError>, fidl::Error> { |
| let value = num_traits::clamp(value, 0.0, 1.0); |
| self.proxy.set_brightness_value(index, value).await |
| } |
| async fn get_num_lights(&mut self) -> Result<u32, fidl::Error> { |
| self.proxy.get_num_lights().await |
| } |
| async fn get_info(&self, index: u32) -> Result<Result<Info, LightError>, fidl::Error> { |
| self.proxy.get_info(index).await |
| } |
| } |
| |
| #[cfg(test)] |
| mod test { |
| |
| use super::*; |
| use fidl_fuchsia_hardware_light::{Capability, LightRequest}; |
| use futures::{future, StreamExt}; |
| |
| #[fuchsia_async::run_singlethreaded(test)] |
| async fn get_num_lights() { |
| let (proxy, mut stream) = |
| fidl::endpoints::create_proxy_and_stream::<LightMarker>().unwrap(); |
| let mut led = Led { proxy }; |
| |
| let fut = async move { |
| assert_eq!(led.get_num_lights().await.unwrap(), 4); |
| }; |
| |
| let stream_fut = async move { |
| match stream.next().await.unwrap() { |
| Ok(LightRequest::GetNumLights { responder }) => { |
| responder.send(4_u32).unwrap(); |
| } |
| request => panic!("Unexpected request: {:?}", request), |
| } |
| }; |
| future::join(fut, stream_fut).await; |
| } |
| |
| #[fuchsia_async::run_singlethreaded(test)] |
| async fn get_info_test() { |
| let (proxy, mut stream) = |
| fidl::endpoints::create_proxy_and_stream::<LightMarker>().unwrap(); |
| let led = Led { proxy }; |
| |
| let fut = async move { |
| let Info { name, capability } = led.get_info(7).await.unwrap().unwrap(); |
| assert_eq!("Fake Light", name); |
| assert_eq!(Capability::Brightness, capability); |
| }; |
| |
| let stream_fut = async move { |
| match stream.next().await.unwrap() { |
| Ok(LightRequest::GetInfo { index, responder }) => { |
| assert_eq!(index, 7); |
| let light_info = |
| Info { name: "Fake Light".into(), capability: Capability::Brightness }; |
| responder.send(Ok(&light_info)).unwrap(); |
| } |
| request => panic!("Unexpected request: {:?}", request), |
| } |
| }; |
| future::join(fut, stream_fut).await; |
| } |
| |
| #[fuchsia_async::run_singlethreaded(test)] |
| async fn set_brightness() { |
| let (proxy, mut stream) = |
| fidl::endpoints::create_proxy_and_stream::<LightMarker>().unwrap(); |
| let mut led = Led { proxy }; |
| |
| let fut = async move { |
| assert_eq!(led.set_brightness(3, 0.5).await.unwrap(), Ok(())); |
| }; |
| |
| let stream_fut = async move { |
| match stream.next().await.unwrap() { |
| Ok(LightRequest::SetBrightnessValue { index, value, responder }) => { |
| assert_eq!(index, 3); |
| assert_eq!(value, 0.5); |
| responder.send(Ok(())).unwrap(); |
| } |
| request => panic!("Unexpected request: {:?}", request), |
| } |
| }; |
| future::join(fut, stream_fut).await; |
| } |
| } |