blackmagic_camera_control/
rawcommand.rs

1use 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    /// Takes the BLE name of the camera and returns a new BluetoothCamera instance
77    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        //Destination
100        v.push(destination);
101        //Length
102        v.push(data.len() as u8 + 4);
103        //Command id
104        v.push(0);
105        //Reserved
106        v.push(0);
107
108        //Category
109        v.push(cmd.id());
110        //Paramter
111        v.push(cmd.parameter_id());
112        //Type
113        v.push(cmd.raw_type());
114        //Operation
115        v.push(operation.id());
116
117        //Data
118        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}