1#[macro_use] extern crate log;
43
44pub mod prelude;
45#[cfg(feature="random")]
46pub mod random;
47pub mod constants;
48pub mod events;
49pub mod packets;
50pub mod version;
51pub mod io;
52pub mod calibration;
53pub mod errors;
54pub mod tof;
55pub mod tracker;
56pub mod monitoring;
57pub mod stats;
58#[cfg(feature="pybindings")]
59pub mod python;
60#[cfg(feature="database")]
61pub mod database;
62
63pub const VERSION: &str = env!("CARGO_PKG_VERSION");
65
66#[cfg(feature="pybindings")]
67use crate::errors::*;
68
69#[macro_export]
74macro_rules! expand_and_test_enum {
75 ($name:ident, $test_name:ident) => {
76 impl fmt::Display for $name {
77 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78 write!(f, "<{}: {}>",stringify!($name), self.as_ref())
79 }
80 }
81
82 impl From<u8> for $name {
83 fn from(value: u8) -> Self {
84 match Self::from_repr(value) {
85 None => {
86 return Self::Unknown;
87 }
88 Some(variant) => {
89 return variant;
90 }
91 }
92 }
93 }
94
95 #[cfg(feature="random")]
96 impl FromRandom for $name {
97 fn from_random() -> Self {
98 let mut choices = Vec::<Self>::new();
99 for k in Self::iter() {
100 choices.push(k);
101 }
102 let mut rng = rand::rng();
103 let idx = rng.random_range(0..choices.len());
104 choices[idx]
105 }
106 }
107
108 #[test]
109 fn $test_name() {
110 for _ in 0..100 {
111 let data = $name::from_random();
112 assert_eq!($name::from(data as u8), data);
113 }
114 }
115
116 #[cfg(feature="pybindings")]
117 #[pymethods]
118 impl $name {
119
120 #[staticmethod]
121 #[pyo3(name = "from_u8")]
122 fn from_py(byte : u8) -> Self {
123 Self::from(byte)
124 }
125 }
126 };
127}
128
129use colored::{
134 Colorize,
135 ColoredString
136};
137use chrono::Utc;
138use log::Level;
139use std::io::Write;
140
141pub fn color_log(level : &Level) -> ColoredString {
143 match level {
144 Level::Error => String::from(" ERROR!").red(),
145 Level::Warn => String::from(" WARN ").yellow(),
146 Level::Info => String::from(" Info ").green(),
147 Level::Debug => String::from(" debug ").blue(),
148 Level::Trace => String::from(" trace ").cyan(),
149 }
150}
151
152pub fn init_env_logger() {
158 env_logger::builder()
159 .format(|buf, record| {
160 writeln!( buf, "[{ts} - {level}][{module_path}:{line}] {args}",
161 ts = Utc::now().format("%Y/%m/%d-%H:%M:%SUTC"),
162 level = color_log(&record.level()),
163 module_path = record.module_path().unwrap_or("<unknown>"),
164 line = record.line().unwrap_or(0),
165 args = record.args()
166 )
167 }).init();
168}
169
170#[cfg(feature="pybindings")]
174pub use pyo3::prelude::*;
175#[cfg(feature="pybindings")]
176pub use pyo3::wrap_pymodule;
177#[cfg(feature="pybindings")]
178pub use pyo3::wrap_pyfunction;
179
180#[cfg(feature="pybindings")]
181#[pymodule]
182#[pyo3(name = "tof")]
183fn tof_py<'_py>(m: &Bound<'_py, PyModule>) -> PyResult<()> {
184 use crate::tof::*;
185 m.add_class::<RBPaddleID>()?;
186 m.add_class::<TofDetectorStatus>()?;
187 m.add_class::<TofCommandCode>()?;
188 m.add_class::<TofCommand>()?;
189 m.add_class::<TofOperationMode>()?;
190 m.add_class::<BuildStrategy>()?;
191 m.add_class::<PreampBiasConfig>()?;
192 m.add_class::<RBChannelMaskConfig>()?;
193 m.add_class::<TriggerConfig>()?;
194 m.add_class::<TofRunConfig>()?;
195 m.add_class::<TofCuts>()?;
196 m.add_class::<TofAnalysis>()?;
197 m.add_class::<TofAnalysisCache>()?;
198 m.add_class::<TofAnalysisPaddleCache>()?;
199 m.add_class::<AnalysisEngineSettings>()?;
200 #[cfg(feature="tof-liftof")]
201 m.add_class::<PyMasterTrigger>()?;
202 m.add_function(wrap_pyfunction!(waveform_analysis, m)?)?;
203 m.add_function(wrap_pyfunction!(to_board_id_string, m)?)?;
204 m.add_function(wrap_pyfunction!(start_run, m)?)?;
206 m.add_function(wrap_pyfunction!(stop_run, m)?)?;
207 m.add_function(wrap_pyfunction!(restart_liftofrb, m)?)?;
208 m.add_function(wrap_pyfunction!(enable_verification_run, m)?)?;
209 m.add_function(wrap_pyfunction!(shutdown_all_rbs, m)?)?;
210 m.add_function(wrap_pyfunction!(shutdown_rat, m)?)?;
211 m.add_function(wrap_pyfunction!(shutdown_ratpair, m)?)?;
212 m.add_function(wrap_pyfunction!(shutdown_rb, m)?)?;
213 m.add_function(wrap_pyfunction!(shutdown_tofcpu, m)?)?;
214 m.add_function(wrap_pyfunction!(run_action_alfa, m)?)?;
215 m.add_function(wrap_pyfunction!(run_action_bravo, m)?)?;
216 m.add_function(wrap_pyfunction!(run_action_charlie, m)?)?;
217 m.add_function(wrap_pyfunction!(run_action_whiskey, m)?)?;
218 m.add_function(wrap_pyfunction!(run_action_tango, m)?)?;
219 m.add_function(wrap_pyfunction!(run_action_foxtrott, m)?)?;
220 m.add_function(wrap_pyfunction!(request_liftof_settings, m)?)?;
221 m.add_function(wrap_pyfunction!(restore_default_config, m)?)?;
222 m.add_function(wrap_pyfunction!(apply_settings_diff, m)?)?;
223 Ok(())
224}
225
226#[cfg(feature="pybindings")]
227#[pymodule]
228#[pyo3(name = "tracker")]
229fn tracker_py<'_py>(m: &Bound<'_py, PyModule>) -> PyResult<()> {
230 use crate::tracker::*;
231 m.add_function(wrap_pyfunction!(strip_lines, m)?)?;
233 Ok(())
234}
235
236#[cfg(feature="pybindings")]
237#[pymodule]
238#[pyo3(name = "calibration")]
239fn calibration_py<'_py>(m: &Bound<'_py, PyModule>) -> PyResult<()> {
240 use crate::calibration::tof::*;
241 m.add_class::<RBCalibrations>()?;
242 Ok(())
243}
244
245#[cfg(feature="pybindings")]
246#[pymodule]
247#[pyo3(name = "events")]
248fn events_py<'_py>(m: &Bound<'_py, PyModule>) -> PyResult<()> {
249 use crate::events::*;
250 m.add_class::<TofHit>()?;
251 m.add_class::<TrackerHit>()?;
252 m.add_class::<RBEventHeader>()?;
253 m.add_class::<RBEvent>()?;
254 m.add_class::<RBWaveform>()?;
255 m.add_class::<EventStatus>()?;
256 m.add_class::<DataType>()?;
257 m.add_class::<TofEvent>()?;
258 m.add_class::<TelemetryEvent>()?;
259 m.add_function(wrap_pyfunction!(strip_id, m)?)?;
260 m.add_class::<EventQuality>()?;
261 m.add_class::<TriggerType>()?;
262 m.add_class::<LTBThreshold>()?;
263 m.add_function(wrap_pyfunction!(mt_event_get_timestamp_abs48,m)?)?;
264 Ok(())
265}
266
267#[cfg(feature="pybindings")]
268#[pymodule]
269#[pyo3(name = "packets")]
270fn packets_py<'_py>(m: &Bound<'_py, PyModule>) -> PyResult<()> {
271 use crate::packets::*;
272 m.add_class::<TofPacketType>()?;
273 m.add_class::<TofPacket>()?;
274 m.add_class::<TelemetryPacketType>()?;
275 m.add_class::<TelemetryPacket>()?;
276 m.add_class::<TelemetryPacketHeader>()?;
277 m.add_class::<TrackerHeader>()?;
278 m.add_class::<PduChannel>()?;
279 m.add_class::<Pac1934>()?;
280 m.add_class::<PduHKPacket>()?;
281 m.add_function(wrap_pyfunction!(make_systime,m)?)?;
282 Ok(())
283}
284
285#[cfg(feature="pybindings")]
286#[pymodule]
287#[pyo3(name = "io")]
288fn io_py<'_py>(m: &Bound<'_py, PyModule>) -> PyResult<()> {
289 use crate::io::*;
290 use crate::io::caraspace::*;
291 #[cfg(feature="root")]
292 use crate::io::root_reader::read_example;
293 use crate::io::caraspace::frame::get_all_telemetry_event_names;
294 #[cfg(feature="root")]
295 m.add_function(wrap_pyfunction!(read_example, m)?)?;
296 m.add_function(wrap_pyfunction!(get_all_telemetry_event_names, m)?)?;
297 m.add_function(wrap_pyfunction!(get_runfilename, m)?)?;
298 m.add_function(wrap_pyfunction!(get_califilename, m)?)?;
299 m.add_function(wrap_pyfunction!(list_path_contents_sorted_py, m)?)?;
300 m.add_function(wrap_pyfunction!(get_utc_timestamp, m)?)?;
301 m.add_function(wrap_pyfunction!(get_utc_date, m)?)?;
302 m.add_function(wrap_pyfunction!(get_rundata_from_file, m)?)?;
303 m.add_function(wrap_pyfunction!(get_datetime, m)?)?;
304 m.add_function(wrap_pyfunction!(get_unix_timestamp, m)?)?;
305 m.add_function(wrap_pyfunction!(get_unix_timestamp_from_telemetry, m)?)?;
306 m.add_function(wrap_pyfunction!(apply_diff_to_file_py, m)?)?;
308 m.add_function(wrap_pyfunction!(compress_toml_py, m)?)?;
309 m.add_function(wrap_pyfunction!(decompress_toml_py, m)?)?;
310 m.add_function(wrap_pyfunction!(create_compressed_diff_py, m)?)?;
311
312 m.add_class::<CRFrameObject>()?;
313 m.add_class::<CRFrameObjectType>()?;
314 m.add_class::<CRFrame>()?;
315 m.add_class::<DataSourceKind>()?;
316 m.add_class::<CRReader>()?;
317 m.add_class::<CRWriter>()?;
318 m.add_class::<TofPacketReader>()?;
319 m.add_class::<TofPacketWriter>()?;
320 m.add_class::<TelemetryPacketReader>()?;
321 Ok(())
323}
324
325#[cfg(feature="pybindings")]
326#[pymodule]
327#[pyo3(name = "monitoring")]
328fn monitoring_py<'_py>(m: &Bound<'_py, PyModule>) -> PyResult<()> {
329 use crate::monitoring::*;
330 m.add_class::<EventBuilderHB>()?;
331 m.add_class::<EventBuilderHBSeries>()?;
332 m.add_class::<DataSinkHB>()?;
333 m.add_class::<DataSinkHBSeries>()?;
334 m.add_class::<MasterTriggerHB>()?;
335 m.add_class::<MasterTriggerHBSeries>()?;
336 m.add_class::<PAMoniData>()?;
337 m.add_class::<PAMoniDataSeries>()?;
338 m.add_class::<PBMoniData>()?;
339 m.add_class::<PBMoniDataSeries>()?;
340 m.add_class::<MtbMoniData>()?;
341 m.add_class::<MtbMoniDataSeries>()?;
342 m.add_class::<LTBMoniData>()?;
343 m.add_class::<LTBMoniDataSeries>()?;
344 m.add_class::<RBMoniData>()?;
345 m.add_class::<RBMoniDataSeries>()?;
346 m.add_class::<CPUMoniData>()?;
347 m.add_class::<CPUMoniDataSeries>()?;
348 m.add_class::<RunStatistics>()?;
349 Ok(())
350}
351
352#[cfg(feature="pybindings")]
353#[pymodule]
354#[pyo3(name = "stats")]
355fn stats_py<'_py>(m: &Bound<'_py, PyModule>) -> PyResult<()> {
356 use crate::stats::py_gamma_pdf;
358 m.add_function(wrap_pyfunction!(py_gamma_pdf, m)?)?;
359 Ok(())
360}
361
362#[cfg(feature="pybindings")]
363#[pymodule]
364#[pyo3(name = "algo")]
365fn algo_py<'_py>(m: &Bound<'_py, PyModule>) -> PyResult<()> {
366 use crate::tof::algorithms::*;
368 m.add_function(wrap_pyfunction!(get_max_value_idx_py, m)?)?;
369 m.add_function(wrap_pyfunction!(interpolate_time_py, m)?)?;
370 m.add_function(wrap_pyfunction!(fit_sine_simple_py, m)?)?;
371 Ok(())
372}
373
374#[cfg(feature="database")]
375#[cfg(feature="pybindings")]
376#[pymodule]
377#[pyo3(name = "db")]
378fn db_py<'_py>(m: &Bound<'_py, PyModule>) -> PyResult<()> {
379 use crate::database::*;
380 m.add_class::<TofPaddle>()?;
381 m.add_class::<ReadoutBoard>()?;
382 m.add_class::<TrackerStrip>()?;
383 m.add_class::<TrackerStripMask>()?;
384 m.add_class::<TrackerStripPedestal>()?;
385 m.add_class::<TrackerStripTransferFunction>()?;
386 m.add_class::<TrackerStripCmnNoise>()?;
387 m.add_class::<TofPaddleTimingConstant>()?;
388 m.add_function(wrap_pyfunction!(get_all_rbids_in_db, m)?)?;
389 m.add_function(wrap_pyfunction!(get_hid_vid_map, m)?)?;
390 m.add_function(wrap_pyfunction!(get_vid_hid_map, m)?)?;
391 m.add_function(wrap_pyfunction!(get_dsi_j_ch_pid_map_py, m)?)?;
392 Ok(())
393}
394
395#[cfg(feature="pybindings")]
396#[pyfunction]
397fn get_version() -> &'static str {
398 return VERSION;
399}
400
401#[cfg(feature="pybindings")]
425pyo3::create_exception!(gondola_core_py, PyMasterTriggerError, pyo3::exceptions::PyException);
426#[cfg(feature="pybindings")]
427pyo3::create_exception!(gondola_core_py, PyRunError, pyo3::exceptions::PyException);
428#[cfg(feature="pybindings")]
429pyo3::create_exception!(gondola_core_py, PyTofError, pyo3::exceptions::PyException);
430#[cfg(feature="pybindings")]
431pyo3::create_exception!(gondola_core_py, PyStagingError, pyo3::exceptions::PyException);
432#[cfg(feature="pybindings")]
433pyo3::create_exception!(gondola_core_py, PySensorError, pyo3::exceptions::PyException);
434#[cfg(feature="pybindings")]
435pyo3::create_exception!(gondola_core_py, PyUserError, pyo3::exceptions::PyException);
436#[cfg(feature="pybindings")]
437pyo3::create_exception!(gondola_core_py, PyCalibrationError, pyo3::exceptions::PyException);
438#[cfg(feature="pybindings")]
439pyo3::create_exception!(gondola_core_py, PyWaveformError, pyo3::exceptions::PyException);
440#[cfg(feature="pybindings")]
441pyo3::create_exception!(gondola_core_py, PyIPBusError, pyo3::exceptions::PyException);
442#[cfg(feature="pybindings")]
443pyo3::create_exception!(gondola_core_py, PySerializationError, pyo3::exceptions::PyException);
444#[cfg(feature="pybindings")]
445pyo3::create_exception!(gondola_core_py, PyAnalysisError, pyo3::exceptions::PyException);
446
447#[macro_export]
448macro_rules! pythonize_error {
449 ($name:ident, $pyname:ident) => {
450
451 impl From<$name> for PyErr {
452 fn from(err: $name) -> PyErr {
453 $pyname::new_err(format!("<GondolaCoreException: {}>", err))
457 }
458 }
459 }
460}
461
462#[cfg(feature="pybindings")]
463pythonize_error!(SerializationError, PySerializationError);
464#[cfg(feature="pybindings")]
465pythonize_error!(AnalysisError, PyAnalysisError);
466
467
468#[cfg(feature="pybindings")]
473#[pymodule]
474#[pyo3(name = "gondola_core")]
475fn gondola_core_py<'_py>(m : &Bound<'_py, PyModule>) -> PyResult<()> { pyo3_log::init();
477 m.add_function(wrap_pyfunction!(get_version, m)?)?;
478 m.add_wrapped(wrap_pymodule!(events_py))?;
479 m.add_wrapped(wrap_pymodule!(monitoring_py))?;
480 m.add_wrapped(wrap_pymodule!(packets_py))?;
481 m.add_wrapped(wrap_pymodule!(tof_py))?;
482 m.add_wrapped(wrap_pymodule!(tracker_py))?;
483 m.add_wrapped(wrap_pymodule!(io_py))?;
484 m.add_wrapped(wrap_pymodule!(db_py))?;
485 m.add_wrapped(wrap_pymodule!(stats_py))?;
486 m.add_wrapped(wrap_pymodule!(algo_py))?;
487 m.add_wrapped(wrap_pymodule!(calibration_py))?;
488 Ok(())
491}
492
493
494
495