redo properties API again - make default ID list smaller (and mostly things people actually use) and make the whole thing simpler overall (for us)

This commit is contained in:
l1npengtul
2024-12-11 14:16:47 +09:00
parent 0646b0abf5
commit 096880eb7e
2 changed files with 357 additions and 92 deletions
+5 -49
View File
@@ -1,8 +1,9 @@
use crate::error::{NokhwaError, NokhwaResult};
use crate::frame_format::FrameFormat;
use crate::properties::{CameraProperties, CameraPropertyId, CameraPropertyValue};
use crate::properties::{ControlId, ControlValue, Properties};
use crate::types::{CameraFormat, CameraIndex, FrameRate, Resolution};
use std::collections::HashMap;
use crate::frame_buffer::FrameBuffer;
use crate::stream::Stream;
pub trait Open {
@@ -14,33 +15,6 @@ pub trait AsyncOpen: Sized {
async fn open_async(index: CameraIndex) -> NokhwaResult<Self>;
}
macro_rules! def_camera_props {
( $($property:ident, )* ) => {
paste::paste! {
$(
fn [<$property:snake>] (&self) -> Option<&crate::properties::CameraPropertyDescriptor> {
self.properties().[<$property:snake>]()
}
fn [<set_ $property:snake>] (&mut self, value: crate::properties::CameraPropertyValue) -> Result<(), crate::error::NokhwaError> {
self.set_property(&crate::properties::CameraPropertyId::$property, value)
}
)*
}
};
}
// macro_rules! def_camera_props_async {
// ( $($property:ident, )* ) => {
// paste::paste! {
// $(
// async fn [<set_ $property:snake _async>] (&mut self, value: CameraPropertyValue) -> Result<(), NokhwaError> {
// self.[<set_ $property:snake >](value)
// }
// )*
// }
// };
// }
pub trait Setting {
fn enumerate_formats(&self) -> Result<Vec<CameraFormat>, NokhwaError>;
@@ -52,31 +26,13 @@ pub trait Setting {
fn set_format(&self, camera_format: CameraFormat) -> Result<(), NokhwaError>;
fn properties(&self) -> &CameraProperties;
fn properties(&self) -> &Properties;
fn set_property(
&mut self,
property: &CameraPropertyId,
value: CameraPropertyValue,
property: &ControlId,
value: ControlValue,
) -> Result<(), NokhwaError>;
def_camera_props!(
Brightness,
Contrast,
Hue,
Saturation,
Sharpness,
Gamma,
WhiteBalance,
BacklightCompensation,
Pan,
Tilt,
Zoom,
Exposure,
Iris,
Focus,
Facing,
);
}
// #[cfg(feature = "async")]
+352 -43
View File
@@ -1,43 +1,144 @@
use std::collections::HashMap;
use crate::ranges::Range;
use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter};
use std::ops::{ControlFlow};
use crate::error::{NokhwaError, NokhwaResult};
use crate::ranges::{Range, ValidatableRange};
pub type PlatformSpecificControlId = u64;
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub enum ControlId {
Focus,
Exposure,
WhiteBalance,
Zoom,
Lighting,
Other(u64)
FocusMode,
FocusAutoType,
FocusAutoRange,
FocusAbsolute,
FocusRelative,
FocusStatus,
ExposureMode,
ExposureBias,
ExposureTime,
ExposureAutoPriority,
ExposureIsoMode,
ExposureIsoSensitivity,
ExposureApertureAbsolute,
ExposureApertureRelative,
WhiteBalanceMode,
WhiteBalanceTemperature,
ZoomMode,
LightingMode,
PlatformSpecific(PlatformSpecificControlId)
}
#[derive(Clone, Debug, PartialEq)]
pub enum ControlGroup {
ModeMultipleValue(ModeAndValuesControl),
Simple(SimpleControl),
impl Display for ControlId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Control ID: {self:?}")
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct ModeAndValuesControl {
id: ControlId,
mode_id: u64,
mode_body: ControlBody,
values: HashMap<String, SimpleControl>
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Properties {
controls: HashMap<ControlId, ControlBody>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct SimpleControl {
id: u64,
body: ControlBody,
impl Properties {
pub fn new(device_controls: HashMap<ControlId, ControlBody>) -> Self {
Self {
controls: device_controls,
}
}
pub fn empty() -> Self {
Self::default()
}
pub fn control_value(&self, control_id: &ControlId) -> Option<&ControlBody> {
self.controls.get(control_id)
}
pub fn set_control_value(&mut self, control_id: &ControlId, value: ControlValue) -> NokhwaResult<()> {
// see if it exists
if let Some(control) = self.controls.get_mut(control_id) {
// FIXME: Remove this clone one day!
control.set_value(value.clone())?;
}
Err(NokhwaError::SetPropertyError {
property: control_id.to_string(),
value: value.to_string(),
error: "Not Found/Not Supported".to_string(),
})
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct ControlBody {
pub typ: ControlType,
pub class: ControlClass,
pub flags: Vec<ControlFlags>,
pub descriptor: ControlValueDescriptor,
pub value: Option<ControlValue>
control_type: ControlType,
flags: HashSet<ControlFlags>,
descriptor: ControlValueDescriptor,
value: Option<ControlValue>,
default_value: Option<ControlValue>,
}
impl ControlBody {
pub fn new(control_type: ControlType, control_flags: HashSet<ControlFlags>, control_value_descriptor: ControlValueDescriptor, value: Option<ControlValue>, default_value: Option<ControlValue>) -> Self {
Self {
control_type,
flags: control_flags,
descriptor: control_value_descriptor,
value,
default_value,
}
}
pub fn control_type(&self) -> &ControlType {
&self.control_type
}
pub fn flags(&self) -> &HashSet<ControlFlags> {
&self.flags
}
pub fn descriptor(&self) -> &ControlValueDescriptor {
&self.descriptor
}
pub fn value(&self) -> &Option<ControlValue> {
&self.value
}
pub fn default_value(&self) -> &Option<ControlValue> {
&self.default_value
}
pub fn add_flag(&mut self, flag: ControlFlags) {
self.flags.insert(flag);
}
pub fn remove_flag(&mut self, flag: ControlFlags) -> bool {
self.flags.remove(&flag)
}
pub fn set_value(&mut self, value: ControlValue) -> NokhwaResult<Option<ControlValue>> {
if let ControlFlow::Break(()) = self.descriptor.validate(&value) {
return Err(NokhwaError::SetPropertyError {
property: "Control Body".to_string(),
value: value.to_string(),
error: "Failed to validate control value".to_string(),
})
}
let old = core::mem::replace(&mut self.value, Some(value));
Ok(old)
}
pub fn clear_value(&mut self) -> Option<ControlValue> {
core::mem::replace(&mut self.value, None)
}
}
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
@@ -51,13 +152,6 @@ pub enum ControlType {
String,
}
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub enum ControlClass {
User,
Camera,
Other(u64),
}
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub enum ControlFlags {
Disabled,
@@ -75,31 +169,246 @@ pub enum ControlFlags {
pub enum ControlValueDescriptor {
Null,
Integer(Range<i64>),
Bitmap(i64),
Float(Range<i64>),
String(String),
Boolean(bool),
Array(Vec<ControlValuePrimitive>),
Map(HashMap<String, ControlValuePrimitive>)
BitMask,
Float(Range<f64>),
String,
Boolean,
// Array of any values of singular type
Array(ControlValuePrimitiveDescriptor),
// Multiple Choice from array
MultiChoice(Vec<ControlValuePrimitiveDescriptor>),
// Singular Choice from array
Enum(Vec<ControlValuePrimitiveDescriptor>),
// Hashmap
Map(HashMap<String, ControlValuePrimitiveDescriptor>),
// A menu, where you pick a key-value
Menu(HashMap<String, ControlValuePrimitiveDescriptor>)
}
impl ControlValueDescriptor {
pub fn validate(&self, value: &ControlValue) -> ControlFlow<()> {
match self {
ControlValueDescriptor::Null => {
if let &ControlValue::Null = value {
return ControlFlow::Continue(())
}
}
ControlValueDescriptor::Integer(int_range) => {
if let ControlValue::Integer(i) = value {
int_range.validate(i)?;
}
}
ControlValueDescriptor::BitMask => {
if let &ControlValue::BitMask(_) = value {
return ControlFlow::Continue(())
}
}
ControlValueDescriptor::Float(float_range) => {
if let ControlValue::Float(i) = value {
float_range.validate(i)?;
}
}
ControlValueDescriptor::String => {
if let &ControlValue::String(_) = value {
return ControlFlow::Continue(())
}
}
ControlValueDescriptor::Boolean => {
if let &ControlValue::Boolean(_) = value {
return ControlFlow::Continue(())
}
}
ControlValueDescriptor::Array(arr) => {
if arr.is_valid_value(value) {
return ControlFlow::Continue(())
}
}
ControlValueDescriptor::MultiChoice(choices) => {
if let &ControlValue::Array(values) = value {
for v in values {
let mut contains = false;
for choice in choices {
if choice.is_valid_value(v.as_ref()) {
contains = true;
break;
}
}
if !contains {
return ControlFlow::Break(())
}
}
}
}
ControlValueDescriptor::Enum(choices) => {
for choice in choices {
if choice.is_valid_value(&value) {
return ControlFlow::Continue(())
}
}
}
ControlValueDescriptor::Map(map) => {
if let ControlValue::Map(setting_map) = &value {
for (setting_key, setting_value) in setting_map {
if let Some(descriptor) = map.get(setting_key) {
if !descriptor.is_valid_value(setting_value.as_ref()) {
return ControlFlow::Break(())
}
}
}
}
}
ControlValueDescriptor::Menu(menu) => {
if let ControlValue::KeyValue(k, v) = &value {
if let Some(descriptor) = menu.get(k) {
if descriptor.is_valid_value(v.as_ref()) {
return ControlFlow::Continue(())
}
}
}
}
}
ControlFlow::Break(())
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum ControlValuePrimitiveDescriptor {
Null,
Integer(Range<i64>),
BitMask,
Float(Range<f64>),
String,
Boolean,
}
impl ControlValuePrimitiveDescriptor {
pub fn is_valid_value(&self, other: &ControlValue) -> bool {
match self {
ControlValuePrimitiveDescriptor::Null => {
if let &ControlValue::Null = other {
return true
}
}
ControlValuePrimitiveDescriptor::Integer(int_range) => {
if let ControlValue::Integer(i) = other {
return int_range.validate(i).is_ok()
}
}
ControlValuePrimitiveDescriptor::BitMask => {
if let &ControlValue::BitMask(_) = other {
return true
}
}
ControlValuePrimitiveDescriptor::Float(float_range) => {
if let ControlValue::Float(i) = other {
return float_range.validate(i).is_ok()
}
}
ControlValuePrimitiveDescriptor::String => {
if let &ControlValue::String(_) = other {
return true
}
}
ControlValuePrimitiveDescriptor::Boolean => {
if let &ControlValue::Boolean(_) = other {
return true
}
}
}
false
}
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub enum ControlValuePrimitive {
Null,
Integer(i64),
Bitmap(i64),
BitMask(i64),
Float(f64),
String(String),
Boolean(bool),
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
impl AsRef<ControlValue> for ControlValuePrimitive {
fn as_ref(&self) -> &ControlValue {
match self {
ControlValuePrimitive::Null => &ControlValue::Null,
ControlValuePrimitive::Integer(i) => &ControlValue::Integer(*i),
ControlValuePrimitive::BitMask(b) => &ControlValue::BitMask(*b),
ControlValuePrimitive::Float(f) => &ControlValue::Float(*f),
ControlValuePrimitive::String(s) => &ControlValue::String(s.clone()),
ControlValuePrimitive::Boolean(b) => &ControlValue::Boolean(*b),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum ControlValue {
Null,
Integer(i64),
Bitmap(i64),
BitMask(i64),
Float(f64),
String(String),
Boolean(bool),
Array(Vec<ControlValuePrimitive>),
KeyValue(String, ControlValuePrimitive),
Map(HashMap<String, ControlValuePrimitive>),
}
impl ControlValue {
pub fn same_type(&self, other: &ControlValue) -> bool {
match self {
ControlValue::Null => {
if let ControlValue::Null = other {
return true;
}
}
ControlValue::Integer(_) => {if let ControlValue::Integer(_) = other {
return true;
}}
ControlValue::BitMask(_) => {if let ControlValue::BitMask(_) = other {
return true;
}}
ControlValue::Float(_) => {if let ControlValue::Float(_) = other {
return true;
}}
ControlValue::String(_) => {if let ControlValue::String(_) = other {
return true;
}}
ControlValue::Boolean(_) => {if let ControlValue::Boolean(_) = other {
return true;
}}
ControlValue::Array(_) => {if let ControlValue::Array(_) = other {
return true;
}}
ControlValue::KeyValue(_, _) => {if let ControlValue::KeyValue(_, _) = other {
return true;
}}
ControlValue::Map(_) => {if let ControlValue::Map(_) = other {
return true;
}}
}
false
}
}
impl Display for ControlValue {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Control Value: {self:?}")
}
}
impl From<ControlValuePrimitive> for ControlValue {
fn from(value: ControlValuePrimitive) -> Self {
match value {
ControlValuePrimitive::Null => ControlValue::Null,
ControlValuePrimitive::Integer(i) => ControlValue::Integer(i),
ControlValuePrimitive::BitMask(b) => ControlValue::BitMask(b),
ControlValuePrimitive::Float(f) => ControlValue::Float(f),
ControlValuePrimitive::String(s) => ControlValue::String(s),
ControlValuePrimitive::Boolean(b) => ControlValue::Boolean(b),
}
}
}