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> {
28 Ok(Self::get_gcutime_unpacked(&stream)?)
29 }
30
31 #[pyo3(name="get_runid")]
34 fn get_runid_py(&self) -> PyResult<u16> {
35 let runid_opt = self.get_runid();
36 match runid_opt {
37 Some(runid_res) => {
38 match runid_res {
39 Ok(runid) => {
40 return Ok(runid);
41 }
42 Err(err) => {
43 return Err(PyValueError::new_err(err.to_string()));
44 }
45 }
46 }
47 None => {
48 return Err(PyValueError::new_err("This packet does not seem to contain a (useful) runid!"));
49 }
50 }
51 }
52
53 #[pyo3(name="get_gpstime_tracker")]
56 fn get_gpstime_tracker_py(&self) -> PyResult<u64> {
57 let gpstime_opt = self.get_gpstime_tracker();
58 match gpstime_opt {
59 Some(gpstime_res) => {
60 match gpstime_res {
61 Ok(gpstime) => {
62 return Ok(gpstime);
63 }
64 Err(err) => {
65 return Err(PyValueError::new_err(err.to_string()));
66 }
67 }
68 }
69 None => {
70 return Err(PyValueError::new_err("This packet does not seem to contain a GPS time!"));
71 }
72 }
73 }
74
75 #[pyo3(name="get_gpstime_tof")]
78 fn get_gpstime_tof_py(&self) -> PyResult<u64> {
79 let gpstime_opt = self.get_gpstime_tof();
80 match gpstime_opt {
81 Some(gpstime_res) => {
82 match gpstime_res {
83 Ok(gpstime) => {
84 return Ok(gpstime);
85 }
86 Err(err) => {
87 return Err(PyValueError::new_err(err.to_string()));
88 }
89 }
90 }
91 None => {
92 return Err(PyValueError::new_err("This packet does not seem to contain a GPS time!"));
93 }
94 }
95 }
96
97 #[getter]
100 fn payload<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyBytes>> {
101 Ok(PyBytes::new(py, &self.payload))
102 }
103
104 #[getter]
105 fn header(&self) -> TelemetryPacketHeader {
106 self.header.clone()
109 }
110
111 #[getter]
112 fn packet_type(&self) -> TelemetryPacketType {
113 TelemetryPacketType::from(self.header.packet_type)
114 }
115
116 #[getter]
119 #[pyo3(name="is_event_packet")]
120 fn is_event_packet_py(&self) -> bool {
121 self.is_event_packet()
122 }
123
124 #[getter]
127 #[pyo3(name="is_tof_toml_packet")]
128 fn is_tof_toml_packet_py(&self) -> bool {
129 if self.header.packet_type == TelemetryPacketType::AnyTofHK {
130 let tof_packet_type = TofPacketType::from(parse_u8(&self.payload, &mut 2));
133 return tof_packet_type == TofPacketType::LiftofSettings;
134 }
135 false
136 }
137
138
139 #[pyo3(name="to_bytestream")]
140 fn to_bytestream_py(&self) -> Vec<u8> {
141 self.to_bytestream()
142 }
143
144 #[staticmethod]
145 #[pyo3(name="from_bytestream")]
146 fn from_bytestream_py(stream : Vec<u8>, pos : usize) -> Result<Self, SerializationError> {
147 let mut pos_ = pos;
148 Self::from_bytestream(&stream, &mut pos_)
149 }
150}
151
152impl TelemetryPacket {
153
154 pub fn new() -> Self {
155 Self {
156 header : TelemetryPacketHeader::new(),
157 payload : Vec::<u8>::new(),
158 tof_paddles : Arc::new(HashMap::<u8, TofPaddle>::new()),
159 trk_strips : Arc::new(HashMap::<u32,TrackerStrip>::new()),
160 }
161 }
162
163 pub fn is_event_packet(&self) -> bool {
164 if self.header.packet_type == TelemetryPacketType::NoTofDataEvent
165 || self.header.packet_type == TelemetryPacketType::NoGapsTriggerEvent
166 || self.header.packet_type == TelemetryPacketType::InterestingEvent
167 || self.header.packet_type == TelemetryPacketType::BoringEvent {
168 true
169 } else {
170 false
171 }
172 }
173
174 pub fn unpack<T>(&self) -> Result<T, SerializationError>
176 where T: TelemetryPackable + Serialization {
177 if !T::TEL_PACKET_TYPES_EVENT.contains(&self.header.packet_type) &&
178 T::TEL_PACKET_TYPE != self.header.packet_type {
179 error!("This bytestream is not for a {} packet!", self.header.packet_type);
180 return Err(SerializationError::IncorrectPacketType);
181 }
182 let unpacked : T = T::from_bytestream(&self.payload, &mut 0)?;
183 Ok(unpacked)
184 }
185
186 pub fn get_runid(&self) -> Option<Result<u16, SerializationError>> {
189 if !self.is_event_packet() {
190 return None;
191 }
192 if self.header.packet_type == TelemetryPacketType::NoTofDataEvent {
193 return None;
194 }
195 if self.payload.len() < 37 {
198 return Some(Err(SerializationError::StreamTooShort));
199 }
200 let mut pos = 41usize;
201 let runid = parse_u16(&self.payload, &mut pos);
202 return Some(Ok(runid));
203 }
204
205 pub fn get_gpstime_tracker(&self) -> Option<Result<u64, SerializationError>> {
208 if self.header.packet_type != TelemetryPacketType::Tracker {
209 return None;
210 }
211 let mut pos = 10usize; if self.payload.len() < 16 {
214 return Some(Err(SerializationError::StreamTooShort));
215 }
216 let lower = parse_u32(&self.payload, &mut pos);
217 let upper = parse_u16(&self.payload, &mut pos);
218 let ts = make_systime(lower, upper);
219 return Some(Ok(ts));
220 }
221
222 pub fn get_gpstime_tof(&self) -> Option<Result<u64, SerializationError>> {
225 if !self.is_event_packet() {
226 return None;
227 }
228 if self.header.packet_type == TelemetryPacketType::NoTofDataEvent {
229 return None;
230 }
231 if self.payload.len() < 41 {
245 return Some(Err(SerializationError::StreamTooShort));
246 }
247 let mut pos = 35usize;
249 let ts32 = parse_u32(&self.payload, &mut pos);
250 let ts16 = parse_u16(&self.payload, &mut pos);
251 let ts = 0x273000000000000 | (((ts16 as u64) << 32) | ts32 as u64);
252 return Some(Ok(ts));
253 }
254
255 pub fn get_gcutime_unpacked(stream : &Vec<u8>) -> Result<f64, SerializationError> {
257 if stream.len() < 7 {
261 error!("Can get gcutime from a bytestream shorter than 7 bytes!");
262 return Err(SerializationError::StreamTooShort);
263 }
264 let mut pos = 3usize;
265 let ts = parse_u32(stream, &mut pos);
266 Ok(TelemetryPacketHeader::convert_telemetry_header_ts(ts))
267 }
268
269}
270
271impl Serialization for TelemetryPacket {
272
273 const HEAD : u16 = 0;
275 const TAIL : u16 = 0;
277 const SIZE : usize = 0;
279
280 fn from_bytestream(stream : &Vec<u8>, pos : &mut usize) -> Result<Self, SerializationError> {
281 let mut tpacket: TelemetryPacket = TelemetryPacket::new();
282 let header: TelemetryPacketHeader = TelemetryPacketHeader::from_bytestream(stream, pos)?;
283 tpacket.header = header;
284 tpacket.payload = stream[*pos..*pos + header.length as usize - TelemetryPacketHeader::SIZE].to_vec();
286 Ok(tpacket)
287 }
288
289 fn to_bytestream(&self) -> Vec<u8> {
290 let mut stream: Vec<u8> = Vec::<u8>::new();
291 let mut s_head = self.header.to_bytestream();
292 stream.append(&mut s_head);
293 stream.extend_from_slice(self.payload.as_slice());
294 stream
295 }
296}
297
298impl Default for TelemetryPacket {
299 fn default() -> Self {
300 Self::new()
301 }
302}
303
304impl fmt::Display for TelemetryPacket {
305 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
306 let mut repr: String = String::from("<TelemetryPacket:");
307 repr += &(format!("\n Header : {}",self.header));
308 repr += &(format!("\n Payload len : {}>",self.payload.len()));
309 write!(f, "{}", repr)
310 }
311}
312
313impl Frameable for TelemetryPacket {
314 const CRFRAMEOBJECT_TYPE : CRFrameObjectType = CRFrameObjectType::TelemetryPacket;
315}
316
317
318#[cfg(feature="pybindings")]
319pythonize!(TelemetryPacket);
320
321