use super::*;
use crate::tx_ack::Data;
use std::{convert::TryFrom, result::Result};
const PROTOCOL_VERSION_INDEX: usize = 0;
const IDENTIFIER_INDEX: usize = 3;
const PREFIX_LEN: usize = IDENTIFIER_INDEX + 1;
const GATEWAY_MAC_LEN: usize = 8;
fn random_token(buffer: &[u8]) -> u16 {
(buffer[1] as u16) << 8 | buffer[2] as u16
}
pub fn gateway_mac(buffer: &[u8]) -> Result<MacAddress, ParseError> {
if buffer.len() < GATEWAY_MAC_LEN {
Err(ParseError::InvalidPacketLength(
buffer.len(),
GATEWAY_MAC_LEN,
))
} else {
Ok(MacAddress::new(
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7],
))
}
}
impl Packet {
pub fn parse_uplink(buffer: &[u8]) -> 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]) -> Result<Down, ParseError> {
match Self::parse(buffer)? {
Packet::Down(down) => Ok(down),
Packet::Up(up) => Err(ParseError::UnexpectedUplink(Box::new(up))),
}
}
}
impl Packet {
pub fn parse(buffer: &[u8]) -> Result<Packet, ParseError> {
if buffer.len() < PREFIX_LEN {
return Err(ParseError::InvalidPacketLength(buffer.len(), PREFIX_LEN));
}
let protocol_version = buffer[PROTOCOL_VERSION_INDEX];
if protocol_version != PROTOCOL_VERSION {
return Err(ParseError::InvalidProtocolVersion(protocol_version));
};
let frame_identifier = buffer[IDENTIFIER_INDEX];
match Identifier::try_from(frame_identifier) {
Err(_) => Err(ParseError::InvalidIdentifier(frame_identifier)),
Ok(id) => {
let random_token = random_token(buffer);
let buffer = &buffer[PREFIX_LEN..];
Ok(match id {
Identifier::PullData => {
let gateway_mac = gateway_mac(buffer)?;
pull_data::Packet {
random_token,
gateway_mac,
}
.into()
}
Identifier::PushData => {
let gateway_mac = gateway_mac(buffer)?;
let json_str =
std::str::from_utf8(&buffer[GATEWAY_MAC_LEN..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)?;
let data = if buffer.len() > GATEWAY_MAC_LEN {
if buffer.len() == GATEWAY_MAC_LEN + 1 && buffer[GATEWAY_MAC_LEN] == 0 {
Data::default()
} else {
let json_str = std::str::from_utf8(
&buffer[GATEWAY_MAC_LEN..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.is_empty() {
0
} else if buf[buf.len() - 1] == 0 {
buf.len() - 1
} else {
buf.len()
}
}