gondola_core/packets/
telemetry_packet.rs1use crate::prelude::*;
7
8#[derive(Debug, Clone, PartialEq)]
13#[cfg_attr(feature = "pybindings", pyclass, pyo3(name="TelemetryPacket"))]
14pub struct TelemetryPacket {
15 pub header : TelemetryPacketHeader,
16 pub payload : Vec<u8>,
17 pub tof_paddles : Arc<HashMap<u8, TofPaddle>>,
18 pub trk_strips : Arc<HashMap<u32, TrackerStrip>>,
19}
20
21#[cfg(feature="pybindings")]
22#[pymethods]
23impl TelemetryPacket {
24
25 #[staticmethod]
26 #[pyo3(name="get_gcutime_unpacked")]
27 fn get_gcutime_unpacked_py(stream : Vec<u8>) -> PyResult<f64> {
29 Ok(Self::get_gcutime_unpacked(&stream)?)
30 }
31
32 #[getter]
33 #[pyo3(name="gcutime")]
34 fn get_gcutime_py(&self) -> f64 {
35 TelemetryPacketHeader::convert_telemetry_header_ts(self.header.timestamp)
36 }
37
38 #[getter]
40 #[pyo3(name="event_id")]
41 fn get_eventid_py(&self) -> PyResult<u16> {
42 let evid_opt = self.get_eventid();
43 match evid_opt {
44 Some(evid_res) => {
45 match evid_res {
46 Ok(evid) => {
47 return Ok(evid);
48 }
49 Err(err) => {
50 return Err(PyValueError::new_err(err.to_string()));
51 }
52 }
53 }
54 None => {
55 return Err(PyValueError::new_err("This packet does not seem to contain a (useful) eventid!"));
56 }
57 }
58 }
59
60 #[getter]
63 #[pyo3(name="run_id")]
64 fn get_runid_py(&self) -> PyResult<u16> {
65 let runid_opt = self.get_runid();
66 match runid_opt {
67 Some(runid_res) => {
68 match runid_res {
69 Ok(runid) => {
70 return Ok(runid);
71 }
72 Err(err) => {
73 return Err(PyValueError::new_err(err.to_string()));
74 }
75 }
76 }
77 None => {
78 return Err(PyValueError::new_err("This packet does not seem to contain a (useful) runid!"));
79 }
80 }
81 }
82
83 #[pyo3(name="get_gpstime_tracker")]
86 fn get_gpstime_tracker_py(&self) -> PyResult<u64> {
87 let gpstime_opt = self.get_gpstime_tracker();
88 match gpstime_opt {
89 Some(gpstime_res) => {
90 match gpstime_res {
91 Ok(gpstime) => {
92 return Ok(gpstime);
93 }
94 Err(err) => {
95 return Err(PyValueError::new_err(err.to_string()));
96 }
97 }
98 }
99 None => {
100 return Err(PyValueError::new_err("This packet does not seem to contain a GPS time!"));
101 }
102 }
103 }
104
105 #[pyo3(name="get_gpstime_tof")]
108 fn get_gpstime_tof_py(&self) -> PyResult<u64> {
109 let gpstime_opt = self.get_gpstime_tof();
110 match gpstime_opt {
111 Some(gpstime_res) => {
112 match gpstime_res {
113 Ok(gpstime) => {
114 return Ok(gpstime);
115 }
116 Err(err) => {
117 return Err(PyValueError::new_err(err.to_string()));
118 }
119 }
120 }
121 None => {
122 return Err(PyValueError::new_err("This packet does not seem to contain a GPS time!"));
123 }
124 }
125 }
126
127 #[getter]
130 fn payload<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
131 Ok(PyBytes::new(py, &self.payload))
132 }
133
134 #[getter]
135 fn header(&self) -> TelemetryPacketHeader {
136 self.header.clone()
139 }
140
141 #[getter]
142 fn packet_type(&self) -> TelemetryPacketType {
143 TelemetryPacketType::from(self.header.packet_type)
144 }
145
146 #[getter]
149 #[pyo3(name="is_event_packet")]
150 fn is_event_packet_py(&self) -> bool {
151 self.is_event_packet()
152 }
153
154 #[getter]
157 #[pyo3(name="is_tof_toml_packet")]
158 fn is_tof_toml_packet_py(&self) -> bool {
159 if self.header.packet_type == TelemetryPacketType::AnyTofHK {
160 let tof_packet_type = TofPacketType::from(parse_u8(&self.payload, &mut 2));
163 return tof_packet_type == TofPacketType::LiftofSettings;
164 }
165 false
166 }
167
168
169 #[pyo3(name="to_bytestream")]
170 fn to_bytestream_py(&self) -> Vec<u8> {
171 self.to_bytestream()
172 }
173
174 #[staticmethod]
175 #[pyo3(name="from_bytestream")]
176 fn from_bytestream_py(stream : Vec<u8>, pos : usize) -> Result<Self, SerializationError> {
177 let mut pos_ = pos;
178 Self::from_bytestream(&stream, &mut pos_)
179 }
180}
181
182impl TelemetryPacket {
183
184 pub fn new() -> Self {
185 Self {
186 header : TelemetryPacketHeader::new(),
187 payload : Vec::<u8>::new(),
188 tof_paddles : Arc::new(HashMap::<u8, TofPaddle>::new()),
189 trk_strips : Arc::new(HashMap::<u32,TrackerStrip>::new()),
190 }
191 }
192
193 pub fn is_event_packet(&self) -> bool {
194 if self.header.packet_type == TelemetryPacketType::NoTofDataEvent
195 || self.header.packet_type == TelemetryPacketType::NoGapsTriggerEvent
196 || self.header.packet_type == TelemetryPacketType::InterestingEvent
197 || self.header.packet_type == TelemetryPacketType::BoringEvent {
198 true
199 } else {
200 false
201 }
202 }
203
204 pub fn unpack<T>(&self) -> Result<T, SerializationError>
206 where T: TelemetryPackable + Serialization {
207 if !T::TEL_PACKET_TYPES_EVENT.contains(&self.header.packet_type) &&
208 T::TEL_PACKET_TYPE != self.header.packet_type {
209 error!("This bytestream is not for a {} packet!", self.header.packet_type);
210 return Err(SerializationError::IncorrectPacketType);
211 }
212 let unpacked : T = T::from_bytestream(&self.payload, &mut 0)?;
213 Ok(unpacked)
214 }
215
216 pub fn get_runid(&self) -> Option<Result<u16, SerializationError>> {
219 if !self.is_event_packet() {
220 return None;
221 }
222 if self.header.packet_type == TelemetryPacketType::NoTofDataEvent {
223 return None;
224 }
225 if self.payload.len() < 37 {
228 return Some(Err(SerializationError::StreamTooShort));
229 }
230 let mut pos = 41usize;
231 let runid = parse_u16(&self.payload, &mut pos);
232 return Some(Ok(runid));
233 }
234
235 pub fn get_eventid(&self) -> Option<Result<u16, SerializationError>> {
238 if !self.is_event_packet() {
239 return None;
240 }
241 if self.payload.len() < 13 + 10 + 4{
243 return Some(Err(SerializationError::StreamTooShort));
244 }
245 let mut pos = 10usize;
246 let evid = parse_u16(&self.payload, &mut pos);
247 return Some(Ok(evid));
248 }
249
250 pub fn get_gpstime_tracker(&self) -> Option<Result<u64, SerializationError>> {
253 if self.header.packet_type != TelemetryPacketType::Tracker {
254 return None;
255 }
256 let mut pos = 10usize; if self.payload.len() < 16 {
259 return Some(Err(SerializationError::StreamTooShort));
260 }
261 let lower = parse_u32(&self.payload, &mut pos);
262 let upper = parse_u16(&self.payload, &mut pos);
263 let ts = make_systime(lower, upper);
264 return Some(Ok(ts));
265 }
266
267 pub fn get_gpstime_tof(&self) -> Option<Result<u64, SerializationError>> {
270 if !self.is_event_packet() {
271 return None;
272 }
273 if self.header.packet_type == TelemetryPacketType::NoTofDataEvent {
274 return None;
275 }
276 if self.payload.len() < 41 {
290 return Some(Err(SerializationError::StreamTooShort));
291 }
292 let mut pos = 35usize;
294 let ts32 = parse_u32(&self.payload, &mut pos);
295 let ts16 = parse_u16(&self.payload, &mut pos);
296 let ts = 0x273000000000000 | (((ts16 as u64) << 32) | ts32 as u64);
297 return Some(Ok(ts));
298 }
299
300 pub fn get_gcutime_unpacked(stream : &Vec<u8>) -> Result<f64, SerializationError> {
302 if stream.len() < 7 {
306 error!("Can not get gcutime from a bytestream shorter than 7 bytes!");
307 return Err(SerializationError::StreamTooShort);
308 }
309 let mut pos = 3usize;
310 let ts = parse_u32(stream, &mut pos);
311 Ok(TelemetryPacketHeader::convert_telemetry_header_ts(ts))
312 }
313
314}
315
316impl Serialization for TelemetryPacket {
317
318 const HEAD : u16 = 0;
320 const TAIL : u16 = 0;
322 const SIZE : usize = 0;
324
325 fn from_bytestream(stream : &Vec<u8>, pos : &mut usize) -> Result<Self, SerializationError> {
326 let mut tpacket: TelemetryPacket = TelemetryPacket::new();
327 let header: TelemetryPacketHeader = TelemetryPacketHeader::from_bytestream(stream, pos)?;
328 tpacket.header = header;
329 tpacket.payload = stream[*pos..*pos + header.length as usize - TelemetryPacketHeader::SIZE].to_vec();
331 Ok(tpacket)
332 }
333
334 fn to_bytestream(&self) -> Vec<u8> {
335 let mut stream: Vec<u8> = Vec::<u8>::new();
336 let mut s_head = self.header.to_bytestream();
337 stream.append(&mut s_head);
338 stream.extend_from_slice(self.payload.as_slice());
339 stream
340 }
341}
342
343impl Default for TelemetryPacket {
344 fn default() -> Self {
345 Self::new()
346 }
347}
348
349impl fmt::Display for TelemetryPacket {
350 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
351 let mut repr: String = String::from("<TelemetryPacket:");
352 repr += &(format!("\n Header : {}",self.header));
353 repr += &(format!("\n Payload len : {}>",self.payload.len()));
354 write!(f, "{}", repr)
355 }
356}
357
358impl Frameable for TelemetryPacket {
359 const CRFRAMEOBJECT_TYPE : CRFrameObjectType = CRFrameObjectType::TelemetryPacket;
360}
361
362
363#[cfg(feature="pybindings")]
364pythonize!(TelemetryPacket);
365
366