1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use std::fmt::{self, Display, Formatter};
const DLE: u8 = 0x10;
const STX: u8 = 0x02;
const ETX: u8 = 0x03;
const NAK: u8 = 0x15;
const HEADER: [u8; 2] = [DLE, STX];
const FOOTER: [u8; 2] = [DLE, ETX];
const NEGATIVE_ACKNOWLEDGEMENT: [u8; 2] = [DLE, NAK];
const HEADER_LENGTH: usize = HEADER.len();
const FOOTER_LENGTH: usize = FOOTER.len();
const BCC_LENGTH: usize = 1;
const LENGTH_MIN: usize = HEADER_LENGTH + FOOTER_LENGTH + BCC_LENGTH;
pub(crate) fn parse_command(command: &[u8]) -> Vec<u8> {
let mut buf = HEADER.to_vec();
let mut bcc = 0;
for byte in command.iter().copied() {
if byte == DLE {
buf.push(byte);
}
buf.push(byte);
bcc ^= byte;
}
for byte in FOOTER.iter().copied() {
buf.push(byte);
if byte != DLE {
bcc ^= byte;
}
}
buf.push(bcc);
buf
}
pub(crate) fn parse_reception(message: &[u8]) -> Result<Vec<u8>, ParseError> {
if message == &NEGATIVE_ACKNOWLEDGEMENT[..] {
return Err(ParseError::NAK);
}
let len = message.len();
if len < LENGTH_MIN {
return Err(ParseError::TooShort(len));
}
let mut buf = vec![];
let mut is_previous_dle = false;
let mut expected_bcc = 0;
for &byte in &message[HEADER_LENGTH..message.len() - FOOTER_LENGTH - BCC_LENGTH] {
if is_previous_dle {
if byte != DLE {
return Err(ParseError::WrongDLE);
}
is_previous_dle = false;
} else {
buf.push(byte);
expected_bcc ^= byte;
is_previous_dle = byte == DLE;
}
}
FOOTER
.iter()
.filter(|&&byte| byte != DLE)
.for_each(|&byte| expected_bcc ^= byte);
let actual_bcc = *message.last().unwrap();
if expected_bcc != actual_bcc {
return Err(ParseError::WrongBCC);
}
Ok(buf)
}
#[derive(Debug)]
pub enum ParseError {
NAK,
TooShort(usize),
WrongDLE,
WrongBCC,
}
impl Display for ParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
ParseError::NAK => write!(f, "Received an negative acknowledgement."),
ParseError::TooShort(l) => write!(f, "Received too short ({} bytes) message,", l),
ParseError::WrongDLE => write!(
f,
"DLE must be contained twice or more in a row, but was not."
),
ParseError::WrongBCC => write!(f, "Wrong BCC."),
}
}
}
impl std::error::Error for ParseError {}