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
131
132
133
134
use super::*;
use crate::tx_ack::Data;
use std::convert::TryFrom;
const PROTOCOL_VERSION_INDEX: usize = 0;
const IDENTIFIER_INDEX: usize = 3;
const PACKET_PAYLOAD_START: usize = 8;
fn random_token(buffer: &[u8]) -> u16 {
(buffer[1] as u16) << 8 | buffer[2] as u16
}
pub fn gateway_mac(buffer: &[u8]) -> MacAddress {
MacAddress::new(
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7],
)
}
pub trait Parser {
fn parse(buffer: &[u8]) -> std::result::Result<Packet, ParseError>;
}
impl Packet {
pub fn parse_uplink(buffer: &[u8]) -> std::result::Result<Up, ParseError> {
match Self::parse(buffer)? {
Packet::Up(up) => Ok(up),
Packet::Down(down) => Err(ParseError::UnexpectedDownlink(down)),
}
}
pub fn parse_downlink(buffer: &[u8]) -> std::result::Result<Down, ParseError> {
match Self::parse(buffer)? {
Packet::Down(down) => Ok(down),
Packet::Up(up) => Err(ParseError::UnexpectedUplink(up)),
}
}
}
impl Parser for Packet {
fn parse(buffer: &[u8]) -> std::result::Result<Packet, ParseError> {
if buffer[PROTOCOL_VERSION_INDEX] != PROTOCOL_VERSION {
return Err(ParseError::InvalidProtocolVersion);
};
match Identifier::try_from(buffer[IDENTIFIER_INDEX]) {
Err(_) => Err(ParseError::InvalidIdentifier),
Ok(id) => {
let random_token = random_token(buffer);
let buffer = &buffer[4..];
Ok(match id {
Identifier::PullData => {
let gateway_mac = gateway_mac(&buffer[..PACKET_PAYLOAD_START]);
pull_data::Packet {
random_token,
gateway_mac,
}
.into()
}
Identifier::PushData => {
let gateway_mac = gateway_mac(&buffer[..PACKET_PAYLOAD_START]);
let json_str =
std::str::from_utf8(&buffer[PACKET_PAYLOAD_START..terminate(buffer)])?;
let data = serde_json::from_str(json_str).map_err(|json_error| {
ParseError::InvalidJson {
identifier: id,
json_str: json_str.into(),
json_error,
}
})?;
push_data::Packet {
random_token,
gateway_mac,
data,
}
.into()
}
Identifier::TxAck => {
let gateway_mac = gateway_mac(&buffer[..PACKET_PAYLOAD_START]);
let data = if buffer.len() > PACKET_PAYLOAD_START {
if buffer.len() == PACKET_PAYLOAD_START + 1
&& buffer[PACKET_PAYLOAD_START] == 0
{
Data::default()
} else {
let json_str = std::str::from_utf8(
&buffer[PACKET_PAYLOAD_START..terminate(buffer)],
)?;
serde_json::from_str(json_str).map_err(|json_error| {
ParseError::InvalidJson {
identifier: id,
json_str: json_str.into(),
json_error,
}
})?
}
} else {
Data::default()
};
tx_ack::Packet {
random_token,
gateway_mac,
data,
}
.into()
}
Identifier::PushAck => push_ack::Packet { random_token }.into(),
Identifier::PullAck => pull_ack::Packet { random_token }.into(),
Identifier::PullResp => {
let json_str = std::str::from_utf8(&buffer[..terminate(buffer)])?;
let data = serde_json::from_str(json_str).map_err(|json_error| {
ParseError::InvalidJson {
identifier: id,
json_str: json_str.into(),
json_error,
}
})?;
pull_resp::Packet { random_token, data }.into()
}
})
}
}
}
}
fn terminate(buf: &[u8]) -> usize {
if buf[buf.len() - 1] == 0 {
buf.len() - 1
} else {
buf.len()
}
}