use eskin_finger_sdk::types::FingerSample; #[derive(Clone)] pub struct FrameTiming { pub pts_ms: Option, pub dts_ms: u64, } #[derive(Clone)] pub struct RecordedFrame { pub timing: FrameTiming, pub frame: F, } #[derive(Clone, Default)] pub struct Recording { pub frames: Vec>, } impl Recording { pub fn new() -> Recording { Self { frames: Vec::new(), } } pub fn push(&mut self, item: RecordedFrame) { self.frames.push(item); } } pub type FingerRecording = Recording; pub fn export_recording_csv( recording: &Recording, mut writer: W, ) -> anyhow::Result<()> where W: std::io::Write, { // Infer channel count from the first sample's combined_forces (just fz) // We write: timestamp_us, sequence, module, fx, fy, fz let mut wrt = csv::Writer::from_writer(&mut writer); wrt.write_record(["timestamp_us", "sequence", "module", "fx", "fy", "fz"])?; for frame in &recording.frames { let s = &frame.frame; wrt.write_record(&[ s.timestamp_us.to_string(), s.sequence.to_string(), format!("{:?}", s.combined_forces.module), s.combined_forces.force.fx.to_string(), s.combined_forces.force.fy.to_string(), s.combined_forces.force.fz.to_string(), ])?; } wrt.flush()?; Ok(()) } pub struct FingerSampleCsvPacket { pub timestamp_us: u64, pub sequence: u32, pub fz: u32, } pub fn import_csv( reader: R, ) -> anyhow::Result> { let mut rdr = csv::Reader::from_reader(reader); let mut packets = Vec::new(); for result in rdr.records() { let record = result?; if record.len() < 6 { continue; } let timestamp_us = record.get(0).unwrap_or("0").parse::().unwrap_or(0); let sequence = record.get(1).unwrap_or("0").parse::().unwrap_or(0); let fz = record.get(5).unwrap_or("0").parse::().unwrap_or(0); packets.push(FingerSampleCsvPacket { timestamp_us, sequence, fz, }); } Ok(packets) }