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
#[macro_use]
extern crate arrayref;
pub use error::Error;
use std::convert::TryFrom;
use std::error::Error as stdError;
use std::io::{Cursor, Write};
mod error;
mod types;
pub use types::*;
#[cfg(test)]
mod tests;
const PROTOCOL_VERSION: u8 = 2;
fn random_token(buffer: &[u8]) -> u16 {
(buffer[1] as u16) << 8 | buffer[2] as u16
}
fn gateway_mac(buffer: &[u8]) -> MacAddress {
MacAddress::new(array_ref![buffer, 4, 8])
}
#[derive(Debug)]
pub struct Packet {
random_token: u16,
gateway_mac: Option<MacAddress>,
data: PacketData,
}
impl Packet {
pub fn data(&self) -> &PacketData {
&self.data
}
pub fn parse(buffer: &[u8], num_recv: usize) -> std::result::Result<Packet, Box<dyn stdError>> {
if buffer[0] != PROTOCOL_VERSION {
Err(Error::InvalidProtocolVersion.into())
} else {
if let Ok(id) = Identifier::try_from(buffer[3]) {
Ok(Packet {
random_token: random_token(buffer),
gateway_mac: match id {
Identifier::PullData | Identifier::PushData | Identifier::TxAck => {
Some(gateway_mac(buffer))
}
_ => None,
},
data: match id {
Identifier::PullData => PacketData::PullData,
Identifier::PushData => {
let json_str = std::str::from_utf8(&buffer[12..num_recv])?;
PacketData::PushData(serde_json::from_str(json_str)?)
}
Identifier::PullResp => {
let json_str = std::str::from_utf8(&buffer[4..num_recv])?;
PacketData::PullResp(serde_json::from_str(json_str)?)
}
Identifier::PullAck => PacketData::PullAck,
Identifier::PushAck => PacketData::PushAck,
Identifier::TxAck => PacketData::TxAck,
},
})
} else {
Err(Error::InvalidIdentifier.into())
}
}
}
pub fn serialize(self, buffer: &mut [u8]) -> std::result::Result<u64, Box<dyn stdError>> {
let mut w = Cursor::new(buffer);
w.write(&[
PROTOCOL_VERSION,
(self.random_token >> 8) as u8,
self.random_token as u8,
])?;
w.write(&[match &self.data {
PacketData::PushData(_) => Identifier::PushData,
PacketData::PushAck => Identifier::PushAck,
PacketData::PullData => Identifier::PullData,
PacketData::PullResp(_) => Identifier::PullResp,
PacketData::PullAck => Identifier::PullAck,
PacketData::TxAck => Identifier::TxAck,
} as u8])?;
if let Some(mac) = self.gateway_mac {
w.write(mac.bytes())?;
};
match self.data {
PacketData::PushData(data) => {
w.write(&serde_json::to_string(&data)?.as_bytes())?;
}
_ => (),
};
Ok(w.position())
}
}