Skip to main content

gondola_core/packets/
telemetry_packet_header.rs

1//! Re-implementation of the telemetry header which is attached 
2//! to each telemetry packet.
3//! Re-implemented from bfsw
4// The following file is part of gaps-online-software and published 
5// under the GPLv3 license
6
7use crate::prelude::*;
8
9/// This gets attached to each telemetry packet 
10/// "in front" of it, conveying meta information
11#[derive(Debug, Copy, Clone, PartialEq)]
12#[cfg_attr(feature = "pybindings", pyclass, pyo3(name="TelemetryPacketHeader"))]
13pub struct TelemetryPacketHeader {
14  /// A constant identifying the start of a packet
15  pub sync      : u16,
16  /// A unique identifier describing the following 
17  /// packet's content
18  pub packet_type     : TelemetryPacketType,
19  /// The timestap from the gcu (flight computer) (NOT GPS!)
20  /// when this packet header has been created
21  pub timestamp : u32,
22  /// Counting packets send out by the gcu (flight computer), 
23  /// rolling over every u16::MAX
24  pub counter   : u16,
25  /// The length in bytes of the following packet
26  pub length    : u16,
27  /// A checksum to verify the integrity of the 
28  /// following packet
29  /// FIXME - currently the algorithm used is 
30  ///         unknown
31  pub checksum  : u16
32}
33
34impl TelemetryPacketHeader {
35
36  pub fn new() -> Self {
37    Self {
38      sync      : 0,
39      packet_type     : TelemetryPacketType::Unknown,
40      timestamp : 0,
41      counter   : 0,
42      length    : 0,
43      checksum  : 0,
44    }
45  }
46
47  /// A re-implementation of make_packet_stub
48  pub fn forge(packet_type : TelemetryPacketType) -> Self {
49    let mut header = Self::new();
50    header.sync    = 0x90EB;
51    header.packet_type   = packet_type;
52    header
53  }
54
55  /// To save space, the timestamp in the telemetry header is 
56  /// shortened to 32bit. Re-hydrate it to be a proper 64bit
57  /// timestamp in unix time
58  pub fn convert_telemetry_header_ts(timestamp : u32) -> f64 {
59    (timestamp as f64) * 0.064 + 1631030675.0
60  }
61  
62  /// Blatent copy of bfsw's timestamp_to_double
63  pub fn get_gcutime(&self) -> f64 {
64    //(self.timestamp as f64) * 0.064 + 1631030675.0
65    Self::convert_telemetry_header_ts(self.timestamp)
66  }
67}
68
69// methods which should be available through python, but 
70// just need to be wrapped
71#[cfg(feature="pybindings")]
72#[pymethods]
73impl TelemetryPacketHeader {
74 
75  /// To save space, the timestamp in the telemetry header is 
76  /// shortened to 32bit. Re-hydrate it to be a proper 64bit
77  /// timestamp in unix time
78  #[staticmethod]
79  #[pyo3(name="convert_telemetry_header_ts")]
80  fn convert_telemetry_header_ts_py(timestamp : u32) -> f64 {
81    Self::convert_telemetry_header_ts(timestamp)
82  }
83
84  #[getter]
85  fn gcutime(&self) -> f64 {
86    self.get_gcutime()
87  }
88
89  #[getter]
90  fn get_packet_type(&self) -> TelemetryPacketType {
91    self.packet_type
92  }
93
94  #[getter]
95  fn get_timestamp(&self) -> u32 {
96    self.timestamp 
97  }
98
99  #[getter]
100  fn get_counter(&self) -> u16 {
101    self.counter 
102  }
103
104  #[getter]
105  fn get_length(&self) -> u16 {
106    self.length
107  } 
108
109  #[getter] 
110  fn get_checksum(&self) -> u16 {
111    self.checksum 
112  }
113}
114
115// Trait implementations
116
117impl Serialization for TelemetryPacketHeader {
118  
119  const HEAD : u16 = 0x90eb;
120  const TAIL : u16 = 0x0000; // there is no tail for telemetry packets
121  const SIZE : usize = 13; 
122
123  fn from_bytestream(stream : &Vec<u8>,
124                     pos    : &mut usize)
125    -> Result<Self, SerializationError> {
126    if stream.len() < *pos + Self::SIZE {
127      return Err(SerializationError::StreamTooShort);
128    }
129    if parse_u16(stream, pos) != 0x90eb {
130      error!("The given position {} does not point to a valid header signature of {}", pos, 0x90eb);
131      return Err(SerializationError::HeadInvalid {});
132    }
133    let mut thead   = TelemetryPacketHeader::new();
134    thead.sync      = 0x90eb;
135    thead.packet_type     = TelemetryPacketType::from(parse_u8 (stream, pos));
136    thead.timestamp = parse_u32(stream, pos);
137    thead.counter   = parse_u16(stream, pos);
138    thead.length    = parse_u16(stream, pos);
139    thead.checksum  = parse_u16(stream, pos);
140    Ok(thead)
141  }
142  
143  fn to_bytestream(&self) -> Vec<u8> {
144    let mut stream = Vec::<u8>::new();
145    //let head : u16 = 0x90eb;
146    // "SYNC" is the header signature
147    stream.extend_from_slice(&self.sync.to_le_bytes());
148    stream.extend_from_slice(&(self.packet_type as u8).to_le_bytes());
149    stream.extend_from_slice(&self.timestamp.to_le_bytes());
150    stream.extend_from_slice(&self.counter.to_le_bytes());
151    stream.extend_from_slice(&self.length.to_le_bytes());
152    stream.extend_from_slice(&self.checksum.to_le_bytes());
153    stream
154  }
155}
156
157impl fmt::Display for TelemetryPacketHeader {
158  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159    let mut repr = String::from("<TelemetryPacketHeader:");
160    repr += &(format!("\n  Header      : {}",self.sync));
161    repr += &(format!("\n  Packet Type : {}",self.packet_type));
162    repr += &(format!("\n  Timestamp   : {}",self.timestamp));
163    repr += &(format!("\n  Counter     : {}",self.counter));
164    repr += &(format!("\n  Length      : {}",self.length));
165    repr += &(format!("\n  Checksum    : {}>",self.checksum));
166    write!(f, "{}", repr)
167  }
168}
169
170#[cfg(feature="random")]
171impl FromRandom for TelemetryPacketHeader {
172
173  fn from_random() -> Self {
174    let mut h     = Self::new();
175    let mut rng   = rand::rng(); 
176    h.sync        = 0x90eb;
177    h.packet_type = TelemetryPacketType::from_random();
178    h.timestamp   = rng.random::<u32>();
179    h.counter     = rng.random::<u16>();
180    h.length      = rng.random::<u16>();
181    h.checksum    = rng.random::<u16>();
182    h
183  }
184}
185
186#[cfg(feature="pybindings")]
187pythonize!(TelemetryPacketHeader);
188
189#[test]
190#[cfg(feature="random")]
191fn serialize_deserialize_telemetrypacketheader() {
192  for _ in 0..10 {
193    let h = TelemetryPacketHeader::from_random();
194    let stream = h.to_bytestream();
195    let test   = TelemetryPacketHeader::from_bytestream(&stream, &mut 0);
196    assert_eq!(h,test.unwrap());
197  }
198}
199
200