gondola_core/io/
tof_writer.rs

1// The following file is part of gaps-online-software and published 
2// under the GPLv3 license
3
4use crate::prelude::*;
5
6/// Write TofPackets to disk.
7///
8/// Operates sequentially, packets can 
9/// be added one at a time, then will
10/// be synced to disk.
11#[cfg_attr(feature="pybindings", pyclass)]
12pub struct TofPacketWriter {
13
14  pub file            : File,
15  /// location to store the file
16  pub file_path       : String,
17  /// The maximum number of packets 
18  /// for a single file. Ater this 
19  /// number is reached, a new 
20  /// file is started.
21  pub pkts_per_file   : usize,
22  /// The maximum number of (Mega)bytes
23  /// per file. After this a new file 
24  /// is started
25  pub mbytes_per_file : usize,
26  /// add timestamps to filenames
27  pub file_type       : FileType,
28  pub file_name       : String,
29
30  file_id             : usize,
31  /// internal packet counter, number of 
32  /// packets which went through the writer
33  n_packets           : usize,
34  /// internal counter for bytes written in 
35  /// this file
36  file_nbytes_wr      : usize,
37}
38
39#[cfg(feature="pybindings")]
40#[pymethods]
41impl TofPacketWriter {
42
43#[new]
44  fn new_py(filename : String, runid : u32) -> PyResult<Self> {
45    let writer = TofPacketWriter::new(filename, FileType::RunFile(runid));
46    Ok(writer)
47  }
48
49  #[pyo3(name="add_tof_packet")]
50  pub fn add_tof_packet_py(&mut self, packet : &TofPacket) {
51    self.add_tof_packet(packet);
52  }
53
54}
55
56impl TofPacketWriter {
57
58  /// Instantiate a new PacketWriter 
59  ///
60  /// # Arguments
61  ///
62  /// * file_prefix     : Prefix file with this string. A continuous number will get 
63  ///                     appended to control the file size.
64  /// * file_type       : control the behaviour of how the filename is
65  ///                     assigned.
66  pub fn new(mut file_path : String, file_type : FileType) -> Self {
67    //let filename = file_prefix.clone() + "_0.tof.gaps";
68    let file : File;
69    let file_name : String;
70    if !file_path.ends_with("/") {
71      file_path += "/";
72    }
73    match file_type {
74      FileType::Unknown => {
75        let filename = file_path.clone() + "Data.tof.gaps";
76        let path     = Path::new(&filename); 
77        info!("Writing to file {filename}");
78        file = OpenOptions::new().create(true).append(true).open(path).expect("Unable to open file {filename}");
79        file_name = filename;
80      }
81      FileType::RunFile(runid) => {
82        let filename = format!("{}{}", file_path, get_runfilename(runid, 0, None, None, true));
83        let path     = Path::new(&filename); 
84        println!("Writing to file {filename}");
85        file = OpenOptions::new().create(true).append(true).open(path).expect("Unable to open file {filename}");
86        file_name = filename;
87      }
88      FileType::CalibrationFile(rbid) => {
89        let filename = format!("{}{}", file_path, get_califilename(rbid, false));
90        //let filename = file_path.clone() + &get_califilename(rbid,false);
91        let path     = Path::new(&filename); 
92        info!("Writing to file {filename}");
93        file = OpenOptions::new().create(true).append(true).open(path).expect("Unable to open file {filename}");
94        file_name = filename;
95      }
96      FileType::SummaryFile(ref fname) => {
97        let filename = fname.replace(".tof.", ".tofsum.");
98        let path     = Path::new(&filename);
99        info!("Writing to file {filename}");
100        file = OpenOptions::new().create(true).append(true).open(path).expect("Unable to open file {filename}");
101        file_name = filename;
102      }
103    }
104    Self {
105      file,
106      file_path        : file_path,
107      pkts_per_file    : 0,
108      mbytes_per_file  : 420,
109      file_nbytes_wr   : 0,    
110      file_type        : file_type,
111      file_id          : 1,
112      n_packets        : 0,
113      file_name        : file_name,
114    }
115  }
116
117  pub fn get_file(&self) -> File { 
118    let file : File;
119    match &self.file_type {
120      FileType::Unknown => {
121        let filename = self.file_path.clone() + "Data.tof.gaps";
122        let path     = Path::new(&filename); 
123        info!("Writing to file {filename}");
124        file = OpenOptions::new().create(true).append(true).open(path).expect("Unable to open file {filename}");
125      }
126      FileType::RunFile(runid) => {
127        let filename = format!("{}{}", self.file_path, get_runfilename(*runid, self.file_id as u64, None, None, true));
128        //let filename = self.file_path.clone() + &get_runfilename(runid,self.file_id as u64, None);
129        let path     = Path::new(&filename); 
130        info!("Writing to file {filename}");
131        file = OpenOptions::new().create(true).append(true).open(path).expect("Unable to open file {filename}");
132      }
133      FileType::CalibrationFile(rbid) => {
134        //let filename = self.file_path.clone() + &get_califilename(rbid,false);
135        let filename = format!("{}{}", self.file_path, get_califilename(*rbid, false));
136        let path     = Path::new(&filename); 
137        info!("Writing to file {filename}");
138        file = OpenOptions::new().create(true).append(true).open(path).expect("Unable to open file {filename}");
139      }
140      FileType::SummaryFile(fname) => {
141        let filename = fname.replace(".tof.", ".tofsum.");
142        let path     = Path::new(&filename);
143        info!("Writing to file {filename}");
144        file = OpenOptions::new().create(true).append(true).open(path).expect("Unable to open file {filename}");
145      }
146    }
147    file
148  }
149
150  /// Induce serialization to disk for a TofPacket
151  ///
152  ///
153  pub fn add_tof_packet(&mut self, packet : &TofPacket) {
154    let buffer = packet.to_bytestream();
155    self.file_nbytes_wr += buffer.len();
156    match self.file.write_all(buffer.as_slice()) {
157      Err(err) => error!("Writing to file to path {} failed! {}", self.file_path, err),
158      Ok(_)    => ()
159    }
160    self.n_packets += 1;
161    let mut newfile = false;
162    if self.pkts_per_file != 0 {
163      if self.n_packets == self.pkts_per_file {
164        newfile = true;
165        self.n_packets = 0;
166      }
167    } else if self.mbytes_per_file != 0 {
168      // multiply by mebibyte
169      if self.file_nbytes_wr >= self.mbytes_per_file * 1_048_576 {
170        newfile = true;
171        self.file_nbytes_wr = 0;
172      }
173    }
174    if newfile {
175        //let filename = self.file_prefix.clone() + "_" + &self.file_id.to_string() + ".tof.gaps";
176        match self.file.sync_all() {
177          Err(err) => {
178            error!("Unable to sync file to disc! {err}");
179          },
180          Ok(_) => ()
181        }
182        self.file = self.get_file();
183        self.file_id += 1;
184        //let path  = Path::new(&filename);
185        //println!("==> [TOFPACKETWRITER] Will start a new file {}", path.display());
186        //self.file = OpenOptions::new().create(true).append(true).open(path).expect("Unable to open file {filename}");
187        //self.n_packets = 0;
188        //self.file_id += 1;
189      }
190  debug!("TofPacket written!");
191  }
192}
193
194impl Default for TofPacketWriter {
195  fn default() -> TofPacketWriter {
196    TofPacketWriter::new(String::from(""), FileType::Unknown)
197  }
198}
199