Implement more efficient scheme for ack packet coding

This commit is contained in:
xenia 2020-03-14 14:42:03 -04:00
parent ee3db94155
commit 815471d6d1
2 changed files with 80 additions and 13 deletions

View File

@ -1,5 +1,5 @@
use super::seg::{SegData, SegIdx};
pub use super::seg::{DOWN_HEADER_SIZE, MAX_TOTAL_PACKET_SIZE, UP_HEADER_SIZE};
pub use super::seg::{DOWN_HEADER_SIZE, MAX_TOTAL_PACKET_SIZE, UP_HEADER_SIZE, MAX_SEG_SIZE};
use byteorder::ByteOrder;
#[derive(Clone)]
@ -78,29 +78,97 @@ impl SerDes for UpMsg {
impl SerDes for DownMsg {
fn des(buf: &[u8]) -> Result<Self, DesError> {
let mut idxs = vec![];
for (i, b) in buf.iter().cloned().enumerate() {
for j in 0..8 {
if b & (1 << j) != 0 {
idxs.push((i * 8 + j) as SegIdx);
if buf.len() < DOWN_HEADER_SIZE {
Err(DesError)
} else {
let first_unacked = BO::read_u32(&buf[0..4]);
let mut idxs = vec![];
for i in 0..first_unacked {
idxs.push(i);
}
for (i, b) in buf.iter().skip(4).cloned().enumerate() {
for j in 0..8 {
if b & (1 << j) != 0 {
idxs.push((i * 8 + j + (first_unacked as usize) + 1) as SegIdx);
}
}
}
Ok(DownMsg::Ack { idxs })
}
Ok(DownMsg::Ack { idxs })
}
fn ser_to(&self, buf: &mut [u8]) -> usize {
match self {
DownMsg::Ack { idxs } => {
let mut first_unacked: u32 = 0;
for idx in idxs.iter().cloned() {
if idx == first_unacked {
first_unacked += 1;
} else {
break;
}
}
BO::write_u32(&mut buf[0..4], first_unacked);
let mut max_i = 0;
for seg_idx in idxs.iter().cloned() {
let i = seg_idx as usize / 8;
let j = (seg_idx % 8) as u8;
buf[i] |= 1 << j;
if seg_idx < first_unacked {
continue;
}
let seg_idx_delta: usize = (seg_idx - first_unacked - 1) as usize;
let i = seg_idx_delta / 8;
let j = (seg_idx_delta % 8) as u8;
buf[i + 4] |= 1 << j;
max_i = std::cmp::max(i, max_i);
}
max_i + 1
max_i + 4 + 1
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn serdes_downmsg(init_idxs: &Vec<SegIdx>, expected_hdr: u32) {
let mut buf = [0u8; MAX_SEG_SIZE];
DownMsg::Ack{idxs: init_idxs.clone()}.ser_to(&mut buf);
assert_eq!(BO::read_u32(&buf[0..4]), expected_hdr);
let des = DownMsg::des(&buf).unwrap();
match des {
DownMsg::Ack { idxs } => {
assert_eq!(*init_idxs, idxs);
}
}
}
#[test]
fn test_serdes_downmsg() {
let init_idxs: Vec<SegIdx> = vec![0, 1, 2, 3];
serdes_downmsg(&init_idxs, 4);
}
#[test]
fn test_serdes_downmsg_empty() {
let init_idxs: Vec<SegIdx> = vec![];
serdes_downmsg(&init_idxs, 0);
}
#[test]
fn test_serdes_downmsg_missing0() {
let init_idxs: Vec<SegIdx> = vec![1, 2, 4];
serdes_downmsg(&init_idxs, 0);
}
#[test]
fn test_serdes_downmsg_missing1() {
let init_idxs: Vec<SegIdx> = vec![0, 2, 7];
serdes_downmsg(&init_idxs, 1);
}
#[test]
fn test_serdes_downmsg_missing2() {
let init_idxs: Vec<SegIdx> = vec![0, 1, 2, 3, 4, 7, 8, 10];
serdes_downmsg(&init_idxs, 5);
}
}

View File

@ -1,9 +1,8 @@
/// Per the assignment spec, `1472` is the maximum size packet we're allowed to send.
pub const MAX_TOTAL_PACKET_SIZE: usize = 1472;
// TODO: change these based off the decoders
pub const UP_HEADER_SIZE: usize = 4;
pub const DOWN_HEADER_SIZE: usize = 1;
pub const DOWN_HEADER_SIZE: usize = 4;
/// This is the maximum amount of segment data we can fit into a packet.
pub const MAX_SEG_SIZE: usize = MAX_TOTAL_PACKET_SIZE - UP_HEADER_SIZE;