blob: 8fd30332b7704314a452f26d0f196acd1cca0c62 [file] [log] [blame]
// 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;
}
}