blob: bfe7fc64a1660b1e67dc73ff9bf6c12a5281462e [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::adc::types::AdcRequest;
use crate::common_utils::common::macros::{fx_err_and_bail, with_line};
use anyhow::Error;
use fidl_fuchsia_hardware_adc::{DeviceMarker, DeviceProxy};
use fuchsia_syslog::macros::fx_log_err;
use fuchsia_zircon as zx;
use serde_json::Value;
use std::path::Path;
/// Perform Adc operations.
///
/// Note this object is shared among all threads created by server.
///
#[derive(Debug)]
pub struct AdcFacade {
/// Adc device proxy that may be optionally provided for testing. The proxy is not cached during
/// normal operation.
proxy: Option<DeviceProxy>,
}
impl AdcFacade {
pub fn new() -> AdcFacade {
AdcFacade { proxy: None }
}
/// Connect to the ADC device specified by `device_path`.
///
/// # Arguments
/// * `device_path` - String representing the ADC device path (e.g., /dev/class/adc/000)
fn get_proxy(&self, device_path: String) -> Result<DeviceProxy, Error> {
let tag = "AdcFacade::get_proxy";
if let Some(proxy) = &self.proxy {
Ok(proxy.clone())
} else {
let (proxy, server) = match fidl::endpoints::create_proxy::<DeviceMarker>() {
Ok(r) => r,
Err(e) => fx_err_and_bail!(
&with_line!(tag),
format_err!("Failed to create proxy {:?}", e)
),
};
if Path::new(&device_path).exists() {
fdio::service_connect(device_path.as_ref(), server.into_channel())?;
Ok(proxy)
} else {
fx_err_and_bail!(
&with_line!(tag),
format_err!("Failed to find device: {}", device_path)
);
}
}
}
/// Gets the resolution from a specified ADC device.
///
/// # Arguments
/// * `args`: JSON value containing the AdcRequest information, where AdcRequest contains the
/// device path to read from.
pub async fn get_resolution(&self, args: Value) -> Result<u8, Error> {
let req: AdcRequest = serde_json::from_value(args)?;
let resolution = self
.get_proxy(req.device_path)?
.get_resolution()
.await?
.map_err(|e| zx::Status::from_raw(e))?;
Ok(resolution)
}
/// Gets a sample from a specified ADC device.
///
/// # Arguments
/// * `args`: JSON value containing the AdcRequest information, where AdcRequest contains the
/// device path to read from.
pub async fn get_sample(&self, args: Value) -> Result<u32, Error> {
let req: AdcRequest = serde_json::from_value(args)?;
let sample = self
.get_proxy(req.device_path)?
.get_sample()
.await?
.map_err(|e| zx::Status::from_raw(e))?;
Ok(sample)
}
/// Gets a normalized sample from a specified ADC device.
///
/// # Arguments
/// * `args`: JSON value containing the AdcRequest information, where AdcRequest contains the
/// device path to read from.
pub async fn get_normalized_sample(&self, args: Value) -> Result<f32, Error> {
let req: AdcRequest = serde_json::from_value(args)?;
let sample = self
.get_proxy(req.device_path)?
.get_normalized_sample()
.await?
.map_err(|e| zx::Status::from_raw(e))?;
Ok(sample)
}
}
#[cfg(test)]
mod tests {
use super::*;
use fidl::endpoints::create_proxy_and_stream;
use fidl_fuchsia_hardware_adc::DeviceRequest;
use fuchsia_async as fasync;
use futures::prelude::*;
use serde_json::json;
/// Tests that the `get_resolution` method correctly queries the ADC device and returns the
/// expected resolution value.
#[fasync::run_singlethreaded(test)]
async fn test_get_resolution() {
let (proxy, mut stream) = create_proxy_and_stream::<DeviceMarker>().unwrap();
let facade = AdcFacade { proxy: Some(proxy) };
let facade_fut = async move {
assert_eq!(
facade
.get_resolution(json!({
"device_path": "/dev/class/adc/000"
}))
.await
.unwrap(),
12
);
};
let stream_fut = async move {
match stream.try_next().await {
Ok(Some(DeviceRequest::GetResolution { responder })) => {
responder.send(&mut Ok(12)).unwrap();
}
err => panic!("Err in request handler: {:?}", err),
}
};
future::join(facade_fut, stream_fut).await;
}
/// Tests that the `get_sample` method correctly queries the ADC device and returns the expected
/// sample value.
#[fasync::run_singlethreaded(test)]
async fn test_get_sample() {
let (proxy, mut stream) = create_proxy_and_stream::<DeviceMarker>().unwrap();
let facade = AdcFacade { proxy: Some(proxy) };
let facade_fut = async move {
assert_eq!(
facade
.get_sample(json!({
"device_path": "/dev/class/adc/000"
}))
.await
.unwrap(),
12
);
};
let stream_fut = async move {
match stream.try_next().await {
Ok(Some(DeviceRequest::GetSample { responder })) => {
responder.send(&mut Ok(12)).unwrap();
}
err => panic!("Err in request handler: {:?}", err),
}
};
future::join(facade_fut, stream_fut).await;
}
/// Tests that the `get_normalized_sample` method correctly queries the ADC device and returns
/// the expected normalized sample value.
#[fasync::run_singlethreaded(test)]
async fn test_get_normalized_sample() {
let (proxy, mut stream) = create_proxy_and_stream::<DeviceMarker>().unwrap();
let facade = AdcFacade { proxy: Some(proxy) };
let facade_fut = async move {
assert_eq!(
facade
.get_normalized_sample(json!({
"device_path": "/dev/class/adc/000"
}))
.await
.unwrap(),
12.34
);
};
let stream_fut = async move {
match stream.try_next().await {
Ok(Some(DeviceRequest::GetNormalizedSample { responder })) => {
responder.send(&mut Ok(12.34)).unwrap();
}
err => panic!("Err in request handler: {:?}", err),
}
};
future::join(facade_fut, stream_fut).await;
}
}