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
128
129
130
131
//! Encode/Decode for ASTERIX protocol using the deku library
//!
//! # Creating an Asterix packet
//! There are currently two ways of creating an AsterixPacket:
//!
//! ## From `&[u8]`
//! ```
//! use deku::prelude::*;
//! use asterix::*;
//! use asterix::data_item::*;
//!
//! let bytes = &[0x22, 0x00, 0x0b, 0xf0, 0x19, 0x0d, 0x02, 0x35, 0x6d, 0xfa, 0x60];
//! let (_, mut packet) = AsterixPacket::from_bytes((bytes, 0)).unwrap();
//! ```
//!
//! ## Packet Creation
//! Create an CAT34 Asterix packet.
//!
//! ```rust
//! use deku::prelude::*;
//! use asterix::*;
//! use asterix::data_item::*;
//! use asterix::types::*;
//!
//! let mut thirty_eight = Cat34::default();
//! thirty_eight.data_source_identifier = Some(DataSourceIdentifier { sac: 25, sic: 13 });
//! thirty_eight.message_type = Some(MessageType {
//!     t: MTYPE::SectorCrossing,
//! });
//! thirty_eight.time_of_day = Some(TimeOfDay { time: 27355.953 });
//! thirty_eight.sector_number = Some(SectorNumber { num: 135 });
//!
//! let mut packet = AsterixPacket::default();
//! packet.category = 34;
//! packet.messages = vec![asterix::AsterixMessage::Cat34(thirty_eight)];
//! ```
//!
//! # Encoding Packets
//! ```rust
//! use deku::prelude::*;
//! use asterix::*;
//! use asterix::data_item::*;
//!
//! // Create / Mutate a packet
//! let mut packet = AsterixPacket::default();
//!
//! // finalize(): Updates fspec for all packet messages, as well as setting the length as per
//! //             the protocol.
//! packet.finalize().unwrap();
//!
//! // serialize
//! packet.to_bytes().unwrap();
//! ```

use deku::bitvec::{BitVec, Msb0};
use deku::prelude::*;

pub mod types;

mod custom_read_write;
mod modifier;

mod fourty_eight;
pub use fourty_eight::Cat48;

mod thirty_four;
pub use thirty_four::Cat34;

pub mod data_item;
mod fspec;

/// Size of category + length in bytes
const ASTERIX_HEADER_SIZE: u16 = 3;

const FSPEC_IDENT: u8 = 0b0000_0001;

#[derive(Debug, Default, PartialEq, DekuRead, DekuWrite)]
#[deku(endian = "big")]
pub struct AsterixPacket {
    /// Category of all `messages`
    pub category: u8,
    /// Total length of `AsterixPacket`
    #[deku(update = "Self::update_len(&mut self.messages)")]
    pub length: u16,
    /// Asterix Messages
    #[deku(bytes_read = "length - ASTERIX_HEADER_SIZE", ctx = "*category")]
    pub messages: Vec<AsterixMessage>,
}

impl AsterixPacket {
    /// Update fspec and len
    pub fn finalize(&mut self) -> Result<(), DekuError> {
        for message in &mut self.messages {
            message.update_fspec();
        }
        self.update()
    }

    /// Read all messages and return byte len
    fn update_len(messages: &mut Vec<AsterixMessage>) -> u16 {
        let mut len: u16 = 0;
        for message in messages.iter_mut() {
            let mut bits: BitVec<u8, Msb0> = BitVec::new();
            message
                .write(&mut bits, (deku::ctx::Endian::Big, 0))
                .unwrap();
            len += (bits.len() / 8) as u16 + ASTERIX_HEADER_SIZE
        }
        len
    }
}

#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
#[deku(id = "category", ctx = "_: deku::ctx::Endian, category: u8")]
/// Union of Asterix categories
pub enum AsterixMessage {
    #[deku(id = "34")]
    Cat34(Cat34),
    #[deku(id = "48")]
    Cat48(Cat48),
}

impl AsterixMessage {
    /// Call `update_fpsec` of internal type
    pub fn update_fspec(&mut self) {
        match self {
            Self::Cat34(c) => c.update_fspec(),
            Self::Cat48(c) => c.update_fspec(),
        }
    }
}