wake_rs/
lib.rs

1#![crate_name = "wake_rs"]
2//! `Wake` is a serial communication protocol highly optimized for microcontrollers.
3//! `wake-rs` is a library written in Rust for encoding/decoding Wake protocol packets.
4
5#[cfg(test)]
6extern crate rand;
7
8#[cfg(test)]
9use rand::Rng;
10use std::fmt;
11
12const FEND: u8 = 0xC0;
13const FESC: u8 = 0xDB;
14const TFEND: u8 = 0xDC;
15const TFESC: u8 = 0xDD;
16
17const ADDR_MASK: u8 = 0x80;
18const CRC_INIT: u8 = 0xDE;
19const PACKET_MIN_LEN: usize = 4;
20
21/// Maximum supported data length. Might be reduced depends on available resources.
22pub const DATA_MAX_LEN: usize = 0xff;
23
24/// Wake decoder/encoder errors
25#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
26pub enum WakeError {
27    TooShortPacket,
28    CannotFindStart,
29    DestuffingFailed,
30    WrongPacketLength,
31    WrongPacketCrc,
32    WrongAddrRange,
33    WrongCmdRange,
34}
35
36impl std::error::Error for WakeError {
37    fn description(&self) -> &str {
38        match *self {
39            WakeError::TooShortPacket => "Too short packet",
40            WakeError::CannotFindStart => "Can't find a start of the packet",
41            WakeError::DestuffingFailed => "De-stuffing failed",
42            WakeError::WrongPacketLength => "Wrong packet length",
43            WakeError::WrongPacketCrc => "Wrong packet CRC",
44            WakeError::WrongAddrRange => "Address is out of range [0 - 127]",
45            WakeError::WrongCmdRange => "Command is out of range [0 - 127]",
46        }
47    }
48}
49
50impl fmt::Display for WakeError {
51    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52        write!(f, "Wake error: {:?}", self)
53    }
54}
55
56/// Wake packet: address, command, and data
57#[derive(Default)]
58pub struct Packet {
59    /// Device address (optional) [0 - 127]
60    pub address: Option<u8>,
61    /// Command [0 - 127]
62    pub command: u8,
63    /// Data load (optional)
64    pub data: Option<Vec<u8>>,
65}
66
67impl fmt::Display for Packet {
68    /// Show error in human readable format
69    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70        let addr = match self.address {
71            Some(a) => format!("ADDR: 0x{:02X}", a),
72            None => "ADDR: ----".to_string(),
73        };
74
75        let cmd = format!("CMD:  0x{:02X}", self.command);
76
77        let data = match &self.data {
78            Some(d) => {
79                let mut print = format!("DATA: {} bytes\n", d.len());
80                print.push_str("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f");
81                for (i, item) in d.iter().enumerate() {
82                    if (i == 0) | (i % 16 == 0) {
83                        print.push_str(&format!("\n{:02x}: ", i));
84                    }
85                    print.push_str(&format!("{:02x} ", item));
86                }
87                print
88            }
89            None => ("DATA: none").to_string(),
90        };
91        write!(f, "{}\n{}\n{}\n", addr, cmd, data)
92    }
93}
94
95trait Wake {
96    fn crc(&self) -> u8;
97    fn stuff(&self) -> Vec<u8>;
98    fn dry(&self) -> Result<Vec<u8>, WakeError>;
99}
100
101/// Calculate CRC sum of data in a vector
102impl Wake for Vec<u8> {
103    /// # Input
104    ///
105    /// * 'Vec<u8>` - input data
106    ///
107    /// # Output
108    ///
109    /// * `u8` - Calculated CRC
110    ///
111    fn crc(&self) -> u8 {
112        let mut crc: u8 = CRC_INIT;
113
114        let mut crc8 = |data| {
115            let mut b = data;
116            for _ in 0..8 {
117                crc = if (b ^ crc) & 1 == 1 {
118                    ((crc ^ 0x18) >> 1) | 0x80
119                } else {
120                    (crc >> 1) & !0x80
121                };
122                b >>= 1;
123            }
124        };
125
126        for n in self {
127            crc8(*n);
128        }
129        crc
130    }
131
132    /// Byte stuffing in a vector
133    ///
134    /// # Arguments
135    ///
136    /// * `data: &Vec<u8>` - input data
137    ///
138    /// # Output
139    ///
140    /// * `Vec<u8>` - output data
141    ///
142    fn stuff(&self) -> Vec<u8> {
143        assert!(self.len() >= (PACKET_MIN_LEN - 1)); // without CRC
144        assert_eq!(self[0], FEND);
145        let mut stuffed: Vec<u8> = vec![self[0]];
146        for x in &self[1..] {
147            match *x {
148                FESC => {
149                    stuffed.push(FESC);
150                    stuffed.push(TFESC);
151                }
152                FEND => {
153                    stuffed.push(FESC);
154                    stuffed.push(TFEND);
155                }
156                _ => stuffed.push(*x),
157            }
158        }
159        stuffed
160    }
161
162    /// Byte destuffing in a vector
163    /// /// Translate stuffed bytes into normal data
164    ///
165    /// # Arguments
166    ///
167    /// * `data` - Input data
168    ///
169    /// # Output
170    ///
171    /// * `Result<Vec<u8>, WakeError>` - Destuffed data wrapped in Result
172    ///
173    fn dry(&self) -> Result<Vec<u8>, WakeError> {
174        let mut output: Vec<u8> = vec![];
175        let mut i = 0;
176        while i < self.len() {
177            match self[i] {
178                FESC => {
179                    if i > (self.len() - 2) {
180                        return Err(WakeError::WrongPacketLength);
181                    }
182                    output.push(match self[i + 1] {
183                        TFESC => FESC,
184                        TFEND => FEND,
185                        _ => return Err(WakeError::DestuffingFailed),
186                    });
187                    i += 1;
188                }
189                _ => output.push(self[i]),
190            }
191            i += 1;
192        }
193        Ok(output)
194    }
195}
196
197/// Decode data from wake format to wake packet structure
198pub trait Decode {
199    fn decode(&self) -> Result<Packet, WakeError>;
200}
201
202/// Decode Vec<u8> from wake format to wake packet structure
203impl Decode for Vec<u8> {
204    /// # Output
205    ///
206    /// * `Result<Packet, WakeError>` - command, data or error
207    ///
208    /// # Example
209    ///
210    /// ```
211    /// extern crate wake_rs;
212    /// use wake_rs::Decode;
213    ///
214    /// let encoded_packet = vec![0xC0, 0x03, 0x05, 1, 2, 3, 4, 5, 0x6b];
215    /// let decoded_packet = encoded_packet.decode();
216    /// match decoded_packet {
217    ///     Ok(w) => {
218    ///         println!("Decoded packet\t: {}", w);
219    ///     },
220    ///     Err(err) => println!("Error: {:?}", err),
221    /// }
222    /// ```
223    ///
224    fn decode(&self) -> Result<Packet, WakeError> {
225        // 1: Check packet length
226        if self.len() < PACKET_MIN_LEN {
227            return Err(WakeError::TooShortPacket);
228        }
229        // 2: Check START symbol (FEND)
230        if self[0] != FEND {
231            return Err(WakeError::CannotFindStart);
232        }
233        // 3: Dry packet (remove stuffed bytes)
234        let mut destuffed_pkt = self.dry()?;
235        let mut v_iter = destuffed_pkt.iter().enumerate();
236        v_iter.next(); // skip start symbol
237                       // 4: Get an address (if exists) and a command
238        let mut decoded = Packet::default();
239        let (_, d) = v_iter.next().ok_or(WakeError::TooShortPacket)?;
240        match d {
241            addr @ ADDR_MASK..=0xff => {
242                decoded.address = Some(addr & !ADDR_MASK);
243                let (_, cmd) = v_iter.next().ok_or(WakeError::TooShortPacket)?;
244                decoded.command = *cmd;
245            }
246            cmd => {
247                decoded.address = None;
248                decoded.command = *cmd;
249            }
250        };
251        // 5: Get data length
252        let (i, data_len) = v_iter.next().ok_or(WakeError::TooShortPacket)?;
253        // 8: Check data length
254        if (destuffed_pkt.len() - i - 2) != *data_len as usize {
255            return Err(WakeError::WrongPacketLength);
256        }
257        // 9: Get data
258        decoded.data = match data_len {
259            0 => None,
260            _ => Some(destuffed_pkt[i + 1..destuffed_pkt.len() - 1].to_vec()),
261        };
262        // 6: Get CRC and remove it
263        let received_crc = destuffed_pkt.remove(destuffed_pkt.len() - 1);
264        // 10: Check CRC
265        if received_crc != destuffed_pkt.to_vec().crc() {
266            Err(WakeError::WrongPacketCrc)
267        } else {
268            Ok(decoded)
269        }
270    }
271}
272
273/// Encode packet to wake format
274pub trait Encode {
275    fn encode(&self) -> Result<Vec<u8>, WakeError>;
276}
277
278/// Encode packet to wake format
279impl Encode for Packet {
280    /// # Input
281    ///
282    /// * Wake packet structure with address, command code and data. Address and data are optional.
283    ///
284    /// # Output
285    ///
286    /// * `Vec<u8>` - Encoded data in wake format
287    ///
288    /// # Example
289    ///
290    /// ```
291    /// extern crate wake_rs;
292    /// use wake_rs::Encode;
293    ///
294    /// let p = wake_rs::Packet{address: Some(0x12), command: 3, data: Some(vec!{0x00, 0xeb})};
295    /// let encoded_packet: Vec<u8> = p.encode().unwrap();
296    /// ```
297    ///
298    fn encode(&self) -> Result<Vec<u8>, WakeError> {
299        let mut encoded_packet: Vec<u8> = vec![];
300        // 1. FEND
301        encoded_packet.push(FEND);
302        // 2. Address, if exists
303        if let Some(addr) = self.address {
304            if addr > 0x7f {
305                return Err(WakeError::WrongAddrRange);
306            }
307            encoded_packet.push(addr | ADDR_MASK);
308        }
309        // 3. Command
310        if self.command > 0x7f {
311            return Err(WakeError::WrongCmdRange);
312        }
313        encoded_packet.push(self.command);
314        // 4. Data length; data, if exists
315        match &self.data {
316            Some(d) => {
317                encoded_packet.push(d.len() as u8);
318                encoded_packet.extend(d.iter().cloned());
319            }
320            None => encoded_packet.push(0),
321        }
322        // 5. CRC
323        encoded_packet.push(encoded_packet.crc());
324        // 6. Stuffing
325        Ok(encoded_packet.stuff())
326    }
327}
328
329#[test]
330fn crc_test() {
331    let xs = vec![1, 2, 3, 4, 5];
332    assert_eq!(xs.crc(), 0xd6);
333
334    let xs = vec![0xc0, 0x03, 0x00];
335    assert_eq!(xs.crc(), 0xeb);
336
337    let xs = vec![0xc0, 0x89, 0x03, 0x05, 1, 2, 3, 4, 5];
338    assert_eq!(xs.crc(), 0x69);
339}
340
341#[test]
342fn stuff_test() {
343    // Regular packet
344    let a = vec![FEND, FESC, 1, 2, 3, 4, 5, FEND]; // initial_data
345    let b = vec![FEND, FESC, TFESC, 1, 2, 3, 4, 5, FESC, TFEND]; // stuffed_data
346    assert_eq!(a.stuff(), b);
347
348    // packet with min len
349    let a = vec![FEND, 3, 0];
350    assert_eq!(a.stuff(), a);
351
352    // empty packet, should panic
353    let a = vec![];
354    let result = std::panic::catch_unwind(|| a.stuff());
355    assert!(result.is_err());
356
357    // short packet, should panic
358    let a = vec![FEND, 3];
359    let result = std::panic::catch_unwind(|| a.stuff());
360    assert!(result.is_err());
361}
362
363#[test]
364fn dry_test() {
365    let t0 = vec![]; // empty
366    let t1 = vec![0x34]; // 1 byte
367    let t2 = vec![1, 2, 3, 4, 5, FEND]; // stuffed data without first FEND
368    let t3 = vec![FEND, FESC, TFESC, 1, 2, 3, 4, 5, FESC]; // stuffed data without last byte
369    let t4 = vec![FEND, FESC, 1, 2, 3, 4, 5, FESC, TFEND]; // stuffed data with missed 3rd byte
370    let t5 = vec![FEND, FESC, TFESC, 1, 2, 3, 4, 5, FESC, TFEND]; // well stuffed data
371    let a5 = vec![FEND, FESC, 1, 2, 3, 4, 5, FEND]; // destuffed t5
372    assert_eq!(t0.dry(), Ok(vec![]));
373    assert_eq!(t1.clone().dry(), Ok(t1));
374    assert_eq!(t2.clone().dry(), Ok(t2));
375    assert_eq!(t3.dry(), Err(WakeError::WrongPacketLength));
376    assert_eq!(t4.dry(), Err(WakeError::DestuffingFailed));
377    assert_eq!(t5.dry(), Ok(a5));
378}
379#[test]
380fn encode_packet_test() {
381    // address is out of range
382    let wp = Packet {
383        address: Some(128),
384        command: 9,
385        data: Some(vec![0x12, 0x34]),
386    };
387    assert_eq!(wp.encode(), Err(WakeError::WrongAddrRange));
388    // command is out of range
389    let wp = Packet {
390        address: None,
391        command: 128,
392        data: Some(vec![0x12, 0x34]),
393    };
394    assert_eq!(wp.encode(), Err(WakeError::WrongCmdRange));
395    // without address
396    let wp = Packet {
397        address: None,
398        command: 9,
399        data: Some(vec![0x12, 0x34]),
400    };
401    assert_eq!(wp.encode(), Ok(vec![FEND, 0x09, 0x02, 0x12, 0x34, 160]));
402    // with data
403    let wp = Packet {
404        address: Some(0x12),
405        command: 3,
406        data: Some(vec![0x00, 0xeb]),
407    };
408    assert_eq!(
409        wp.encode(),
410        Ok(vec![FEND, 0x92, 0x03, 0x02, 0x00, 0xeb, 114])
411    );
412    // empty packet
413    let wp = Packet {
414        address: Some(0x13),
415        command: 4,
416        data: None,
417    };
418    assert_eq!(wp.encode(), Ok(vec![FEND, 0x93, 0x04, 0x00, 218]));
419    // empty packet with stuffing
420    let wp = Packet {
421        address: Some(0x40),
422        command: 0x40,
423        data: None,
424    };
425    assert_eq!(wp.encode(), Ok(vec![FEND, FESC, TFEND, 0x40, 0x00, 229]));
426}
427
428#[test]
429fn decode_wo_address_test() {
430    let command = 0x03u8;
431    let data = [1, 2, 3, 4, 5];
432    let n = data.len() as u8;
433    let crc = [0x6B];
434    let wrong_crc = [0x6C];
435
436    let mut good_packet = vec![FEND, command, n];
437    good_packet.extend_from_slice(&data);
438    good_packet.extend_from_slice(&crc);
439    let decoded = good_packet.decode().unwrap(); // TODO: need unwrap?
440    assert_eq!(decoded.command, command);
441    assert_eq!(decoded.data.unwrap(), data);
442
443    let bad_packet_too_short = vec![FEND, command, n];
444    let decoded = bad_packet_too_short.decode();
445    assert_eq!(decoded.err(), Some(WakeError::TooShortPacket));
446
447    let mut bad_packet_wo_start = vec![command, n];
448    bad_packet_wo_start.extend_from_slice(&data);
449    bad_packet_wo_start.extend_from_slice(&crc);
450    let decoded = bad_packet_wo_start.decode();
451    assert_eq!(decoded.err(), Some(WakeError::CannotFindStart));
452
453    let bad_packet_wrong_stuffing = vec![FEND, FESC, FESC, 1, 2, 3, 4, 5, FESC, TFEND]; // stuffed packed with wrong 3rd byte
454    let decoded = bad_packet_wrong_stuffing.decode();
455    assert_eq!(decoded.err(), Some(WakeError::DestuffingFailed));
456
457    let mut bad_packet_wrong_data_len = vec![FEND, command, n - 1];
458    bad_packet_wrong_data_len.extend_from_slice(&data);
459    bad_packet_wrong_data_len.extend_from_slice(&wrong_crc);
460    let decoded = bad_packet_wrong_data_len.decode();
461    assert_eq!(decoded.err(), Some(WakeError::WrongPacketLength));
462
463    let mut bad_packet_wrong_data_len = vec![FEND, command, n + 1];
464    bad_packet_wrong_data_len.extend_from_slice(&data);
465    bad_packet_wrong_data_len.extend_from_slice(&wrong_crc);
466    let decoded = bad_packet_wrong_data_len.decode();
467    assert_eq!(decoded.err(), Some(WakeError::WrongPacketLength));
468
469    let mut bad_packet_wrong_crc = vec![FEND, command, n];
470    bad_packet_wrong_crc.extend_from_slice(&data);
471    bad_packet_wrong_crc.extend_from_slice(&wrong_crc);
472    let decoded = bad_packet_wrong_crc.decode();
473    assert_eq!(decoded.err(), Some(WakeError::WrongPacketCrc));
474}
475
476#[test]
477fn decode_w_address_test() {
478    let address = 0x09u8;
479    let command = 0x03u8;
480    let data = [1, 2, 3, 4, 5];
481    let n = data.len() as u8;
482    let crc = [0x69];
483
484    let mut good_packet = vec![FEND, address | 0x80u8, command, n];
485    good_packet.extend_from_slice(&data);
486    good_packet.extend_from_slice(&crc);
487    let decoded = good_packet.decode();
488    assert_eq!(decoded.is_ok(), true);
489    let decoded = decoded.unwrap();
490    assert_eq!(decoded.address.unwrap(), address);
491    assert_eq!(decoded.command, command);
492    assert_eq!(decoded.data.unwrap(), data);
493
494    // 0x40 test
495    let good_packet = vec![FEND, FESC, TFEND, 0x40, 0x00, 229];
496    let decoded = good_packet.decode();
497    assert_eq!(decoded.is_ok(), true);
498    let decoded = decoded.unwrap();
499    assert_eq!(decoded.address.unwrap(), 0x40);
500    assert_eq!(decoded.command, 0x40);
501    assert_eq!(decoded.data, None);
502}
503
504#[test]
505fn random_encode_decode_test() {
506    let mut rng = rand::thread_rng();
507
508    for _ in 0..100_000 {
509        let address_exists = rng.gen_bool(0.5);
510        let n = rng.gen_range(0..0x100);
511        let mut d: Vec<u8> = Vec::new();
512        for _ in 0..n {
513            d.push(rng.gen_range(0..0xff));
514        }
515
516        let wp = Packet {
517            address: if address_exists {
518                Some(rng.gen_range(0..0x7f))
519            } else {
520                None
521            },
522            command: rng.gen_range(0..0x7f),
523            data: if d.len() == 0 { None } else { Some(d.clone()) },
524        };
525        // print!("{}\n", &wp);
526        let encoded = wp.encode().unwrap();
527        let decoded = encoded.decode().unwrap();
528        assert_eq!(decoded.address, wp.address);
529        assert_eq!(decoded.command, wp.command);
530        assert_eq!(decoded.data, wp.data);
531    }
532}