v4l/
control.rs

1use bitflags::bitflags;
2use std::convert::{TryFrom, TryInto};
3use std::{ffi, fmt, mem, str};
4
5use crate::v4l_sys::*;
6
7/// Control data type
8#[allow(clippy::unreadable_literal)]
9#[rustfmt::skip]
10#[repr(u32)]
11#[derive(Debug, Copy, Clone, PartialEq, Eq)]
12pub enum Type {
13    Integer         = 1,
14    Boolean         = 2,
15    Menu            = 3,
16    Button          = 4,
17    Integer64       = 5,
18    CtrlClass       = 6,
19    String          = 7,
20    Bitmask         = 8,
21    IntegerMenu     = 9,
22
23    /* Compound types are >= 0x0100 */
24    U8              = 0x0100,
25    U16             = 0x0101,
26    U32             = 0x0102,
27    Area            = 0x0106,
28}
29
30impl TryFrom<u32> for Type {
31    type Error = ();
32
33    fn try_from(repr: u32) -> Result<Self, Self::Error> {
34        match repr {
35            1 => Ok(Type::Integer),
36            2 => Ok(Type::Boolean),
37            3 => Ok(Type::Menu),
38            4 => Ok(Type::Button),
39            5 => Ok(Type::Integer64),
40            6 => Ok(Type::CtrlClass),
41            7 => Ok(Type::String),
42            8 => Ok(Type::Bitmask),
43            9 => Ok(Type::IntegerMenu),
44
45            0x0100 => Ok(Type::U8),
46            0x0101 => Ok(Type::U16),
47            0x0102 => Ok(Type::U32),
48            0x0106 => Ok(Type::Area),
49            _ => Err(()),
50        }
51    }
52}
53
54impl From<Type> for u32 {
55    fn from(t: Type) -> Self {
56        t as Self
57    }
58}
59
60impl fmt::Display for Type {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        fmt::Debug::fmt(self, f)
63    }
64}
65
66bitflags! {
67    #[allow(clippy::unreadable_literal)]
68    pub struct Flags: u32 {
69        const DISABLED              = 0x0001;
70        const GRABBED               = 0x0002;
71        const READ_ONLY             = 0x0004;
72        const UPDATE                = 0x0008;
73        const INACTIVE              = 0x0010;
74        const SLIDER                = 0x0020;
75        const WRITE_ONLY            = 0x0040;
76        const VOLATILE              = 0x0080;
77        const HAS_PAYLOAD           = 0x0100;
78        const EXECUTE_ON_WRITE      = 0x0200;
79        const MODIFY_LAYOUT         = 0x0400;
80
81        const NEXT_CTRL             = 0x80000000;
82        const NEXT_COMPOUND         = 0x40000000;
83    }
84}
85
86impl From<u32> for Flags {
87    fn from(flags: u32) -> Self {
88        Self::from_bits_truncate(flags)
89    }
90}
91
92impl From<Flags> for u32 {
93    fn from(flags: Flags) -> Self {
94        flags.bits()
95    }
96}
97
98impl fmt::Display for Flags {
99    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100        fmt::Debug::fmt(self, f)
101    }
102}
103
104#[derive(Debug)]
105/// Device control menu item
106pub enum MenuItem {
107    Name(String),
108    Value(i64),
109}
110
111impl fmt::Display for MenuItem {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        match self {
114            MenuItem::Name(name) => {
115                write!(f, "{}", name)?;
116            }
117            MenuItem::Value(value) => {
118                write!(f, "{}", value)?;
119            }
120        }
121        Ok(())
122    }
123}
124
125impl TryFrom<(Type, v4l2_querymenu)> for MenuItem {
126    type Error = ();
127
128    fn try_from(item: (Type, v4l2_querymenu)) -> Result<Self, Self::Error> {
129        unsafe {
130            match item.0 {
131                Type::Menu => Ok(MenuItem::Name(
132                    str::from_utf8(&item.1.__bindgen_anon_1.name)
133                        .unwrap()
134                        .trim_matches(char::from(0))
135                        .to_string(),
136                )),
137                Type::IntegerMenu => Ok(MenuItem::Value(item.1.__bindgen_anon_1.value)),
138                _ => Err(()),
139            }
140        }
141    }
142}
143
144#[derive(Debug)]
145/// Device control description
146pub struct Description {
147    /// Control identifier, set by the the application
148    pub id: u32,
149    /// Type of control
150    pub typ: Type,
151    /// Name of the control, intended for the user
152    pub name: String,
153    /// Minimum value, inclusive
154    pub minimum: i64,
155    /// Maximum value, inclusive
156    pub maximum: i64,
157    /// Step size, always positive
158    pub step: u64,
159    /// Default value
160    pub default: i64,
161    /// Control flags
162    pub flags: Flags,
163
164    /// Items for menu controls (only valid if typ is a menu type)
165    pub items: Option<Vec<(u32, MenuItem)>>,
166}
167
168impl From<v4l2_query_ext_ctrl> for Description {
169    fn from(ctrl: v4l2_query_ext_ctrl) -> Self {
170        Self {
171            id: ctrl.id,
172            typ: Type::try_from(ctrl.type_).unwrap(),
173            name: unsafe { ffi::CStr::from_ptr(ctrl.name.as_ptr()) }
174                .to_str()
175                .unwrap()
176                .to_string(),
177            minimum: ctrl.minimum,
178            maximum: ctrl.maximum,
179            step: ctrl.step,
180            default: ctrl.default_value,
181            flags: Flags::from(ctrl.flags),
182            items: None,
183        }
184    }
185}
186
187impl fmt::Display for Description {
188    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189        writeln!(f, "ID         : {}", self.id)?;
190        writeln!(f, "Type       : {}", self.typ)?;
191        writeln!(f, "Name       : {}", self.name)?;
192        writeln!(f, "Minimum    : {}", self.minimum)?;
193        writeln!(f, "Maximum    : {}", self.maximum)?;
194        writeln!(f, "Step       : {}", self.step)?;
195        writeln!(f, "Default    : {}", self.default)?;
196        writeln!(f, "Flags      : {}", self.flags)?;
197        if let Some(items) = &self.items {
198            writeln!(f, "Menu ==>")?;
199            for item in items {
200                writeln!(f, " * {}", item.1)?;
201            }
202        }
203        Ok(())
204    }
205}
206
207#[derive(Debug)]
208pub struct Control {
209    pub id: u32,
210    pub value: Value,
211}
212
213#[derive(Debug, PartialEq, Eq)]
214/// Device control value
215pub enum Value {
216    /* buttons */
217    None,
218    /* single values */
219    Integer(i64),
220    Boolean(bool),
221    String(String),
222    /* compound (matrix) values */
223    CompoundU8(Vec<u8>),
224    CompoundU16(Vec<u16>),
225    CompoundU32(Vec<u32>),
226    CompoundPtr(Vec<u8>),
227}
228
229impl TryInto<v4l2_control> for Control {
230    type Error = ();
231
232    fn try_into(self) -> Result<v4l2_control, Self::Error> {
233        unsafe {
234            let mut ctrl = v4l2_control {
235                id: self.id,
236                ..mem::zeroed()
237            };
238            match self.value {
239                Value::None => Ok(ctrl),
240                Value::Integer(val) => {
241                    ctrl.value = val as i32;
242                    Ok(ctrl)
243                }
244                Value::Boolean(val) => {
245                    ctrl.value = val as i32;
246                    Ok(ctrl)
247                }
248                _ => Err(()),
249            }
250        }
251    }
252}