1use bitflags::bitflags;
2use std::convert::{TryFrom, TryInto};
3use std::{ffi, fmt, mem, str};
4
5use crate::sys::*;
6
7#[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 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)]
106pub 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)]
146pub struct Description {
148 pub id: u32,
150 pub typ: Type,
152 pub name: String,
154 pub minimum: i64,
156 pub maximum: i64,
158 pub step: u64,
160 pub default: i64,
162 pub flags: Flags,
164
165 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)]
215pub enum Value {
217 None,
219 Integer(i64),
221 Boolean(bool),
222 String(String),
223 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}