semtech_udp/packet/
parser.rs1use super::*;
2use crate::tx_ack::Data;
3use std::{convert::TryFrom, result::Result};
4
5const PROTOCOL_VERSION_INDEX: usize = 0;
6const IDENTIFIER_INDEX: usize = 3;
7const PREFIX_LEN: usize = IDENTIFIER_INDEX + 1;
8const GATEWAY_MAC_LEN: usize = 8;
9
10fn random_token(buffer: &[u8]) -> u16 {
11 (buffer[1] as u16) << 8 | buffer[2] as u16
12}
13
14pub fn gateway_mac(buffer: &[u8]) -> Result<MacAddress, ParseError> {
15 if buffer.len() < GATEWAY_MAC_LEN {
16 Err(ParseError::InvalidPacketLength(
17 buffer.len(),
18 GATEWAY_MAC_LEN,
19 ))
20 } else {
21 Ok(MacAddress::new(
22 buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7],
23 ))
24 }
25}
26
27impl Packet {
28 pub fn parse_uplink(buffer: &[u8]) -> Result<Up, ParseError> {
29 match Self::parse(buffer)? {
30 Packet::Up(up) => Ok(up),
31 Packet::Down(down) => Err(ParseError::UnexpectedDownlink(down)),
32 }
33 }
34 pub fn parse_downlink(buffer: &[u8]) -> Result<Down, ParseError> {
35 match Self::parse(buffer)? {
36 Packet::Down(down) => Ok(down),
37 Packet::Up(up) => Err(ParseError::UnexpectedUplink(Box::new(up))),
38 }
39 }
40}
41
42impl Packet {
43 pub fn parse(buffer: &[u8]) -> Result<Packet, ParseError> {
44 if buffer.len() < PREFIX_LEN {
45 return Err(ParseError::InvalidPacketLength(buffer.len(), PREFIX_LEN));
46 }
47
48 let protocol_version = buffer[PROTOCOL_VERSION_INDEX];
49 if protocol_version != PROTOCOL_VERSION {
50 return Err(ParseError::InvalidProtocolVersion(protocol_version));
51 };
52
53 let frame_identifier = buffer[IDENTIFIER_INDEX];
54 match Identifier::try_from(frame_identifier) {
55 Err(_) => Err(ParseError::InvalidIdentifier(frame_identifier)),
56 Ok(id) => {
57 let random_token = random_token(buffer);
59 let buffer = &buffer[PREFIX_LEN..];
60
61 Ok(match id {
62 Identifier::PullData => {
64 let gateway_mac = gateway_mac(buffer)?;
65 pull_data::Packet {
66 random_token,
67 gateway_mac,
68 }
69 .into()
70 }
71 Identifier::PushData => {
72 let gateway_mac = gateway_mac(buffer)?;
73 let json_str =
74 std::str::from_utf8(&buffer[GATEWAY_MAC_LEN..terminate(buffer)])?;
75 let data = serde_json::from_str(json_str).map_err(|json_error| {
76 ParseError::InvalidJson {
77 identifier: id,
78 json_str: json_str.into(),
79 json_error,
80 }
81 })?;
82 push_data::Packet {
83 random_token,
84 gateway_mac,
85 data,
86 }
87 .into()
88 }
89 Identifier::TxAck => {
90 let gateway_mac = gateway_mac(buffer)?;
91 let data = if buffer.len() > GATEWAY_MAC_LEN {
92 if buffer.len() == GATEWAY_MAC_LEN + 1 && buffer[GATEWAY_MAC_LEN] == 0 {
94 Data::default()
95 } else {
96 let json_str = std::str::from_utf8(
97 &buffer[GATEWAY_MAC_LEN..terminate(buffer)],
98 )?;
99 serde_json::from_str(json_str).map_err(|json_error| {
100 ParseError::InvalidJson {
101 identifier: id,
102 json_str: json_str.into(),
103 json_error,
104 }
105 })?
106 }
107 } else {
108 Data::default()
109 };
110 tx_ack::Packet {
111 random_token,
112 gateway_mac,
113 data,
114 }
115 .into()
116 }
117 Identifier::PushAck => push_ack::Packet { random_token }.into(),
119 Identifier::PullAck => pull_ack::Packet { random_token }.into(),
120 Identifier::PullResp => {
121 let json_str = std::str::from_utf8(&buffer[..terminate(buffer)])?;
122 let data = serde_json::from_str(json_str).map_err(|json_error| {
123 ParseError::InvalidJson {
124 identifier: id,
125 json_str: json_str.into(),
126 json_error,
127 }
128 })?;
129 pull_resp::Packet { random_token, data }.into()
130 }
131 })
132 }
133 }
134 }
135}
136
137fn terminate(buf: &[u8]) -> usize {
139 if buf.is_empty() {
140 0
141 } else if buf[buf.len() - 1] == 0 {
142 buf.len() - 1
143 } else {
144 buf.len()
145 }
146}