Skip to content

Commit 0dba0ce

Browse files
Nic ZoghbCQ bot account: commit-bot@chromium.org
authored andcommitted
[camera][calibrate] SL4F Facade
This CL provides the SL4F Facade for communication between the factory host and the on-device FIDL service. The Facade will be incorporated into SL4F proper in a future CL. The corresponding FIDL interface is fxr/332809. Note: This CL only guarantees the correctness of de/serialization of API responses. Many changes are expected to both this facade and the FIDL interface. End-to-end functionality is implemented in followup CLs. Tested: tests written in `types.rs` and `facade.rs`. Requires the `--with garnet/bin/sl4f:service-tests` build flag and can be run with `fx run-test sl4f-service-tests` Change-Id: I867dd2eb7fd685b57502b7fc2f4efcb0acf946bc
1 parent c24e5a8 commit 0dba0ce

File tree

6 files changed

+572
-0
lines changed

6 files changed

+572
-0
lines changed

garnet/bin/sl4f/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ rustc_library("lib") {
4242
"//sdk/fidl/fuchsia.bluetooth.control:fuchsia.bluetooth.control-rustc",
4343
"//sdk/fidl/fuchsia.bluetooth.gatt:fuchsia.bluetooth.gatt-rustc",
4444
"//sdk/fidl/fuchsia.bluetooth.le:fuchsia.bluetooth.le-rustc",
45+
"//sdk/fidl/fuchsia.camera2:fuchsia.camera2-rustc",
46+
"//sdk/fidl/fuchsia.factory.camera:fuchsia.factory.camera-rustc",
4547
"//sdk/fidl/fuchsia.factory:fuchsia.factory-rustc",
4648
"//sdk/fidl/fuchsia.images:fuchsia.images-rustc",
4749
"//sdk/fidl/fuchsia.intl:fuchsia.intl-rustc",
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2019 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+
5+
use failure::Error;
6+
use futures::future::{FutureExt, LocalBoxFuture};
7+
use serde_json::{from_value, Value};
8+
9+
use crate::camera_factory::facade::CameraFactoryFacade;
10+
use crate::camera_factory::types::{SetConfigRequest, WriteCalibrationDataRequest};
11+
use crate::server::Facade;
12+
13+
impl Facade for CameraFactoryFacade {
14+
fn handle_request(
15+
&self,
16+
method: String,
17+
args: Value,
18+
) -> LocalBoxFuture<'_, Result<Value, Error>> {
19+
camera_factory_method_to_fidl(method, args, self).boxed_local()
20+
}
21+
}
22+
23+
/// Takes JSON-RPC method command and forwards to corresponding CameraFactory FIDL methods.
24+
pub async fn camera_factory_method_to_fidl(
25+
method_name: String,
26+
args: Value,
27+
facade: &CameraFactoryFacade,
28+
) -> Result<Value, Error> {
29+
let result = match method_name.as_ref() {
30+
"DetectCamera" => facade.detect_camera().await,
31+
"Init" => facade.init().await,
32+
"Start" => facade.start().await,
33+
"Stop" => facade.stop().await,
34+
"SetConfig" => {
35+
let req: SetConfigRequest = from_value(args)?;
36+
facade.set_config(req.mode, req.exposure, req.analog_gain, req.digital_gain).await
37+
}
38+
"CaptureImage" => facade.capture_image().await,
39+
"WriteCalibrationData" => {
40+
let mut req: WriteCalibrationDataRequest = from_value(args)?;
41+
facade.write_calibration_data(&mut req.calibration_data, req.file_path).await
42+
}
43+
_ => bail!("invalid FIDL method: {}", method_name),
44+
}?;
45+
Ok(result)
46+
}
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
// Copyright 2019 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+
5+
use failure::Error;
6+
use fidl_fuchsia_factory_camera::{CameraFactoryError, CameraFactoryMarker, CameraFactoryProxy};
7+
use fidl_fuchsia_mem::Buffer;
8+
use fuchsia_component::client::connect_to_service;
9+
use fuchsia_syslog::fx_log_err;
10+
use parking_lot::RwLock;
11+
use serde_json::{to_value, Value};
12+
13+
use crate::camera_factory::types::{
14+
CaptureImageResult, DetectCameraResult, Sl4fCameraFactoryError,
15+
};
16+
use crate::common_utils::common::macros::{fx_err_and_bail, with_line};
17+
18+
/// Facade providing access to Camera Factory interfaces.
19+
#[derive(Debug)]
20+
pub struct CameraFactoryFacade {
21+
camera_factory_svc: RwLock<Option<CameraFactoryProxy>>,
22+
}
23+
24+
impl CameraFactoryFacade {
25+
/// Instantiate a Facade.
26+
pub fn new() -> Self {
27+
CameraFactoryFacade { camera_factory_svc: RwLock::new(None) }
28+
}
29+
30+
/// Connect to the Camera Factory FIDL service.
31+
pub async fn init(&self) -> Result<Value, Error> {
32+
match connect_to_service::<CameraFactoryMarker>() {
33+
Ok(r) => {
34+
*self.camera_factory_svc.write() = Some(r);
35+
Ok(to_value(())?)
36+
}
37+
Err(err) => fx_err_and_bail!(
38+
&with_line!("CameraFactoryFacade::init"),
39+
format_err!("SL4F Error: Failed to connect to service {}.", err)
40+
),
41+
}
42+
}
43+
44+
/// Helper method for the methods that need a connected service. Checks that the init method
45+
/// has been called.
46+
async fn init_check(&self, tag: &str) -> Result<CameraFactoryProxy, Error> {
47+
match self.camera_factory_svc.read().clone() {
48+
Some(svc) => Ok(svc),
49+
None => fx_err_and_bail!(&with_line!(tag), "No CameraFactoryProxy created."),
50+
}
51+
}
52+
53+
/// Checks whether the device under test has a camera and provides information about
54+
/// it. If the device has multiple cameras, the first one listed is chosen.
55+
///
56+
/// Takes no arguments.
57+
pub async fn detect_camera(&self) -> Result<Value, Error> {
58+
const TAG: &str = "CameraFactoryFacade::detect_camera";
59+
let svc = self.init_check(TAG).await?;
60+
match svc.detect_camera().await? {
61+
Ok(r) => Ok(to_value(DetectCameraResult { camera_id: r.0, camera_info: r.1 })?),
62+
Err(_) => Ok(to_value(Sl4fCameraFactoryError::NoCamera)?),
63+
}
64+
}
65+
66+
/// Initializes the camera sensor (and associated MIPI) and connects to a stream.
67+
///
68+
/// Takes no arguments. Outputs an empty response.
69+
pub async fn start(&self) -> Result<Value, Error> {
70+
const TAG: &str = "CameraFactoryFacade::start";
71+
let svc = self.init_check(TAG).await?;
72+
match svc.start() {
73+
Ok(_) => Ok(to_value(())?),
74+
Err(_) => Ok(to_value(Sl4fCameraFactoryError::Streaming)?),
75+
}
76+
}
77+
78+
/// Stops the camera sensor (and associated MIPI) stream.
79+
///
80+
/// Takes no arguments. Outputs an empty response.
81+
pub async fn stop(&self) -> Result<Value, Error> {
82+
const TAG: &str = "CameraFactoryFacade::stop";
83+
let svc = self.init_check(TAG).await?;
84+
match svc.stop() {
85+
Ok(_) => Ok(to_value(())?),
86+
Err(_) => Ok(to_value(Sl4fCameraFactoryError::Streaming)?),
87+
}
88+
}
89+
90+
/// Stops the camera sensor (and associated MIPI) stream.
91+
///
92+
/// # Arguments
93+
/// * `mode`: One of the camera's predefined sensor modes (fpms, resolution,
94+
/// etc).
95+
/// * `exposure`: The camera's sensor exposure parameter.
96+
/// * `analog_gain`: The camera's sensor analog gain parameter.
97+
/// * `digital_gain`: The camera's sensor digital gain parameter.
98+
///
99+
/// Outputs an empty response.
100+
pub async fn set_config(
101+
&self,
102+
mode: u32,
103+
exposure: u32,
104+
analog_gain: i32,
105+
digital_gain: i32,
106+
) -> Result<Value, Error> {
107+
const TAG: &str = "CameraFactoryFacade::set_config";
108+
let svc = self.init_check(TAG).await?;
109+
match svc.set_config(mode, exposure, analog_gain, digital_gain).await? {
110+
Ok(_) => Ok(to_value(())?),
111+
Err(err) => match err {
112+
CameraFactoryError::NoCamera => Ok(to_value(Sl4fCameraFactoryError::NoCamera)?),
113+
CameraFactoryError::Streaming => Ok(to_value(Sl4fCameraFactoryError::Streaming)?),
114+
},
115+
}
116+
}
117+
118+
/// Instructs the device to save a frame from the stream, and send it back to the host.
119+
///
120+
/// Takes no arguments.
121+
// TODO(42847): Implement scp functionality.
122+
pub async fn capture_image(&self) -> Result<Value, Error> {
123+
const TAG: &str = "CameraFactoryFacade::capture_image";
124+
let svc = self.init_check(TAG).await?;
125+
match svc.capture_image().await? {
126+
Ok(r) => Ok(to_value(CaptureImageResult { image_data: r.0, image_info: r.1 })?),
127+
Err(_) => Ok(to_value(Sl4fCameraFactoryError::Streaming)?),
128+
}
129+
}
130+
131+
/// Instructs the device to save tuning data to a persistent factory partition.
132+
///
133+
/// # Arguments
134+
/// * `calibration_data`: A blob of calibration data to be written to disk.
135+
/// * `file_path`: Outlines where on device the data is to be written.
136+
///
137+
/// Outputs an empty response.
138+
pub async fn write_calibration_data(
139+
&self,
140+
calibration_data: &mut Buffer,
141+
file_path: String,
142+
) -> Result<Value, Error> {
143+
const TAG: &str = "CameraFactoryFacade::write_calibration_data";
144+
let svc = self.init_check(TAG).await?;
145+
match svc.write_calibration_data(calibration_data, &file_path).await? {
146+
Ok(_) => Ok(to_value(())?),
147+
Err(_) => Ok(to_value(Sl4fCameraFactoryError::Streaming)?),
148+
}
149+
}
150+
}
151+
152+
#[cfg(test)]
153+
mod tests {
154+
// TODO(42847): end-to-end tests once FIDL service is linked up.
155+
use super::*;
156+
use fuchsia_async as fasync;
157+
158+
#[fasync::run_singlethreaded(test)]
159+
async fn detect_camera_with_no_camera_fails() -> Result<(), Error> {
160+
let camera_factory_facade = CameraFactoryFacade::new();
161+
camera_factory_facade.init().await.unwrap();
162+
camera_factory_facade.detect_camera().await.unwrap_err();
163+
Ok(())
164+
}
165+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright 2019 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+
5+
pub mod commands;
6+
pub mod facade;
7+
pub mod types;

0 commit comments

Comments
 (0)