1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
13#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
14#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS), ts(export))]
15pub enum ResolutionMode {
16 FullHD60,
18 FullHD30,
20 FullHD25,
22 HD60,
24 HD30,
26 HD25,
28 Unknown(u8),
30}
31
32impl ResolutionMode {
33 pub fn from_byte(mode: u8) -> Self {
41 match mode {
42 0x00 => ResolutionMode::FullHD60,
43 0x01 => ResolutionMode::FullHD30,
44 0x02 => ResolutionMode::FullHD25,
45 0x03 => ResolutionMode::HD60,
46 0x04 => ResolutionMode::HD30,
47 0x05 => ResolutionMode::HD25,
48 _ => ResolutionMode::Unknown(mode),
49 }
50 }
51
52 pub fn description(&self) -> &'static str {
54 match self {
55 ResolutionMode::FullHD60 => "1080p60 (1920x1080 @ 60fps)",
56 ResolutionMode::FullHD30 => "1080p30 (1920x1080 @ 30fps)",
57 ResolutionMode::FullHD25 => "1080p25 (1920x1080 @ 25fps)",
58 ResolutionMode::HD60 => "720p60 (1280x720 @ 60fps)",
59 ResolutionMode::HD30 => "720p30 (1280x720 @ 30fps)",
60 ResolutionMode::HD25 => "720p25 (1280x720 @ 25fps)",
61 ResolutionMode::Unknown(_) => "Unknown resolution mode",
62 }
63 }
64
65 pub fn width(&self) -> Option<u32> {
67 match self {
68 ResolutionMode::FullHD60 | ResolutionMode::FullHD30 | ResolutionMode::FullHD25 => {
69 Some(1920)
70 }
71 ResolutionMode::HD60 | ResolutionMode::HD30 | ResolutionMode::HD25 => Some(1280),
72 ResolutionMode::Unknown(_) => None,
73 }
74 }
75
76 pub fn height(&self) -> Option<u32> {
78 match self {
79 ResolutionMode::FullHD60 | ResolutionMode::FullHD30 | ResolutionMode::FullHD25 => {
80 Some(1080)
81 }
82 ResolutionMode::HD60 | ResolutionMode::HD30 | ResolutionMode::HD25 => Some(720),
83 ResolutionMode::Unknown(_) => None,
84 }
85 }
86
87 pub fn frame_rate(&self) -> Option<f32> {
89 match self {
90 ResolutionMode::FullHD60 | ResolutionMode::HD60 => Some(60.0),
91 ResolutionMode::FullHD30 | ResolutionMode::HD30 => Some(30.0),
92 ResolutionMode::FullHD25 | ResolutionMode::HD25 => Some(25.0),
93 ResolutionMode::Unknown(_) => None,
94 }
95 }
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
103#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
104#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
105#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS), ts(export))]
106pub enum PictureEffectMode {
107 Off,
109 Negative,
114 BlackAndWhite,
116 Sepia,
121 Sketch,
126 Emboss,
131 Mosaic,
136 Unknown(u8),
138}
139
140impl PictureEffectMode {
141 pub fn from_byte(effect: u8) -> Self {
149 match effect {
150 0x00 | 0x02 => PictureEffectMode::Off,
151 0x01 => PictureEffectMode::Negative,
152 0x03 => PictureEffectMode::Sepia,
153 0x04 => PictureEffectMode::BlackAndWhite,
154 0x05 => PictureEffectMode::Emboss,
155 0x06 => PictureEffectMode::Mosaic,
156 _ => PictureEffectMode::Unknown(effect),
157 }
158 }
159
160 pub fn description(&self) -> &'static str {
162 match self {
163 PictureEffectMode::Off => "Off (normal)",
164 PictureEffectMode::Negative => "Negative",
165 PictureEffectMode::BlackAndWhite => "Black & White",
166 PictureEffectMode::Sepia => "Sepia",
167 PictureEffectMode::Sketch => "Sketch",
168 PictureEffectMode::Emboss => "Emboss",
169 PictureEffectMode::Mosaic => "Mosaic",
170 PictureEffectMode::Unknown(_) => "Unknown picture effect",
171 }
172 }
173
174 pub fn as_byte(&self) -> u8 {
176 match self {
177 PictureEffectMode::Off => 0x00,
178 PictureEffectMode::Negative => 0x01,
179 PictureEffectMode::BlackAndWhite => 0x04,
180 PictureEffectMode::Sepia => 0x03,
181 PictureEffectMode::Sketch => 0x04,
182 PictureEffectMode::Emboss => 0x05,
183 PictureEffectMode::Mosaic => 0x06,
184 PictureEffectMode::Unknown(value) => *value,
185 }
186 }
187}
188
189#[derive(Debug, Clone, Copy, PartialEq, Eq)]
193pub enum NdFilterPosition {
194 Clear,
196 OneQuarter,
198 OneEighth,
200 OneSixteenth,
202 OneThirtySecond,
204 OneSixtyFourth,
206 Unknown(u8),
208}
209
210impl NdFilterPosition {
211 pub fn from_byte(position: u8) -> Self {
219 match position {
220 0x00 => NdFilterPosition::Clear,
221 0x01 => NdFilterPosition::OneQuarter,
222 0x02 => NdFilterPosition::OneEighth,
223 0x03 => NdFilterPosition::OneSixteenth,
224 0x04 => NdFilterPosition::OneThirtySecond,
225 0x05 => NdFilterPosition::OneSixtyFourth,
226 _ => NdFilterPosition::Unknown(position),
227 }
228 }
229
230 pub fn description(&self) -> &'static str {
232 match self {
233 NdFilterPosition::Clear => "Clear (no filter)",
234 NdFilterPosition::OneQuarter => "1/4 ND",
235 NdFilterPosition::OneEighth => "1/8 ND",
236 NdFilterPosition::OneSixteenth => "1/16 ND",
237 NdFilterPosition::OneThirtySecond => "1/32 ND",
238 NdFilterPosition::OneSixtyFourth => "1/64 ND",
239 NdFilterPosition::Unknown(_) => "Unknown ND filter position",
240 }
241 }
242
243 pub fn as_byte(&self) -> u8 {
245 match self {
246 NdFilterPosition::Clear => 0x00,
247 NdFilterPosition::OneQuarter => 0x01,
248 NdFilterPosition::OneEighth => 0x02,
249 NdFilterPosition::OneSixteenth => 0x03,
250 NdFilterPosition::OneThirtySecond => 0x04,
251 NdFilterPosition::OneSixtyFourth => 0x05,
252 NdFilterPosition::Unknown(value) => *value,
253 }
254 }
255
256 pub fn reduction_factor(&self) -> Option<(u32, u32)> {
259 match self {
260 NdFilterPosition::Clear => Some((1, 1)),
261 NdFilterPosition::OneQuarter => Some((1, 4)),
262 NdFilterPosition::OneEighth => Some((1, 8)),
263 NdFilterPosition::OneSixteenth => Some((1, 16)),
264 NdFilterPosition::OneThirtySecond => Some((1, 32)),
265 NdFilterPosition::OneSixtyFourth => Some((1, 64)),
266 NdFilterPosition::Unknown(_) => None,
267 }
268 }
269
270 pub fn stops_reduction(&self) -> Option<f32> {
273 match self {
274 NdFilterPosition::Clear => Some(0.0),
275 NdFilterPosition::OneQuarter => Some(2.0),
276 NdFilterPosition::OneEighth => Some(3.0),
277 NdFilterPosition::OneSixteenth => Some(4.0),
278 NdFilterPosition::OneThirtySecond => Some(5.0),
279 NdFilterPosition::OneSixtyFourth => Some(6.0),
280 NdFilterPosition::Unknown(_) => None,
281 }
282 }
283}
284
285#[cfg(test)]
286mod tests {
287 use super::*;
288
289 #[test]
290 fn test_resolution_mode_conversion() {
291 assert_eq!(ResolutionMode::from_byte(0x00), ResolutionMode::FullHD60);
292 assert_eq!(ResolutionMode::from_byte(0x01), ResolutionMode::FullHD30);
293 assert_eq!(ResolutionMode::from_byte(0x04), ResolutionMode::HD30);
294 assert_eq!(
295 ResolutionMode::from_byte(0xFF),
296 ResolutionMode::Unknown(0xFF)
297 );
298 }
299
300 #[test]
301 fn test_resolution_properties() {
302 let mode = ResolutionMode::FullHD60;
303 assert_eq!(mode.width(), Some(1920));
304 assert_eq!(mode.height(), Some(1080));
305 assert_eq!(mode.frame_rate(), Some(60.0));
306 assert_eq!(mode.description(), "1080p60 (1920x1080 @ 60fps)");
307
308 let unknown = ResolutionMode::Unknown(0x99);
309 assert_eq!(unknown.width(), None);
310 assert_eq!(unknown.height(), None);
311 assert_eq!(unknown.frame_rate(), None);
312 }
313
314 #[test]
315 fn test_nd_filter_descriptions() {
316 assert_eq!(NdFilterPosition::Clear.description(), "Clear (no filter)");
317 assert_eq!(NdFilterPosition::OneQuarter.description(), "1/4 ND");
318 assert_eq!(NdFilterPosition::OneSixtyFourth.description(), "1/64 ND");
319 assert_eq!(
320 NdFilterPosition::Unknown(0xFF).description(),
321 "Unknown ND filter position"
322 );
323 }
324
325 #[test]
326 fn test_picture_effect_descriptions() {
327 assert_eq!(PictureEffectMode::Off.description(), "Off (normal)");
328 assert_eq!(PictureEffectMode::Negative.description(), "Negative");
329 assert_eq!(
330 PictureEffectMode::BlackAndWhite.description(),
331 "Black & White"
332 );
333 assert_eq!(PictureEffectMode::from_byte(0x02), PictureEffectMode::Off);
334 assert_eq!(
335 PictureEffectMode::from_byte(0x04),
336 PictureEffectMode::BlackAndWhite
337 );
338 assert_eq!(PictureEffectMode::BlackAndWhite.as_byte(), 0x04);
339 assert_eq!(
340 PictureEffectMode::Unknown(0xFF).description(),
341 "Unknown picture effect"
342 );
343 }
344}