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
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use super::BlockType;
use crate::sbx_specs;
use crate::sbx_specs::{Version, SBX_FILE_UID_LEN, SBX_FIRST_DATA_SEQ_NUM, SBX_SIGNATURE};
use std;

use super::crc::*;

use super::Error;

#[derive(Debug, Clone, PartialEq)]
pub struct Header {
    pub version: Version,
    pub crc: u16,
    pub uid: [u8; SBX_FILE_UID_LEN],
    pub seq_num: u32,
}

impl Header {
    pub fn new(version: Version, uid: [u8; SBX_FILE_UID_LEN], seq_num: u32) -> Header {
        Header {
            version,
            crc: 0,
            uid,
            seq_num,
        }
    }

    pub fn to_bytes(&self, buffer: &mut [u8]) {
        if buffer.len() != 16 {
            panic!("Incorrect buffer size");
        }

        {
            // signature
            buffer[0..3].copy_from_slice(SBX_SIGNATURE);
        }
        {
            // version byte
            buffer[3] = sbx_specs::ver_to_usize(self.version) as u8;
        }
        {
            // crc ccitt
            let crc: [u8; 2] = unsafe { std::mem::transmute::<u16, [u8; 2]>(self.crc.to_be()) };
            buffer[4..6].copy_from_slice(&crc);
        }
        {
            // file uid
            buffer[6..12].copy_from_slice(&self.uid);
        }
        {
            // seq num
            let seq_num: [u8; 4] =
                unsafe { std::mem::transmute::<u32, [u8; 4]>(self.seq_num.to_be()) };
            buffer[12..16].copy_from_slice(&seq_num);
        }
    }

    pub fn from_bytes(&mut self, buffer: &[u8]) -> Result<(), Error> {
        if buffer.len() != 16 {
            return Err(Error::IncorrectBufferSize);
        }

        match parsers::header_p(buffer) {
            Ok((_, header)) => {
                *self = header;
                Ok(())
            }
            _ => Err(Error::ParseError),
        }
    }

    pub fn calc_crc(&self) -> u16 {
        let crc = sbx_crc_ccitt(self.version, &self.uid);
        let seq_num: [u8; 4] = unsafe { std::mem::transmute::<u32, [u8; 4]>(self.seq_num.to_be()) };
        crc_ccitt_generic(crc, &seq_num)
    }

    pub fn header_type(&self) -> BlockType {
        if self.seq_num < SBX_FIRST_DATA_SEQ_NUM as u32 {
            BlockType::Meta
        } else {
            BlockType::Data
        }
    }
}

mod parsers {
    use super::Header;
    use super::Version;
    use nom::number::complete::{be_u16, be_u32};

    named!(sig_p, tag!(b"SBx"));

    named!(
        ver_p<Version>,
        alt!(
            complete!(do_parse!(_v: tag!(&[1]) >> (Version::V1)))
                | complete!(do_parse!(_v: tag!(&[2]) >> (Version::V2)))
                | complete!(do_parse!(_v: tag!(&[3]) >> (Version::V3)))
                | complete!(do_parse!(_v: tag!(&[17]) >> (Version::V17)))
                | complete!(do_parse!(_v: tag!(&[18]) >> (Version::V18)))
                | complete!(do_parse!(_v: tag!(&[19]) >> (Version::V19)))
        )
    );

    named!(uid_p, take!(6));

    named!(pub header_p <Header>,
           do_parse!(
               _sig : sig_p >>
                   version : ver_p >>
                   crc     : be_u16 >>
                   uid_raw : uid_p >>
                   seq_num : be_u32 >>
                   ({
                       let mut uid : [u8; 6] = [0; 6];
                       uid.copy_from_slice(uid_raw);
                       Header {
                           version,
                           crc,
                           uid,
                           seq_num
                       }
                   })
           )
    );
}