1use anyhow::{anyhow, Result};
3use csv::StringRecord;
4use itertools::Itertools;
5use std::str::FromStr;
6
7pub trait Csv {
9 fn csv(&self) -> Vec<StringRecord>;
10}
11
12impl Csv for StringRecord {
13 fn csv(&self) -> Vec<StringRecord> {
14 vec![self.clone()]
15 }
16}
17
18#[derive(Debug, Clone)]
20pub struct DataPacket {
21 pub host_timestamp: f64,
23 pub emotibit_timestamp: f64,
25 pub packet_id: u32,
27 pub data_points: u8,
29 pub version: u8,
31 pub reliability: u8,
33 pub data_type: DataType,
35}
36
37impl Csv for DataPacket {
38 fn csv(&self) -> Vec<StringRecord> {
39 let mut vec = Vec::new();
40 let payload = Self::parse_data_type(&self.data_type, self.data_type.payload());
41 for p in payload {
42 vec.push(StringRecord::from(vec![
43 self.host_timestamp.to_string(),
44 self.emotibit_timestamp.to_string(),
45 self.packet_id.to_string(),
46 self.data_points.to_string(),
47 self.data_type.as_str().to_owned(),
48 self.version.to_string(),
49 self.reliability.to_string(),
50 p.to_string(),
51 ]));
52 }
53 vec
54 }
55}
56
57impl DataPacket {
58 fn parse_data_type(data_type: &DataType, payload: Vec<String>) -> Vec<String> {
59 use DataType::*;
60 match data_type {
61 TxLcLm(_) | TxTlLc(_) => vec![format!(
62 "{},{}",
63 payload.get(0).unwrap(),
64 payload.get(1).unwrap()
65 )],
66 _ => payload,
67 }
68 }
69 pub fn inject_host_timestamp(self, map: &TimeSyncMap) -> Self {
71 let timestamp = map.tl0
72 + (map.tl1 - map.tl0) * (self.emotibit_timestamp - map.te0) / (map.te1 - map.te0);
73 DataPacket {
74 host_timestamp: timestamp,
75 emotibit_timestamp: self.emotibit_timestamp,
76 packet_id: self.packet_id,
77 data_points: self.data_points,
78 version: self.version,
79 reliability: self.reliability,
80 data_type: self.data_type,
81 }
82 }
83}
84
85impl TryFrom<&StringRecord> for DataPacket {
86 type Error = anyhow::Error;
87 fn try_from(r: &StringRecord) -> Result<Self, Self::Error> {
88 if let (
89 Some(timestamp),
90 Some(packet_id),
91 Some(data_points),
92 Some(data_type),
93 Some(version),
94 Some(reliability),
95 ) = (r.get(0), r.get(1), r.get(2), r.get(3), r.get(4), r.get(5))
96 {
97 Ok(DataPacket {
98 host_timestamp: f64::NAN,
99 emotibit_timestamp: timestamp.parse()?,
100 packet_id: packet_id.parse()?,
101 data_points: data_points.parse()?,
102 version: version.parse()?,
103 reliability: reliability.parse()?,
104 data_type: get_data_type(r, data_type)?,
105 })
106 } else {
107 Err(anyhow!("Missing Column, record: {:?}", r))
108 }
109 }
110}
111
112impl TryFrom<&str> for DataPacket {
113 type Error = anyhow::Error;
114 fn try_from(str: &str) -> Result<Self, Self::Error> {
115 let r: Vec<&str> = str.split(',').collect();
116 let r = csv::ByteRecord::from(r);
117 let r = &StringRecord::from_byte_record(r)?;
118 r.try_into()
119 }
120}
121
122#[test]
123fn string_to_data() {
124 let input = "1126349,49106,10,PI,1,100,156593,156471,156372,156300,156205,156136,156130,156103,156051,156103";
125 let packet: DataPacket = input.try_into().unwrap();
126 assert_eq!(packet.packet_id, 49106);
127 assert_eq!(packet.data_points, 10);
128}
129
130#[derive(Debug, Clone, PartialEq)]
132pub enum DataType {
133 EA(Vec<f32>),
135 EL(Vec<f32>),
137 ER(Vec<f32>),
139 PI(Vec<u32>),
141 PR(Vec<u32>),
143 PG(Vec<u32>),
145 T0(Vec<f32>),
147 T1(Vec<f32>),
149 TH(Vec<f32>),
151 AX(Vec<f32>),
153 AY(Vec<f32>),
155 AZ(Vec<f32>),
157 GX(Vec<f32>),
159 GY(Vec<f32>),
161 GZ(Vec<f32>),
163 MX(Vec<i32>),
165 MY(Vec<i32>),
167 MZ(Vec<i32>),
169 BV(Vec<f32>),
171 BATLV(Vec<u32>),
173 AK(Vec<String>),
174 RD(Vec<String>),
176 TL(String),
177 TX(Vec<String>),
178 TxTlLc((String, f32)),
179 TxLcLm(Vec<f32>),
180 EM(Vec<String>),
181 HR(Vec<i32>),
183 BI(Vec<i32>),
185 SA(Vec<f32>),
187 SF(Vec<f32>),
189 SR(Vec<f32>),
191 UN(Vec<String>),
193 LM(String),
195 RB(String),
197}
198
199impl DataType {
200 pub fn as_str(&self) -> &'static str {
201 use DataType::*;
202 match self {
203 EA(_) => "EA",
204 EL(_) => "EL",
205 ER(_) => "ER",
206 PI(_) => "PI",
207 PR(_) => "PR",
208 PG(_) => "PG",
209 T0(_) => "T0",
210 T1(_) => "T1",
211 TH(_) => "TH",
212 AX(_) => "AX",
213 AY(_) => "AY",
214 AZ(_) => "AZ",
215 GX(_) => "GX",
216 GY(_) => "GY",
217 GZ(_) => "GZ",
218 MX(_) => "MX",
219 MY(_) => "MY",
220 MZ(_) => "MZ",
221 BV(_) => "BV",
222 BATLV(_) => "B%",
223 AK(_) => "AK",
224 RD(_) => "RD",
225 TL(_) => "TL",
226 TX(_) => "TX",
227 TxTlLc(_) => "TX_TL_LC",
228 TxLcLm(_) => "TX_LC_LM",
229 EM(_) => "EM",
230 HR(_) => "HR",
231 BI(_) => "BI",
232 SA(_) => "SA",
233 SF(_) => "SF",
234 SR(_) => "SR",
235 UN(_) => "UN",
237 LM(_) => "LM",
238 RB(_) => "RB",
240 }
241 }
242
243 pub fn payload(&self) -> Vec<String> {
244 use DataType::*;
245 match self {
246 EA(v) => v.iter().map(|p| p.to_string()).collect(),
247 EL(v) => v.iter().map(|p| p.to_string()).collect(),
248 ER(v) => v.iter().map(|p| p.to_string()).collect(),
249 PI(v) => v.iter().map(|p| p.to_string()).collect(),
250 PR(v) => v.iter().map(|p| p.to_string()).collect(),
251 PG(v) => v.iter().map(|p| p.to_string()).collect(),
252 T0(v) => v.iter().map(|p| p.to_string()).collect(),
253 T1(v) => v.iter().map(|p| p.to_string()).collect(),
254 TH(v) => v.iter().map(|p| p.to_string()).collect(),
255 AX(v) => v.iter().map(|p| p.to_string()).collect(),
256 AY(v) => v.iter().map(|p| p.to_string()).collect(),
257 AZ(v) => v.iter().map(|p| p.to_string()).collect(),
258 GX(v) => v.iter().map(|p| p.to_string()).collect(),
259 GY(v) => v.iter().map(|p| p.to_string()).collect(),
260 GZ(v) => v.iter().map(|p| p.to_string()).collect(),
261 MX(v) => v.iter().map(|p| p.to_string()).collect(),
262 MY(v) => v.iter().map(|p| p.to_string()).collect(),
263 MZ(v) => v.iter().map(|p| p.to_string()).collect(),
264 BV(v) => v.iter().map(|p| p.to_string()).collect(),
265 BATLV(v) => v.iter().map(|p| p.to_string()).collect(),
266 AK(sv) => sv.to_vec(),
267 RD(sv) => sv.to_vec(),
268 TL(s) => vec![s.to_owned()],
269 TX(sv) => sv.to_vec(),
270 TxTlLc((s, f)) => vec![s.to_owned(), f.to_string()],
271 TxLcLm(v) => v.iter().map(|p| p.to_string()).collect(),
272 EM(sv) => sv.to_vec(),
273 HR(v) => v.iter().map(|p| p.to_string()).collect(),
274 BI(v) => v.iter().map(|p| p.to_string()).collect(),
275 SA(v) => v.iter().map(|p| p.to_string()).collect(),
276 SF(v) => v.iter().map(|p| p.to_string()).collect(),
277 SR(v) => v.iter().map(|p| p.to_string()).collect(),
278 UN(sv) => sv.to_vec(),
280 LM(s) => vec![s.to_owned()],
281 RB(s) => vec![s.to_owned()],
283 }
284 }
285}
286
287fn get_data_type(record: &StringRecord, type_str: &str) -> Result<DataType> {
288 let skip_to_payload = 6_usize;
289 match type_str {
290 "RB" => Ok(DataType::RB(to_string(record, skip_to_payload))),
291 "AK" => Ok(DataType::AK(to_string_vec(record, skip_to_payload))),
292 "EA" => Ok(DataType::EA(to_vec::<f32>(record, skip_to_payload)?)),
293 "EL" => Ok(DataType::EL(to_vec::<f32>(record, skip_to_payload)?)),
294 "ER" => Ok(DataType::ER(to_vec::<f32>(record, skip_to_payload)?)),
295 "PI" => Ok(DataType::PI(to_vec::<u32>(record, skip_to_payload)?)),
296 "PR" => Ok(DataType::PR(to_vec::<u32>(record, skip_to_payload)?)),
297 "PG" => Ok(DataType::PG(to_vec::<u32>(record, skip_to_payload)?)),
298 "T0" => Ok(DataType::T0(to_vec::<f32>(record, skip_to_payload)?)),
299 "T1" => Ok(DataType::T1(to_vec::<f32>(record, skip_to_payload)?)),
300 "TH" => Ok(DataType::TH(to_vec::<f32>(record, skip_to_payload)?)),
301 "AX" => Ok(DataType::AX(to_vec::<f32>(record, skip_to_payload)?)),
302 "AY" => Ok(DataType::AY(to_vec::<f32>(record, skip_to_payload)?)),
303 "AZ" => Ok(DataType::AZ(to_vec::<f32>(record, skip_to_payload)?)),
304 "GX" => Ok(DataType::GX(to_vec::<f32>(record, skip_to_payload)?)),
305 "GY" => Ok(DataType::GY(to_vec::<f32>(record, skip_to_payload)?)),
306 "GZ" => Ok(DataType::GZ(to_vec::<f32>(record, skip_to_payload)?)),
307 "MX" => Ok(DataType::MX(to_vec::<i32>(record, skip_to_payload)?)),
308 "MY" => Ok(DataType::MY(to_vec::<i32>(record, skip_to_payload)?)),
309 "MZ" => Ok(DataType::MZ(to_vec::<i32>(record, skip_to_payload)?)),
310 "BI" => Ok(DataType::BI(to_vec::<i32>(record, skip_to_payload)?)),
311 "SA" => Ok(DataType::SA(to_vec::<f32>(record, skip_to_payload)?)),
312 "SF" => Ok(DataType::SF(to_vec::<f32>(record, skip_to_payload)?)),
313 "SR" => Ok(DataType::SR(to_vec::<f32>(record, skip_to_payload)?)),
314 "BV" => Ok(DataType::BV(to_vec::<f32>(record, skip_to_payload)?)),
315 "HR" => Ok(DataType::HR(to_vec::<i32>(record, skip_to_payload)?)),
316 "B%" => Ok(DataType::BATLV(to_vec::<u32>(record, skip_to_payload)?)),
317 "RD" => Ok(DataType::RD(to_string_vec(record, skip_to_payload))),
318 "UN" => Ok(DataType::UN(to_string_vec(record, skip_to_payload))),
319 "EM" => Ok(DataType::EM(to_string_vec(record, skip_to_payload))),
320 "TL" => Ok(DataType::TL(to_string(record, skip_to_payload))),
321 "TX" => Ok(DataType::TX(to_string_vec(record, skip_to_payload))),
322 "LM" => Ok(DataType::LM(to_string(record, skip_to_payload))),
323 _ => Err(anyhow!("Unknown Type: {}, {:?}", type_str, record)),
325 }
326}
327
328fn to_string(record: &StringRecord, index: usize) -> String {
330 record.iter().skip(index).join(",")
331}
332
333fn to_vec<T>(record: &StringRecord, index_from: usize) -> Result<Vec<T>>
334where
335 T: num::Num + FromStr,
336 <T as std::str::FromStr>::Err: std::fmt::Debug,
337{
338 let mut errors = vec![];
339 let vec = record
340 .iter()
341 .skip(index_from)
342 .map(|x| x.to_string().trim().parse::<T>())
343 .filter_map(|r| r.map_err(|e| errors.push(e)).ok())
344 .collect::<Vec<T>>();
345 if errors.is_empty() {
346 Ok(vec)
347 } else {
348 Err(anyhow!("Parse to Num Error: {:?}", record))
349 }
350}
351
352fn to_string_vec(record: &StringRecord, index_from: usize) -> Vec<String> {
353 record
354 .iter()
355 .skip(index_from)
356 .map(|str| str.to_owned())
357 .collect()
358}
359
360#[derive(Debug, Clone)]
362pub struct TimeSync {
363 pub rd: f64,
365 pub ts_received: f64,
367 pub ts_sent: String,
369 pub ak: f64,
371 pub round_trip: f64,
373}
374
375impl Csv for TimeSync {
376 fn csv(&self) -> Vec<StringRecord> {
377 vec![StringRecord::from(vec![
378 self.rd.to_string(),
379 self.ts_received.to_string(),
380 self.ts_sent.to_owned(),
381 self.ak.to_string(),
382 self.round_trip.to_string(),
383 ])]
384 }
385}
386
387#[derive(Debug)]
389pub struct TimeSyncMap {
390 pub te0: f64,
391 pub te1: f64,
392 pub tl0: f64,
393 pub tl1: f64,
394 pub syncs_received: usize,
395 pub emotibit_start_time: f64,
396 pub emotibit_end_time: f64,
397 pub parse_version: String,
398}
399
400impl Csv for TimeSyncMap {
401 fn csv(&self) -> Vec<StringRecord> {
402 vec![StringRecord::from(vec![
403 self.te0.to_string(),
404 self.te1.to_string(),
405 self.tl0.to_string(),
406 self.tl1.to_string(),
407 self.syncs_received.to_string(),
408 self.emotibit_start_time.to_string(),
409 self.emotibit_end_time.to_string(),
410 self.parse_version.to_owned(),
411 ])]
412 }
413}