bmd_speededitor/
speed_editor.rs

1pub mod handler;
2pub mod key;
3pub mod key_led;
4
5use chrono::{DateTime, Utc};
6use hidapi::{HidDevice, HidError};
7use std::{io::Read, thread, time::Duration};
8use strum::IntoEnumIterator;
9
10use handler::{
11    ConnectedHandler, DisconnectedHandler, JogHandler, KeyDownHandler, KeyHandler, KeyUpHandler,
12    KeysHandler, UnknownHandler,
13};
14use key::Key;
15use key_led::KeyLed;
16
17pub struct SpeedEditor {
18    pub device: Option<HidDevice>,
19    pub last_authenticated_at: Option<DateTime<Utc>>,
20    pub current_keys: Vec<Key>,
21    pub current_key_leds: Vec<KeyLed>,
22    pub connected_handler: ConnectedHandler,
23    pub disconnected_handler: DisconnectedHandler,
24    pub keys_handler: KeysHandler,
25    pub key_handler: KeyHandler,
26    pub key_down_handler: KeyDownHandler,
27    pub key_up_handler: KeyUpHandler,
28    pub jog_handler: JogHandler,
29    pub unknown_handler: UnknownHandler,
30}
31
32pub type SpeedEditorResult = Result<(), SpeedEditorError>;
33
34#[derive(Debug)]
35pub enum SpeedEditorError {
36    HidApiError(hidapi::HidError),
37    StdIoError(std::io::Error),
38    AuthGetKbdChallengeError,
39    AuthGetKbdResponseError,
40    AuthGetKbdStatusError,
41    CallbackExecutionError,
42}
43
44impl From<hidapi::HidError> for SpeedEditorError {
45    fn from(e: HidError) -> Self {
46        SpeedEditorError::HidApiError(e)
47    }
48}
49
50impl From<std::io::Error> for SpeedEditorError {
51    fn from(e: std::io::Error) -> Self {
52        SpeedEditorError::StdIoError(e)
53    }
54}
55
56impl SpeedEditor {
57    const VID: u16 = 7899;
58    const PID: u16 = 55822;
59    const READ_TIMEOUT: i32 = 1000;
60    const RECONNECT_INTERVAL: u64 = 100;
61    const AUTH_INTERVAL: i64 = 30000;
62
63    const AUTH_EVEN_TBL: [u64; 8] = [
64        4242707987619187656,
65        3069963097229903046,
66        2352841328256802570,
67        12646368222702737177,
68        17018789593460232529,
69        12706253227766860309,
70        11978781369061872007,
71        8438608961089703390,
72    ];
73
74    const AUTH_ODD_TBL: [u64; 8] = [
75        4477338132788707294,
76        2622620659002747676,
77        11637077509869926595,
78        7923852755392722584,
79        8224257920127642516,
80        4049197610885016386,
81        18266591397768539273,
82        7035737829027231430,
83    ];
84
85    const MASK: u64 = 12077075256910773232;
86
87    fn rol8(&self, v: u64) -> u64 {
88        ((v << 56) | (v >> 8)) & 18446744073709551615
89    }
90
91    fn rol8n(&self, mut v: u64, n: u64) -> u64 {
92        for _ in 0..n {
93            v = self.rol8(v);
94        }
95        v
96    }
97
98    /*
99     * Authenticate module is taken from:
100     * https://github.com/smunaut/blackmagic-misc
101     * Copyright (C) 2021 Sylvain Munaut <tnt@246tNt.com>
102     *
103     * */
104    fn auth(&mut self) -> SpeedEditorResult {
105        let mut buf = [0; 8];
106        let mut bytes = vec![0; 10];
107
108        if let Some(device) = &self.device {
109            device.send_feature_report(&[0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0])?;
110            bytes[0] = 0x6;
111
112            let _ = device.get_feature_report(&mut bytes)?;
113            if bytes[0] != 0x6 || bytes[1] != 0x0 {
114                return Err(SpeedEditorError::AuthGetKbdChallengeError);
115            }
116
117            (&bytes[2..]).read_exact(&mut buf).unwrap();
118            let challenge = u64::from_le_bytes(buf);
119
120            device.send_feature_report(&[0x6, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0])?;
121            let _ = device.get_feature_report(&mut bytes)?;
122            if bytes[0] != 0x6 || bytes[1] != 0x2 {
123                return Err(SpeedEditorError::AuthGetKbdResponseError);
124            }
125
126            let n = challenge & 7;
127            let mut v = self.rol8n(challenge, n);
128            let k: u64;
129            if (v & 1) == ((120 >> n) & 1) {
130                k = Self::AUTH_EVEN_TBL[n as usize];
131            } else {
132                v = v ^ self.rol8(v);
133                k = Self::AUTH_ODD_TBL[n as usize];
134            }
135
136            let response = v ^ (self.rol8(v) & Self::MASK) ^ k;
137            buf = response.to_le_bytes();
138
139            bytes[1] = 0x3;
140            for i in 0..8 {
141                bytes[i + 2] = buf[i];
142            }
143
144            device.send_feature_report(bytes.as_slice())?;
145
146            let _ = device.get_feature_report(&mut bytes)?;
147            if bytes[0] != 0x6 || bytes[1] != 0x4 {
148                return Err(SpeedEditorError::AuthGetKbdStatusError);
149            }
150
151            self.last_authenticated_at = Some(Utc::now());
152        }
153
154        Ok(())
155    }
156
157    fn is_expired(&self) -> bool {
158        if let Some(at) = self.last_authenticated_at {
159            let elapsed_time = Utc::now() - at;
160            elapsed_time.num_milliseconds() >= Self::AUTH_INTERVAL
161        } else {
162            true
163        }
164    }
165
166    pub fn run(&mut self) -> SpeedEditorResult {
167        loop {
168            if self.device.is_none() {
169                self.connect()?;
170                continue;
171            }
172
173            if self.is_expired() {
174                self.auth()?;
175                continue;
176            }
177
178            if let Some(device) = &self.device {
179                let mut buf = [0; 64];
180                match device.read_timeout(&mut buf, Self::READ_TIMEOUT) {
181                    Ok(len) => {
182                        if len > 0 {
183                            self.process_events(&buf[..len])?;
184                        }
185                    }
186                    Err(_) => self.disconnect()?,
187                }
188            }
189        }
190    }
191
192    fn process_events(&mut self, buf: &[u8]) -> SpeedEditorResult {
193        match buf[0] {
194            3 => self.jog_event(buf[1], &buf[2..])?,
195            4 => self.key_event(&buf[1..])?,
196            _ => self.unknown_event(buf)?,
197        }
198
199        Ok(())
200    }
201
202    fn jog_event(&mut self, mode: u8, buf: &[u8]) -> SpeedEditorResult {
203        let mut data = [0; 4];
204        (&buf[..]).read_exact(&mut data)?;
205        let value = i32::from_le_bytes(data) / 360;
206        self.jog_handler.call(mode, value)?;
207        Ok(())
208    }
209
210    fn key_event(&mut self, buf: &[u8]) -> SpeedEditorResult {
211        let current_keys: Vec<Key> = buf
212            .iter()
213            .enumerate()
214            .filter(|&(i, _)| i % 2 == 0)
215            .filter(|&(_, &v)| v > 0)
216            .map(|(_, &v)| Key::try_from(v).unwrap())
217            .collect();
218
219        // Are you pressing 7 or more keys at the same time?
220        if current_keys == self.current_keys {
221            return Ok(());
222        }
223
224        let down_keys: Vec<Key> = current_keys
225            .iter()
226            .map(|&v| {
227                if self.current_keys.iter().find(|&k| *k == v) == None {
228                    v
229                } else {
230                    Key::None
231                }
232            })
233            .filter(|&v| v > Key::None)
234            .collect();
235
236        let up_keys: Vec<Key> = self
237            .current_keys
238            .iter()
239            .map(|&v| {
240                if current_keys.iter().find(|&k| *k == v) == None {
241                    v
242                } else {
243                    Key::None
244                }
245            })
246            .filter(|&v| v > Key::None)
247            .collect();
248
249        self.current_keys = current_keys.to_owned();
250
251        for k in down_keys {
252            self.key_handler.call(k, true)?;
253            self.key_down_handler.call(k)?;
254        }
255
256        for k in up_keys {
257            self.key_handler.call(k, false)?;
258            self.key_up_handler.call(k)?;
259        }
260
261        self.keys_handler.call(&self.current_keys)?;
262
263        Ok(())
264    }
265
266    fn unknown_event(&mut self, buf: &[u8]) -> SpeedEditorResult {
267        self.unknown_handler.call(buf)
268    }
269
270    fn disconnect(&mut self) -> SpeedEditorResult {
271        self.device = None;
272        self.last_authenticated_at = None;
273        self.disconnected_handler.call()
274    }
275
276    // Try to connect
277    fn connect(&mut self) -> SpeedEditorResult {
278        let api = hidapi::HidApi::new()?;
279
280        self.device = match api.open(SpeedEditor::VID, SpeedEditor::PID) {
281            Ok(device) => {
282                self.connected_handler.call()?;
283                Some(device)
284            }
285            Err(_) => {
286                thread::sleep(Duration::from_millis(Self::RECONNECT_INTERVAL));
287                None
288            }
289        };
290
291        Ok(())
292    }
293
294    fn add_key_led(&mut self, led: KeyLed) {
295        self.current_key_leds.push(led);
296    }
297
298    fn remove_key_led(&mut self, led: KeyLed) {
299        self.current_key_leds = self
300            .current_key_leds
301            .iter()
302            .filter(|&i| *i != led)
303            .map(|i| *i)
304            .collect::<Vec<KeyLed>>();
305    }
306
307    pub fn set_all_key_leds(&mut self, on: bool) -> SpeedEditorResult {
308        for led in KeyLed::iter() {
309            if on {
310                self.add_key_led(led);
311            } else {
312                self.remove_key_led(led);
313            }
314        }
315
316        self.light_key_leds()
317    }
318
319    pub fn set_key_led(&mut self, led: KeyLed, on: bool) -> SpeedEditorResult {
320        if on {
321            self.add_key_led(led);
322        } else {
323            self.remove_key_led(led);
324        }
325
326        self.light_key_leds()
327    }
328
329    pub fn set_leds(&mut self, leds: Vec<KeyLed>, on: bool) -> SpeedEditorResult {
330        for led in leds {
331            if on {
332                self.add_key_led(led);
333            } else {
334                self.remove_key_led(led);
335            }
336        }
337
338        self.light_key_leds()
339    }
340
341    fn light_key_leds(&mut self) -> SpeedEditorResult {
342        if let Some(device) = &self.device {
343            let mut leds: i32 = 0;
344            for i in self.current_key_leds.iter() {
345                leds |= 1 << *i as i32;
346            }
347
348            let buf = leds.to_le_bytes();
349            let mut data = [0x2, 0x0, 0x0, 0x0, 0x0, 0x0];
350            data[0] = 0x2;
351            for i in 0..4 {
352                data[i + 1] = buf[i];
353            }
354
355            device.write(data.as_slice())?;
356        }
357        Ok(())
358    }
359
360    pub fn on_connected<F>(&mut self, callback: F)
361    where
362        F: FnMut() -> SpeedEditorResult + Sync + Send + 'static,
363    {
364        self.connected_handler.callbacks.push(Box::new(callback));
365    }
366
367    pub fn on_disconnected<F>(&mut self, callback: F)
368    where
369        F: FnMut() -> SpeedEditorResult + Sync + Send + 'static,
370    {
371        self.disconnected_handler.callbacks.push(Box::new(callback));
372    }
373
374    pub fn on_keys<F>(&mut self, callback: F)
375    where
376        F: FnMut(Vec<Key>) -> SpeedEditorResult + Send + Sync + 'static,
377    {
378        self.keys_handler.callbacks.push(Box::new(callback));
379    }
380
381    pub fn on_key<F>(&mut self, callback: F)
382    where
383        F: FnMut(Key, bool) -> SpeedEditorResult + Sync + Send + 'static,
384    {
385        self.key_handler.callbacks.push(Box::new(callback));
386    }
387
388    pub fn on_key_down<F>(&mut self, callback: F)
389    where
390        F: FnMut(Key) -> SpeedEditorResult + Sync + Send + 'static,
391    {
392        self.key_down_handler.callbacks.push(Box::new(callback));
393    }
394
395    pub fn on_key_up<F>(&mut self, callback: F)
396    where
397        F: FnMut(Key) -> SpeedEditorResult + Sync + Send + 'static,
398    {
399        self.key_up_handler.callbacks.push(Box::new(callback));
400    }
401
402    pub fn on_jog<F>(&mut self, callback: F)
403    where
404        F: FnMut(u8, i32) -> SpeedEditorResult + Sync + Send + 'static,
405    {
406        self.jog_handler.callbacks.push(Box::new(callback));
407    }
408
409    pub fn on_unknown<F>(&mut self, callback: F)
410    where
411        F: FnMut(&[u8]) -> SpeedEditorResult + Sync + Send + 'static,
412    {
413        self.unknown_handler.callbacks.push(Box::new(callback));
414    }
415}
416
417#[cfg(test)]
418mod tests {
419    #[test]
420    fn it_works() {
421        let result = 2 + 2;
422        assert_eq!(result, 4);
423    }
424}