Skip to main content

moq_v4l/
control.rs

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