Skip to content

Commit

Permalink
Created Packet struct to more easily manage packet parsing.
Browse files Browse the repository at this point in the history
  • Loading branch information
grebneerg committed Nov 17, 2018
1 parent 501eff0 commit 18466c9
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 79 deletions.
61 changes: 61 additions & 0 deletions src/bytes.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,67 @@
use byteorder::{ByteOrder, NetworkEndian};
use std::collections::VecDeque;

/// [Packet] represents a data packet and allows for extracting components in order.
pub struct Packet(VecDeque<u8>);

impl Packet {
/// Creates a [Packet] from the given [Vec<u8>].
pub fn from_vec(vec: Vec<u8>) -> Self {
Packet(VecDeque::from(vec))
}

/// Returns the number of bytes left in the [Packet].
pub fn len(&self) -> usize {
self.0.len()
}

/// Returns an [Option] containing the next byte if there is one or [None] otherwise.
pub fn next_u8(&mut self) -> Option<u8> {
self.0.pop_front()
}

/// Parses and returns the next two bytes as a [u16] if they are present, otherwaise returns [None].
pub fn next_u16(&mut self) -> Option<u16> {
if self.0.len() < 2 {
None
} else {
Some(NetworkEndian::read_u16(&[
self.next_u8().unwrap(),
self.next_u8().unwrap(),
]))
}
}

/// Parses and returns the next four bytes as a [f32] if they are present, otherwaise returns [None].
pub fn next_f32(&mut self) -> Option<f32> {
if self.0.len() < 4 {
None
} else {
Some(NetworkEndian::read_f32(&[
self.next_u8().unwrap(),
self.next_u8().unwrap(),
self.next_u8().unwrap(),
self.next_u8().unwrap(),
]))
}
}

/// Creates a string from the next [size] bytes of the packet.
///
/// Returns an Option containing the string or None if the [Packet] is not long enough.
pub fn extract_string(&mut self, size: usize) -> Option<String> {
if self.len() < 2 {
None
} else {
let mut vec = Vec::new();
for i in 0..size {
vec.push(self.next_u8().unwrap());
}
Some(String::from_utf8_lossy(vec.as_ref()).to_string())
}
}
}

/// Extracts a string from a [VecDeque<u8>] where the first two bytes are a [u16] representing the length of the string.
/// That many bytes will be used to construct the string, being removed from the [VecDeque].
///
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ mod messages;
mod states;

use joystick::Joystick;
use messages::{Status, Trace};
use states::{Alliance, RobotMode};

const TIMEZONE: &'static str = "UTC";
Expand Down
129 changes: 51 additions & 78 deletions src/messages.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use std::collections::VecDeque;
use std::convert::From;

use byteorder::{ByteOrder, NetworkEndian};

use bytes::extract_string_u16_size;
use states::{Alliance, RobotMode};
use bytes::Packet;
use states::RobotMode;

pub(crate) struct Trace {
robot_code: bool,
Expand Down Expand Up @@ -56,27 +53,24 @@ struct RioUdpPacket {
trace: Trace,
battery_voltage: f32,
request_date: bool,
tags: VecDeque<u8>, // TODO: parse tags from this vec
tags: Packet, // TODO: parse tags from this Packet
}

impl RioUdpPacket {
fn from_bytes(bytes: Vec<u8>) -> Option<Self> {
if bytes.len() > 8 {
None
} else {
let mut bytes = VecDeque::from(bytes);
let mut packet = Packet::from_vec(bytes);
Some(RioUdpPacket {
sequence_num: NetworkEndian::read_u16(&[
bytes.pop_front().unwrap(),
bytes.pop_front().unwrap(),
]),
comm_version: bytes.pop_front().unwrap(),
status: bytes.pop_front().unwrap().into(),
trace: bytes.pop_front().unwrap().into(),
battery_voltage: f32::from(bytes.pop_front().unwrap())
+ f32::from(bytes.pop_front().unwrap()) / 256.0,
request_date: bytes.pop_front().unwrap() == 0x01,
tags: bytes,
sequence_num: packet.next_u16().unwrap(),
comm_version: packet.next_u8().unwrap(),
status: packet.next_u8().unwrap().into(),
trace: packet.next_u8().unwrap().into(),
battery_voltage: f32::from(packet.next_u8().unwrap())
+ f32::from(packet.next_u8().unwrap()) / 256.0,
request_date: packet.next_u8().unwrap() == 0x01,
tags: packet,
})
}
}
Expand Down Expand Up @@ -136,88 +130,67 @@ impl RioTcpPacket {
None
} else {
use self::RioTcpPacket::*;
let mut bytes = VecDeque::from(bytes);
match bytes.pop_front().unwrap() {
0x00 => Some(RadioEvent(
String::from_utf8_lossy(Vec::from(bytes).as_ref()).to_string(),
)),
0x04 => if bytes.len() != 4 {
let mut packet = Packet::from_vec(bytes);
match packet.next_u8().unwrap() {
0x00 => Some(RadioEvent({
let size = packet.len();
packet.extract_string(size).unwrap()
})),
0x04 => if packet.len() != 4 {
None
} else {
Some(DisableFaults {
comms: NetworkEndian::read_u16(&[
bytes.pop_front().unwrap(),
bytes.pop_front().unwrap(),
]),
twelve_v: NetworkEndian::read_u16(&[
bytes.pop_front().unwrap(),
bytes.pop_front().unwrap(),
]),
comms: packet.next_u16().unwrap(),
twelve_v: packet.next_u16().unwrap(),
})
},
0x05 => if bytes.len() != 6 {
0x05 => if packet.len() != 6 {
None
} else {
Some(RailFaults {
six_v: NetworkEndian::read_u16(&[
bytes.pop_front().unwrap(),
bytes.pop_front().unwrap(),
]),
five_v: NetworkEndian::read_u16(&[
bytes.pop_front().unwrap(),
bytes.pop_front().unwrap(),
]),
three_point_three_v: NetworkEndian::read_u16(&[
bytes.pop_front().unwrap(),
bytes.pop_front().unwrap(),
]),
six_v: packet.next_u16().unwrap(),
five_v: packet.next_u16().unwrap(),
three_point_three_v: packet.next_u16().unwrap(),
})
},
0x0a => if bytes.len() < 5 {
0x0a => if packet.len() < 5 {
None
} else {
None // TODO
},
0x0b => if bytes.len() < 16 {
0x0b => if packet.len() < 16 {
None
} else {
Some(ErrorMessage {
timestamp: NetworkEndian::read_f32(&[
bytes.pop_front().unwrap(),
bytes.pop_front().unwrap(),
bytes.pop_front().unwrap(),
bytes.pop_front().unwrap(),
]),
sequence_number: NetworkEndian::read_u16(&[
bytes.pop_front().unwrap(),
bytes.pop_front().unwrap(),
]),
print_msg: bytes.pop_front().unwrap() == 0x01,
error_code: NetworkEndian::read_u16(&[
bytes.pop_front().unwrap(),
bytes.pop_front().unwrap(),
]),
is_error: bytes.pop_front().unwrap() != 0,
details: extract_string_u16_size(&mut bytes).unwrap(),
location: extract_string_u16_size(&mut bytes).unwrap(),
call_stack: extract_string_u16_size(&mut bytes).unwrap(),
timestamp: packet.next_f32().unwrap(),
sequence_number: packet.next_u16().unwrap(),
print_msg: packet.next_u8().unwrap() == 0x01,
error_code: packet.next_u16().unwrap(),
is_error: packet.next_u8().unwrap() != 0,
details: {
let size = packet.next_u16().unwrap() as usize;
packet.extract_string(size).unwrap()
},
location: {
let size = packet.next_u16().unwrap() as usize;
packet.extract_string(size).unwrap()
},
call_stack: {
let size = packet.next_u16().unwrap() as usize;
packet.extract_string(size).unwrap()
},
})
},
0x0c => if bytes.len() < 6 {
0x0c => if packet.len() < 6 {
None
} else {
Some(StandardOutput {
timestamp: NetworkEndian::read_f32(&[
bytes.pop_front().unwrap(),
bytes.pop_front().unwrap(),
bytes.pop_front().unwrap(),
bytes.pop_front().unwrap(),
]),
sequence_number: NetworkEndian::read_u16(&[
bytes.pop_front().unwrap(),
bytes.pop_front().unwrap(),
]),
message: String::from_utf8_lossy(Vec::from(bytes).as_ref()).to_string(),
timestamp: packet.next_f32().unwrap(),
sequence_number: packet.next_u16().unwrap(),
message: {
let size = packet.len();
packet.extract_string(size).unwrap()
},
})
},
_ => None,
Expand Down

0 comments on commit 18466c9

Please sign in to comment.