blackmagic_camera_control/
rawcommand.rs1use crate::command::Command;
2use fixed::types::I5F11;
3use num_traits::cast::FromPrimitive;
4use std::convert::TryInto;
5use thiserror::Error;
6
7#[derive(Error, Debug)]
8pub enum CommandError {
9 #[error("Message is too short")]
10 MessageShort,
11
12 #[error("Category not defined")]
13 CategoryNotDefined,
14
15 #[error("Parameter not defined")]
16 ParameterNotDefined,
17
18 #[error("Not Enough Bytes")]
19 NotEnoughBytes,
20
21 #[error(transparent)]
22 UTF8Error(#[from] std::string::FromUtf8Error),
23}
24
25#[derive(Debug, PartialEq)]
26pub enum Operation {
27 AssignValue,
28 OffsetValue,
29 Unknown,
30}
31
32impl Operation {
33 pub fn from_u8(id: u8) -> Self {
34 match id {
35 0 => Operation::AssignValue,
36 1 => Operation::OffsetValue,
37 _ => Operation::Unknown,
38 }
39 }
40
41 pub fn id(&self) -> u8 {
42 match self {
43 Operation::AssignValue => 0,
44 Operation::OffsetValue => 1,
45 Operation::Unknown => 2,
46 }
47 }
48}
49
50pub trait Parameter {
51 fn id(&self) -> u8;
52
53 fn from_raw(cmd: RawCommand) -> Result<Self, CommandError>
54 where
55 Self: Sized;
56
57 fn raw_type(&self) -> u8;
58
59 fn to_bytes(&self) -> Vec<u8>;
60
61 fn normalized_name(&self) -> String;
62}
63
64#[derive(Debug)]
65pub struct RawCommand {
66 pub destination_device: u8,
67 pub command_id: u8,
68 pub category: u8,
69 pub parameter: u8,
70 pub data_type: u8,
71 pub operation: u8,
72 pub data: Vec<u8>,
73}
74
75impl RawCommand {
76 pub fn from_raw(data: &[u8]) -> Result<Self, CommandError> {
78 if data.len() < 8 {
79 return Err(CommandError::MessageShort);
80 }
81
82 Ok(RawCommand {
83 destination_device: data[0],
84 command_id: data[2],
85 category: data[4],
86 parameter: data[5],
87 data_type: data[6],
88 operation: data[7],
89
90 data: data[8..8 + (data[1] - 4) as usize].to_vec(),
91 })
92 }
93
94 pub fn to_raw(destination: u8, operation: Operation, cmd: &Command) -> Vec<u8> {
95 let mut v = Vec::new();
96
97 let mut data = cmd.to_bytes();
98
99 v.push(destination);
101 v.push(data.len() as u8 + 4);
103 v.push(0);
105 v.push(0);
107
108 v.push(cmd.id());
110 v.push(cmd.parameter_id());
112 v.push(cmd.raw_type());
114 v.push(operation.id());
116
117 v.append(&mut data);
119
120 v
121 }
122}
123
124pub trait ParamType {
125 fn from_bytes(data: &[u8]) -> Result<Self, CommandError>
126 where
127 Self: Sized;
128
129 fn to_bytes(&self) -> Vec<u8>;
130
131 fn data_as_string(&self) -> String;
132}
133
134impl ParamType for String {
135 fn from_bytes(data: &[u8]) -> Result<Self, CommandError> {
136 Ok(String::from_utf8(data.to_vec())?)
137 }
138
139 fn to_bytes(&self) -> Vec<u8> {
140 self.as_bytes().to_vec()
141 }
142 fn data_as_string(&self) -> String {
143 self.clone()
144 }
145}
146
147impl ParamType for u8 {
148 fn from_bytes(data: &[u8]) -> Result<Self, CommandError> {
149 data.first()
150 .map(|v| *v as u8)
151 .ok_or(CommandError::NotEnoughBytes)
152 }
153
154 fn to_bytes(&self) -> Vec<u8> {
155 self.to_le_bytes().to_vec()
156 }
157 fn data_as_string(&self) -> String {
158 self.to_string()
159 }
160}
161
162impl ParamType for i8 {
163 fn from_bytes(data: &[u8]) -> Result<Self, CommandError> {
164 data.first()
165 .map(|v| *v as i8)
166 .ok_or(CommandError::NotEnoughBytes)
167 }
168
169 fn to_bytes(&self) -> Vec<u8> {
170 self.to_le_bytes().to_vec()
171 }
172
173 fn data_as_string(&self) -> String {
174 self.to_string()
175 }
176}
177
178impl ParamType for i16 {
179 fn from_bytes(data: &[u8]) -> Result<Self, CommandError> {
180 data.chunks_exact(2)
181 .next()
182 .ok_or(CommandError::NotEnoughBytes)
183 .map(|x| i16::from_le_bytes(x.try_into().unwrap()))
184 }
185
186 fn to_bytes(&self) -> Vec<u8> {
187 self.to_le_bytes().to_vec()
188 }
189 fn data_as_string(&self) -> String {
190 self.to_string()
191 }
192}
193
194impl ParamType for i32 {
195 fn from_bytes(data: &[u8]) -> Result<Self, CommandError> {
196 data.chunks_exact(4)
197 .next()
198 .ok_or(CommandError::NotEnoughBytes)
199 .map(|x| i32::from_le_bytes(x.try_into().unwrap()))
200 }
201
202 fn to_bytes(&self) -> Vec<u8> {
203 self.to_le_bytes().to_vec()
204 }
205
206 fn data_as_string(&self) -> String {
207 self.to_string()
208 }
209}
210
211impl ParamType for i64 {
212 fn from_bytes(data: &[u8]) -> Result<Self, CommandError> {
213 data.chunks_exact(8)
214 .next()
215 .ok_or(CommandError::NotEnoughBytes)
216 .map(|x| i64::from_le_bytes(x.try_into().unwrap()))
217 }
218
219 fn to_bytes(&self) -> Vec<u8> {
220 self.to_le_bytes().to_vec()
221 }
222
223 fn data_as_string(&self) -> String {
224 self.to_string()
225 }
226}
227
228impl ParamType for f32 {
229 fn from_bytes(data: &[u8]) -> Result<Self, CommandError> {
230 data.chunks_exact(8)
231 .next()
232 .ok_or(CommandError::NotEnoughBytes)
233 .map(|x| f32::from(I5F11::from_le_bytes(x.try_into().unwrap())))
234 }
235
236 fn to_bytes(&self) -> Vec<u8> {
237 I5F11::from_f32(*self).unwrap().to_le_bytes().to_vec()
238 }
239
240 fn data_as_string(&self) -> String {
241 self.to_string()
242 }
243}
244
245impl<T: ParamType> ParamType for Vec<T> {
246 fn from_bytes(data: &[u8]) -> Result<Vec<T>, CommandError> {
247 data.chunks_exact(std::mem::size_of::<T>())
248 .map(<T as ParamType>::from_bytes)
249 .collect()
250 }
251
252 fn to_bytes(&self) -> Vec<u8> {
253 self.iter().flat_map(|x| x.to_bytes()).collect()
254 }
255
256 fn data_as_string(&self) -> String {
257 let mut out = String::new();
258
259 for (index, val) in self.iter().enumerate() {
260 if index != 0 {
261 out.push_str(", ");
262 }
263 out.push_str(&val.data_as_string());
264 }
265
266 out
267 }
268}