blob: f218fe38223cb753d22820ed6da21f67c04866b1 [file] [log] [blame]
// Copyright 2019 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 fidl_fuchsia_camera2::{DeviceInfo, DeviceType};
use fidl_fuchsia_images::{AlphaFormat, ColorSpace, ImageInfo, PixelFormat, Tiling, Transform};
use fidl_fuchsia_mem::Buffer;
use fuchsia_zircon::Vmo;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::collections::BTreeMap;
use thiserror::Error;
// FIDL request/response definitions.
#[derive(Serialize, Deserialize, Debug)]
pub struct DetectResult {
pub camera_id: i32,
#[serde(with = "DeviceInfoDef")]
pub camera_info: DeviceInfo,
}
#[cfg(test)]
impl PartialEq for DetectResult {
fn eq(&self, other: &Self) -> bool {
self.camera_id == other.camera_id && self.camera_info == other.camera_info
}
}
#[derive(Deserialize, Debug)]
pub struct SetCfgRequest {
pub mode: u32,
pub integration_time: i32,
pub analog_gain: i32,
pub digital_gain: i32,
}
#[derive(Serialize, Debug)]
pub struct CaptureResult {
#[serde(with = "buffer_wrapper")]
pub image_data: Buffer,
#[serde(with = "ImageInfoDef")]
pub image_info: ImageInfo,
}
// TODO(fxbug.dev/52737): Revise this once data transfer method is decided on.
#[derive(Serialize, Deserialize, Debug)]
pub struct WriteCalibrationDataRequest {
#[serde(with = "buffer_wrapper")]
pub calibration_data: Buffer,
pub file_path: String,
// This field is needed to match the FIDL-generated struct exactly. It
// should be removed once we are no longer using Serde remote.
#[serde(skip)]
__non_exhaustive: (),
}
#[derive(Serialize, Deserialize, Debug, Error)]
pub enum Sl4fCameraFactoryError {
#[error("SL4F Error: No camera.")]
NoCamera = 1,
#[error("SL4F Error: Streaming not started.")]
Streaming = 2,
#[error("SL4F Error: Unable to de/serialize.")]
Serialization = 3,
}
// |fidl_fuchsia_camera2| Helper definitions for Serde de/serialization.
#[derive(Serialize, Deserialize)]
#[serde(remote = "DeviceType")]
enum DeviceTypeDef {
Builtin = 1,
Virtual = 2,
}
// TODO(fxbug.dev/59274): Do not use Serde remote for FIDL tables.
#[derive(Serialize, Deserialize)]
#[serde(remote = "DeviceInfo")]
struct DeviceInfoDef {
vendor_id: Option<u16>,
vendor_name: Option<String>,
product_id: Option<u16>,
product_name: Option<String>,
#[serde(default, with = "device_type_wrapper")]
type_: Option<DeviceType>,
// These fields are needed to match the FIDL-generated struct exactly. They
// should be removed once we are no longer using Serde remote.
#[serde(skip)]
unknown_data: Option<BTreeMap<u64, Vec<u8>>>,
#[serde(skip)]
__non_exhaustive: (),
}
impl PartialEq for DeviceInfoDef {
fn eq(&self, other: &Self) -> bool {
self.vendor_id == other.vendor_id
&& self.vendor_name == other.vendor_name
&& self.product_id == other.product_id
&& self.product_name == other.product_name
}
}
mod device_type_wrapper {
use super::{Deserialize, Deserializer, DeviceType, DeviceTypeDef, Serialize, Serializer};
pub fn serialize<S: Serializer>(
value: &Option<DeviceType>,
serializer: S,
) -> Result<S::Ok, S::Error> {
#[derive(Serialize)]
struct Helper<'a>(#[serde(with = "DeviceTypeDef")] &'a DeviceType);
value.as_ref().map(Helper).serialize(serializer)
}
pub fn deserialize<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<DeviceType>, D::Error> {
#[derive(Deserialize)]
struct Helper(#[serde(with = "DeviceTypeDef")] DeviceType);
let helper = Option::deserialize(deserializer)?;
Ok(helper.map(|Helper(external)| external))
}
}
// |fidl_fuchsia_images| Helper definitions for Serde de/serialization.
#[derive(Serialize, Deserialize)]
#[serde(remote = "Transform")]
enum TransformDef {
Normal = 0,
FlipHorizontal = 1,
FlipVertical = 2,
FlipVerticalAndHorizontal = 3,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "PixelFormat")]
enum PixelFormatDef {
Bgra8 = 0,
Yuy2 = 1,
Nv12 = 2,
Yv12 = 3,
R8G8B8A8 = 4,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "ColorSpace")]
enum ColorSpaceDef {
Srgb = 0,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "Tiling")]
enum TilingDef {
Linear = 0,
GpuOptimal = 1,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "AlphaFormat")]
enum AlphaFormatDef {
Opaque = 0,
Premultiplied = 1,
NonPremultiplied = 2,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "ImageInfo")]
struct ImageInfoDef {
#[serde(with = "TransformDef")]
transform: Transform,
width: u32,
height: u32,
stride: u32,
#[serde(with = "PixelFormatDef")]
pixel_format: PixelFormat,
#[serde(with = "ColorSpaceDef")]
color_space: ColorSpace,
#[serde(with = "TilingDef")]
tiling: Tiling,
#[serde(with = "AlphaFormatDef")]
alpha_format: AlphaFormat,
}
// |fidl_fuchsia_mem| Helper definitions for Serde de/serialization.
mod buffer_wrapper {
use super::{Buffer, Deserialize, Deserializer, Serializer, Vmo};
use base64;
pub fn serialize<S: Serializer>(value: &Buffer, serializer: S) -> Result<S::Ok, S::Error> {
let mut data = vec![0; value.size as usize];
value.vmo.read(&mut data, 0).map_err(serde::ser::Error::custom)?;
serializer.serialize_str(&base64::encode(&data))
}
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Buffer, D::Error> {
let s = String::deserialize(deserializer)?;
let len = s.len();
let buf =
Buffer { size: len as u64, vmo: Vmo::create(len as u64).expect("VMO creation failed") };
match base64::decode(&s) {
Ok(v) => {
buf.vmo.write(&v, 0).map_err(serde::de::Error::custom)?;
}
Err(_) => {}
}
Ok(buf)
}
}
#[cfg(test)]
mod tests {
use super::*;
use base64;
use serde_json::{from_value, json, to_value};
struct Setup {
test_int: i32,
test_str: String,
empty_buf: Buffer,
full_buf: Buffer,
device_info: DeviceInfo,
image_info: ImageInfo,
}
impl Setup {
fn new() -> Self {
const BUFFER_SIZE: u64 = 5;
const TEST_INT32: i32 = 256;
const TEST_UINT32: u32 = 256;
const TEST_UINT16: u16 = 256;
const TEST_STR: &str = "test_string";
let one_vec = vec![1; BUFFER_SIZE as usize];
let full_vmo = Vmo::create(BUFFER_SIZE).unwrap();
full_vmo.write(&one_vec, 0).unwrap();
Self {
test_int: TEST_INT32,
test_str: TEST_STR.to_string(),
empty_buf: Buffer { size: 0, vmo: Vmo::create(0).unwrap() },
full_buf: Buffer { size: BUFFER_SIZE, vmo: full_vmo },
device_info: DeviceInfo {
vendor_id: Some(TEST_UINT16),
vendor_name: Some(TEST_STR.to_string()),
product_id: Some(TEST_UINT16),
product_name: Some(TEST_STR.to_string()),
type_: Some(DeviceType::Virtual),
..DeviceInfo::EMPTY
},
image_info: ImageInfo {
transform: Transform::Normal,
width: TEST_UINT32,
height: TEST_UINT32,
stride: TEST_UINT32,
pixel_format: PixelFormat::Bgra8,
color_space: ColorSpace::Srgb,
tiling: Tiling::Linear,
alpha_format: AlphaFormat::Opaque,
},
}
}
}
#[test]
fn serialize_detect_result() {
let setup = Setup::new();
let serialized_val =
to_value(DetectResult { camera_id: setup.test_int, camera_info: setup.device_info })
.unwrap();
let expected_val = json!({
"camera_id": 256,
"camera_info": {
"vendor_id": 256,
"vendor_name": "test_string",
"product_id": 256,
"product_name": "test_string",
"type_": "Virtual",
}
});
assert_eq!(serialized_val, expected_val);
}
#[test]
fn serialize_capture_image_result() {
let setup = Setup::new();
let serialized_val =
to_value(CaptureResult { image_data: setup.full_buf, image_info: setup.image_info })
.unwrap();
let expected_val = json!({
"image_data": base64::encode(&vec![1; 5]),
"image_info": {
"transform": "Normal",
"width": 256,
"height": 256,
"stride": 256,
"pixel_format": "Bgra8",
"color_space": "Srgb",
"tiling": "Linear",
"alpha_format": "Opaque",
}
});
assert_eq!(serialized_val, expected_val);
}
#[test]
fn serialize_capture_image_result_empty_buf() {
let setup = Setup::new();
let serialized_val =
to_value(CaptureResult { image_data: setup.empty_buf, image_info: setup.image_info })
.unwrap();
let expected_val = json!({
"image_data": "",
"image_info": {
"transform": "Normal",
"width": 256,
"height": 256,
"stride": 256,
"pixel_format": "Bgra8",
"color_space": "Srgb",
"tiling": "Linear",
"alpha_format": "Opaque",
}
});
assert_eq!(serialized_val, expected_val);
}
#[test]
fn deserialize_write_calibration_data_request() {
let setup = Setup::new();
let serialized_req: WriteCalibrationDataRequest = from_value(json!({
"calibration_data": base64::encode(&vec![1; 5]),
"file_path": "test_string",
}))
.unwrap();
let expected_req = WriteCalibrationDataRequest {
calibration_data: setup.full_buf,
file_path: setup.test_str,
__non_exhaustive: (),
};
let serialized_len = serialized_req.calibration_data.vmo.get_size().unwrap();
let expected_len = expected_req.calibration_data.vmo.get_size().unwrap();
assert_eq!(serialized_len, expected_len);
let mut serialized_val = vec![0; 5];
serialized_req.calibration_data.vmo.read(&mut serialized_val, 0).unwrap();
let mut expected_val = vec![0; 5];
expected_req.calibration_data.vmo.read(&mut expected_val, 0).unwrap();
assert_eq!(serialized_val, expected_val);
}
}