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
//! 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 [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(),
        }
    }
}