1#![crate_name = "wake_rs"]
2#[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
21pub const DATA_MAX_LEN: usize = 0xff;
23
24#[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#[derive(Default)]
58pub struct Packet {
59 pub address: Option<u8>,
61 pub command: u8,
63 pub data: Option<Vec<u8>>,
65}
66
67impl fmt::Display for Packet {
68 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
101impl Wake for Vec<u8> {
103 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 fn stuff(&self) -> Vec<u8> {
143 assert!(self.len() >= (PACKET_MIN_LEN - 1)); 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 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
197pub trait Decode {
199 fn decode(&self) -> Result<Packet, WakeError>;
200}
201
202impl Decode for Vec<u8> {
204 fn decode(&self) -> Result<Packet, WakeError> {
225 if self.len() < PACKET_MIN_LEN {
227 return Err(WakeError::TooShortPacket);
228 }
229 if self[0] != FEND {
231 return Err(WakeError::CannotFindStart);
232 }
233 let mut destuffed_pkt = self.dry()?;
235 let mut v_iter = destuffed_pkt.iter().enumerate();
236 v_iter.next(); 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 let (i, data_len) = v_iter.next().ok_or(WakeError::TooShortPacket)?;
253 if (destuffed_pkt.len() - i - 2) != *data_len as usize {
255 return Err(WakeError::WrongPacketLength);
256 }
257 decoded.data = match data_len {
259 0 => None,
260 _ => Some(destuffed_pkt[i + 1..destuffed_pkt.len() - 1].to_vec()),
261 };
262 let received_crc = destuffed_pkt.remove(destuffed_pkt.len() - 1);
264 if received_crc != destuffed_pkt.to_vec().crc() {
266 Err(WakeError::WrongPacketCrc)
267 } else {
268 Ok(decoded)
269 }
270 }
271}
272
273pub trait Encode {
275 fn encode(&self) -> Result<Vec<u8>, WakeError>;
276}
277
278impl Encode for Packet {
280 fn encode(&self) -> Result<Vec<u8>, WakeError> {
299 let mut encoded_packet: Vec<u8> = vec![];
300 encoded_packet.push(FEND);
302 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 if self.command > 0x7f {
311 return Err(WakeError::WrongCmdRange);
312 }
313 encoded_packet.push(self.command);
314 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 encoded_packet.push(encoded_packet.crc());
324 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 let a = vec![FEND, FESC, 1, 2, 3, 4, 5, FEND]; let b = vec![FEND, FESC, TFESC, 1, 2, 3, 4, 5, FESC, TFEND]; assert_eq!(a.stuff(), b);
347
348 let a = vec![FEND, 3, 0];
350 assert_eq!(a.stuff(), a);
351
352 let a = vec![];
354 let result = std::panic::catch_unwind(|| a.stuff());
355 assert!(result.is_err());
356
357 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![]; let t1 = vec![0x34]; let t2 = vec![1, 2, 3, 4, 5, FEND]; let t3 = vec![FEND, FESC, TFESC, 1, 2, 3, 4, 5, FESC]; let t4 = vec![FEND, FESC, 1, 2, 3, 4, 5, FESC, TFEND]; let t5 = vec![FEND, FESC, TFESC, 1, 2, 3, 4, 5, FESC, TFEND]; let a5 = vec![FEND, FESC, 1, 2, 3, 4, 5, FEND]; 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 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 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 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 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 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 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(); 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]; 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 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 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}