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
#![allow(clippy::identity_op)]

use std::mem;

use modular_bitfield_msb::prelude::*;
use zerocopy::{AsBytes, FromBytes, Unaligned};

#[bitfield(bytes = 5)]
#[derive(Debug, Default, Clone, FromBytes, AsBytes, Unaligned)]
#[repr(C)]
pub struct PrimaryHeader {
    pub version_number: B2,
    pub bypass_flag: bool,
    pub control_command_flag: bool,
    #[skip]
    __: B2,
    pub scid: B10,
    pub vcid: B6,
    pub frame_length_raw: B10,
    pub frame_sequence_number: B8,
}

impl PrimaryHeader {
    pub const SIZE: usize = mem::size_of::<Self>();

    pub fn frame_length_in_bytes(&self) -> usize {
        self.frame_length_raw() as usize + 1
    }

    pub fn set_frame_length_in_bytes(&mut self, frame_length_in_bytes: usize) {
        self.set_frame_length_raw((frame_length_in_bytes - 1) as u16)
    }
}

pub const FECF_CRC: crc::Crc<u16> = crc::Crc::<u16>::new(&crc::CRC_16_IBM_3740);

pub const MAX_SIZE: usize = 1024;

#[cfg(test)]
mod tests {
    use zerocopy::LayoutVerified;

    use super::*;

    const CASE1: [u8; 5] = [0b01110010, 0b00011100, 0b10100110, 0b01100011, 0xDEu8];

    #[test]
    fn test_read() {
        let ph = LayoutVerified::<_, PrimaryHeader>::new(CASE1.as_slice()).unwrap();
        assert_eq!(1, ph.version_number());
        assert!(ph.bypass_flag());
        assert!(ph.control_command_flag());
        assert_eq!(0b1000011100, ph.scid());
        assert_eq!(0b101001, ph.vcid());
        assert_eq!(0b1001100011, ph.frame_length_raw());
        assert_eq!(0xDE, ph.frame_sequence_number());
    }

    #[test]
    fn test_write() {
        let mut bytes = [0u8; 5];
        let mut ph = LayoutVerified::<_, PrimaryHeader>::new(bytes.as_mut_slice()).unwrap();
        ph.set_version_number(1);
        ph.set_bypass_flag(true);
        ph.set_control_command_flag(true);
        ph.set_scid(0b1000011100);
        ph.set_vcid(0b101001);
        ph.set_frame_length_raw(0b1001100011);
        ph.set_frame_sequence_number(0xDE);
        assert_eq!(CASE1, bytes);
    }
}