Skip to main content

tttr_toolbox/parsers/ptu/
mod.rs

1pub mod header;
2pub mod streamers;
3
4use std::collections::HashMap;
5use std::path::PathBuf;
6
7use num_traits::FromPrimitive;
8
9use crate::errors::Error;
10use crate::headers;
11use crate::TTTRFile;
12
13pub type Header = HashMap<String, PTUTag>;
14
15#[derive(Debug)]
16pub enum PTUTag {
17    Empty8,
18    Bool8(bool),
19    Int8(i64),
20    BitSet64(i64),
21    Color8(i64),
22    Float8(f64),
23    TDateTime(f64),
24    Float8Array(Vec<f64>),
25    AnsiString8(String),
26    WideString(String),
27    BinaryBlob(Vec<u8>),
28}
29
30#[derive(FromPrimitive, ToPrimitive, Debug)]
31enum PTUTagType {
32    Empty8 = 0xFFFF0008,
33    Bool8 = 0x00000008,
34    Int8 = 0x10000008,
35    BitSet64 = 0x11000008,
36    Color8 = 0x12000008,
37    Float8 = 0x20000008,
38    TDateTime = 0x21000008,
39    Float8Array = 0x2001FFFF,
40    AnsiString8 = 0x4001FFFF,
41    WideString = 0x4002FFFF,
42    BinaryBlob = 0xFFFFFFFF,
43}
44
45#[derive(FromPrimitive, ToPrimitive, Debug)]
46enum RecType {
47    PicoHarpT3 = 0x00010303, // (SubID = $00 ,RecFmt: $01) (V1), T-Mode: $03 (T3), HW: $03 (PicoHarp)
48    PicoHarpT2 = 0x00010203, // (SubID = $00 ,RecFmt: $01) (V1), T-Mode: $02 (T2), HW: $03 (PicoHarp)
49    HydraHarpT3 = 0x00010304, // (SubID = $00 ,RecFmt: $01) (V1), T-Mode: $03 (T3), HW: $04 (HydraHarp)
50    HydraHarpT2 = 0x00010204, // (SubID = $00 ,RecFmt: $01) (V1), T-Mode: $02 (T2), HW: $04 (HydraHarp)
51    HydraHarp2T3 = 0x01010304, // (SubID = $01 ,RecFmt: $01) (V2), T-Mode: $03 (T3), HW: $04 (HydraHarp)
52    HydraHarp2T2 = 0x01010204, // (SubID = $01 ,RecFmt: $01) (V2), T-Mode: $02 (T2), HW: $04 (HydraHarp)
53    TimeHarp260NT3 = 0x00010305, // (SubID = $00 ,RecFmt: $01) (V1), T-Mode: $03 (T3), HW: $05 (TimeHarp260N)
54    TimeHarp260NT2 = 0x00010205, // (SubID = $00 ,RecFmt: $01) (V1), T-Mode: $02 (T2), HW: $05 (TimeHarp260N)
55    TimeHarp260PT3 = 0x00010306, // (SubID = $00 ,RecFmt: $01) (V1), T-Mode: $03 (T3), HW: $06 (TimeHarp260P)
56    TimeHarp260PT2 = 0x00010206, // (SubID = $00 ,RecFmt: $01) (V1), T-Mode: $02 (T2), HW: $06 (TimeHarp260P)
57}
58
59const TAG_TTTR_REC_TYPE: &str = "TTResultFormat_TTTRRecType";
60const TAG_NUM_RECORDS: &str = "TTResult_NumberOfRecords"; // Number of TTTR Records in the File;
61const TAG_GLOB_RES: &str = "MeasDesc_GlobalResolution"; // Global Resolution of TimeTag(T2) /NSync (T3)
62const FILE_TAG_END: &str = "Header_End"; // Always appended as last tag (BLOCKEND)
63const _TAG_ACQUISITION_TIMETTTR: &str = "MeasDesc_AcquisitionTime";
64const _TAG_RES: &str = "MeasDesc_Resolution"; // Resolution for the Dtime (T3 Only)
65
66/// Metadata for a PTU file from PicoQuant
67pub struct PTUFile {
68    pub path: PathBuf,
69    pub header: Header,
70}
71
72impl PTUFile {
73    /// Create a PTUFile from its filepath.
74    ///
75    /// If the file does not exist a FileNotAvailable error will be returned.
76    pub fn new(filename: PathBuf) -> Result<Self, Error> {
77        // check if file in path exists
78        if filename.exists() {
79            let header = self::header::read_ptu_header(&filename)?;
80            Ok(Self {
81                path: filename,
82                header,
83            })
84        } else {
85            let filename_string = filename.display().to_string();
86            Err(Error::FileNotAvailable(filename_string))
87        }
88    }
89}
90
91use tttr_toolbox_proc_macros::read_ptu_tag;
92
93impl TTTRFile for PTUFile {
94    fn time_resolution(&self) -> Result<f64, Error> {
95        let header = &self.header;
96        Ok(read_ptu_tag!(header[TAG_GLOB_RES] as Float8))
97    }
98
99    /// Returns the `record_type` used in the file. This is matched on each algorithm
100    /// with a specific file parser.
101    fn record_type(&self) -> Result<headers::RecordType, Error> {
102        let header = &self.header;
103        let record_type = FromPrimitive::from_i64(read_ptu_tag!(header[TAG_TTTR_REC_TYPE] as Int8));
104
105        Ok(
106            match record_type
107                .ok_or_else(|| Error::InvalidHeader(String::from("Invalid RecordType type")))?
108            {
109                RecType::PicoHarpT3 => headers::RecordType::NotImplemented,
110                RecType::PicoHarpT2 => headers::RecordType::PHT2,
111                RecType::HydraHarpT3 => headers::RecordType::NotImplemented,
112                RecType::HydraHarpT2 => headers::RecordType::HHT2_HH2,
113                RecType::HydraHarp2T3 => headers::RecordType::HHT3_HH2,
114                RecType::HydraHarp2T2 => headers::RecordType::HHT2_HH1,
115                RecType::TimeHarp260NT3 => headers::RecordType::HHT3_HH2,
116                RecType::TimeHarp260NT2 => headers::RecordType::HHT2_HH2,
117                RecType::TimeHarp260PT3 => headers::RecordType::HHT3_HH2,
118                RecType::TimeHarp260PT2 => headers::RecordType::HHT2_HH2,
119            },
120        )
121    }
122}
123
124impl std::fmt::Display for PTUFile {
125    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
126        let mut string = String::from("");
127        for (key, value) in &self.header {
128            string.push_str(&format!("{:<35}: {}\n", key, value));
129        }
130        write!(f, "{}", string)
131    }
132}