go_pybindings/
master_trigger.rs

1//! MasterTriggerBoard python interface
2//!
3//!
4//!
5//!
6
7
8use std::collections::HashMap;
9
10use pyo3::prelude::*;
11use pyo3::exceptions::PyValueError;
12
13//extern crate pyo3_log;
14
15use comfy_table::modifiers::UTF8_ROUND_CORNERS;
16use comfy_table::presets::UTF8_FULL;
17use comfy_table::*;
18
19use tof_dataclasses::ipbus::IPBus;
20use tof_dataclasses::events::MasterTriggerEvent;
21
22use liftof_lib::master_trigger::registers::*;
23use liftof_lib::master_trigger as mt_api;
24
25use crate::PyMasterTriggerEvent;
26
27#[pyfunction]
28#[pyo3(name="prescale_to_u32")]
29/// Convert a prescale value in range from 0-1.0 to 
30/// an u32 value so that it can be written to the 
31/// MTB registers
32pub fn wrap_prescale_to_u32(prescale : f32) -> u32 {
33  let mut _prescale = prescale;
34  prescale_to_u32(prescale)
35}
36
37#[pyclass]
38#[pyo3(name = "MasterTrigger")]
39pub struct PyMasterTrigger {
40  ipbus : IPBus,
41}
42
43#[pymethods]
44impl PyMasterTrigger {
45  #[new]
46  fn new(target_address : &str) -> Self {
47    let ipbus = IPBus::new(target_address).expect("Unable to connect to {target_address}");
48    Self {
49      ipbus : ipbus,
50    }
51  }
52
53  fn reset_daq(&mut self) -> PyResult<()>{
54    match self.ipbus.write(0x10,1) {
55      Ok(result) => {
56        return Ok(result); 
57      }
58      Err(err) => {
59        return Err(PyValueError::new_err(err.to_string()));
60      }
61    }
62  }
63
64  fn get_expected_pid(&mut self) -> PyResult<u16> {
65    match self.ipbus.get_target_next_expected_packet_id(){
66      Ok(result) => {
67        return Ok(result); 
68      }
69      Err(err) => {
70        return Err(PyValueError::new_err(err.to_string()));
71      }
72    }
73  }
74
75  fn realign_packet_id(&mut self) -> PyResult<()> {
76    match self.ipbus.realign_packet_id() {
77      Ok(_) => {
78        return Ok(()); 
79      }
80      Err(err) => {
81        return Err(PyValueError::new_err(err.to_string()));
82      }
83    }
84  }
85
86  fn set_packet_id(&mut self, pid : u16) {
87    self.ipbus.pid = pid;
88  }
89
90  fn get_packet_id(&mut self) -> u16 {
91    self.ipbus.pid
92  }
93 
94  #[getter]
95  /// Get the global trigger rate in Hz
96  fn rate(&mut self) -> PyResult<u32> {
97    match TRIGGER_RATE.get(&mut self.ipbus) {
98      Ok(rate) => {
99        return Ok(rate);
100      }
101      Err(err) => {
102        return Err(PyValueError::new_err(err.to_string()));
103      }
104    }
105  }
106  
107  #[getter]
108  /// Get the lost global trigger rate in Hz
109  ///
110  /// This is the rate of triggers which got 
111  /// dropped due to TIU BUSY signal + those which 
112  /// get dropped due to the RBs being busy
113  fn lost_rate(&mut self) -> PyResult<u32> {
114    match LOST_TRIGGER_RATE.get(&mut self.ipbus) {
115      Ok(rate) => {
116        return Ok(rate);
117      }
118      Err(err) => {
119        return Err(PyValueError::new_err(err.to_string()));
120      }
121    }
122  }
123  
124  #[getter]
125  /// The lost rate which occured due to RB busy timeouts
126  fn rb_lost_rate(&mut self) -> PyResult<u32> {
127    match RB_LOST_TRIGGER_RATE.get(&mut self.ipbus) {
128      Ok(rate) => {
129        return Ok(rate);
130      }
131      Err(err) => {
132        return Err(PyValueError::new_err(err.to_string()));
133      }
134    }
135  }
136
137  /// The lost rate which occured due to the tracker BUSY signal
138  #[getter]
139  fn tiu_lost_rate(&mut self) -> PyResult<u32> {
140    match TIU_LOST_TRIGGER_RATE.get(&mut self.ipbus) {
141      Ok(rate) => {
142        return Ok(rate);
143      }
144      Err(err) => {
145        return Err(PyValueError::new_err(err.to_string()));
146      }
147    }
148  }
149
150  #[getter]
151  /// Check if the TIU emulation mode is on
152  ///
153  fn get_tiu_emulation_mode(&mut self) -> PyResult<u32> {
154    match TIU_EMULATION_MODE.get(&mut self.ipbus) {
155      Ok(mode) => {
156        return Ok(mode);
157      }
158      Err(err) => {
159        return Err(PyValueError::new_err(err.to_string()));
160      }
161    }
162  }
163 
164  #[setter]
165  fn set_tiu_emulation_mode(&mut self, value : u32) -> PyResult<()> {
166    match TIU_EMULATION_MODE.set(&mut self.ipbus, value) {
167      Ok(_) => {
168        return Ok(());
169      }
170      Err(err) => {
171        return Err(PyValueError::new_err(err.to_string()));
172      }
173    }
174  }
175
176  #[setter]
177  fn set_tiu_emulation_mode_bsy_cnt(&mut self,  cycles : u32) -> PyResult<()> {
178    match TIU_EMU_BUSY_CNT.set(&mut self.ipbus, cycles) {
179      Ok(_) => {
180        return Ok(());
181      }
182      Err(err) => {
183        return Err(PyValueError::new_err(err.to_string()));
184      }
185    }
186  }
187  
188  #[getter]
189  fn get_tiu_emulation_mode_bsy_cnt(&mut self) -> PyResult<u32> {
190    match TIU_EMU_BUSY_CNT.get(&mut self.ipbus) {
191      Ok(value) => {
192        return Ok(value);
193      }
194      Err(err) => {
195        return Err(PyValueError::new_err(err.to_string()));
196      }
197    }
198  }
199
200  fn get_enable_cyclic_trig(&mut self) -> PyResult<bool> {
201    match TRIG_CYCLIC_EN.get(&mut self.ipbus) {
202      Ok(value) => {
203        return Ok(value > 0);
204      }
205      Err(err) => {
206        return Err(PyValueError::new_err(err.to_string()));
207      }
208    }
209  }
210
211  fn disable_cyclic_trig(&mut self) -> PyResult<()> {
212    match TRIG_CYCLIC_EN.set(&mut self.ipbus, 0x0) {
213      Ok(_) => {
214        return Ok(());
215      }
216      Err(err) => {
217        return Err(PyValueError::new_err(err.to_string()));
218      }
219    }
220  }
221  
222  fn enable_cyclic_trig(&mut self) -> PyResult<()> {
223    match TRIG_CYCLIC_EN.set(&mut self.ipbus, 0x1) {
224      Ok(_) => {
225        return Ok(());
226      }
227      Err(err) => {
228        return Err(PyValueError::new_err(err.to_string()));
229      }
230    }
231  }
232  
233  fn get_cyclic_trigger_interval(&mut self) -> PyResult<u32> {
234    match TRIG_CYCLIC_INTERVAL.get(&mut self.ipbus) {
235      Ok(interval) =>  {
236        return Ok(interval);
237      }
238      Err(err) => {
239        return Err(PyValueError::new_err(err.to_string()));
240      }
241    }
242  } 
243
244  fn set_cyclic_trigger_interval(&mut self, interval : u32) -> PyResult<()> {
245    match TRIG_CYCLIC_INTERVAL.set(&mut self.ipbus, interval) {
246      Ok(_) =>  {
247        return Ok(());
248      }
249      Err(err) => {
250        return Err(PyValueError::new_err(err.to_string()));
251      }
252    }
253  }
254  
255  /// Issue a one-time forced trigger
256  fn trigger(&mut self) -> PyResult<()> {
257    match FORCE_TRIGGER.set(&mut self.ipbus, 1) {
258      Ok(_)  => {
259        return Ok(());
260      }
261      Err(err) => {
262        return Err(PyValueError::new_err(err.to_string()));
263      }
264    }
265  }
266
267  fn set_poisson_trigger(&mut self, rate : u32) -> PyResult<()> {
268    let clk_period = 100000000;
269    let rate_val   = (u32::MAX*rate)/clk_period;//(1.0/ clk_period)).floor() as u32;
270    match TRIG_GEN_RATE.set(&mut self.ipbus, rate_val) {
271      Ok(_)  => {
272        return Ok(());
273      }
274      Err(err) => {
275        return Err(PyValueError::new_err(err.to_string()));
276      }
277    }
278  }
279
280  fn set_gaps_track_trigger(&mut self, prescale : f32, use_beta : bool) -> PyResult<()>  {
281    match mt_api::control::set_gaps_track_trigger(&mut self.ipbus, prescale, use_beta) {
282      Ok(_) => {
283        return Ok(());
284      }
285      Err(err) => {
286        return Err(PyValueError::new_err(err.to_string()));
287      }
288    }
289  }
290  
291  fn set_gaps_any_trigger(&mut self, prescale : f32, use_beta : bool) -> PyResult<()>  {
292    match mt_api::control::set_gaps_any_trigger(&mut self.ipbus, prescale, use_beta) {
293      Ok(_) => {
294        return Ok(());
295      }
296      Err(err) => {
297        return Err(PyValueError::new_err(err.to_string()));
298      }
299    }
300  }
301
302  fn set_gaps_central_track_trigger(&mut self, prescale : f32, use_beta : bool) -> PyResult<()>  {
303    match mt_api::control::set_gaps_central_track_trigger(&mut self.ipbus, prescale, use_beta) {
304      Ok(_) => {
305        return Ok(());
306      }
307      Err(err) => {
308        return Err(PyValueError::new_err(err.to_string()));
309      }
310    }
311  }
312
313  fn set_gaps422_central_track_trigger(&mut self, prescale : f32, use_beta : bool) -> PyResult<()>  {
314    match mt_api::control::set_gaps422_central_track_trigger(&mut self.ipbus, prescale, use_beta) {
315      Ok(_) => {
316        return Ok(());
317      }
318      Err(err) => {
319        return Err(PyValueError::new_err(err.to_string()));
320      }
321    }
322  }
323
324  /// Get the status of enabling for LTBs 0-9
325  fn get_lt_link_en0(&mut self) -> PyResult<u32> {
326    match LT_LINK_EN0.get(&mut self.ipbus) {
327      Ok(value)  => {
328        return Ok(value);
329      }
330      Err(err) => {
331        return Err(PyValueError::new_err(err.to_string()));
332      }
333    }
334  }
335  /// Get the status of enabling for LTBs 10-19
336  fn get_lt_link_en1(&mut self) -> PyResult<u32> {
337    match LT_LINK_EN1.get(&mut self.ipbus) {
338      Ok(value)  => {
339        return Ok(value);
340      }
341      Err(err) => {
342        return Err(PyValueError::new_err(err.to_string()));
343      }
344    }
345  }
346  /// Get the status of enabling for LTBs 20-29
347  fn get_lt_link_en02(&mut self) -> PyResult<u32> {
348    match LT_LINK_EN2.get(&mut self.ipbus) {
349      Ok(value)  => {
350        return Ok(value);
351      }
352      Err(err) => {
353        return Err(PyValueError::new_err(err.to_string()));
354      }
355    }
356  }
357  /// Get the status of enabling for LTBs 30-39
358  fn get_lt_link_en3(&mut self) -> PyResult<u32> {
359    match LT_LINK_EN3.get(&mut self.ipbus) {
360      Ok(value)  => {
361        return Ok(value);
362      }
363      Err(err) => {
364        return Err(PyValueError::new_err(err.to_string()));
365      }
366    }
367  }
368  /// Get the status of enabling for LTBs 40-49
369  fn get_lt_link_en4(&mut self) -> PyResult<u32> {
370    match LT_LINK_EN4.get(&mut self.ipbus) {
371      Ok(value)  => {
372        return Ok(value);
373      }
374      Err(err) => {
375        return Err(PyValueError::new_err(err.to_string()));
376      }
377    }
378  }
379  ///Set on/off link enabling for LTBs 0-9
380  fn set_lt_link_en0(&mut self, value : u32) -> PyResult<u32> {
381    match LT_LINK_EN0.set(&mut self.ipbus, value) {
382      Ok(_) => {
383        return Ok(value);
384      }
385      Err(err) => {
386        return Err(PyValueError::new_err(err.to_string()));
387      }
388    }
389  }
390  ///Set on/off link enabling for LTBs 10-19
391  fn set_lt_link_en1(&mut self, value : u32) -> PyResult<u32> {
392    match LT_LINK_EN1.set(&mut self.ipbus, value) {
393      Ok(_) => {
394        return Ok(value);
395      }
396      Err(err) => {
397        return Err(PyValueError::new_err(err.to_string()));
398      }
399    }
400  }
401  ///Set on/off link enabling for LTBs 20-29
402  fn set_lt_link_en2(&mut self, value : u32) -> PyResult<u32> {
403    match LT_LINK_EN2.set(&mut self.ipbus, value) {
404      Ok(_) => {
405        return Ok(value);
406      }
407      Err(err) => {
408        return Err(PyValueError::new_err(err.to_string()));
409      }
410    }
411  }
412  ///Set on/off link enabling for LTBs 30-39
413  fn set_lt_link_en3(&mut self, value : u32) -> PyResult<u32> {
414    match LT_LINK_EN3.set(&mut self.ipbus, value) {
415      Ok(_) => {
416        return Ok(value);
417      }
418      Err(err) => {
419        return Err(PyValueError::new_err(err.to_string()));
420      }
421    }
422  }
423  ///Set on/off link enabling for LTBs 40-49
424  fn set_lt_link_en4(&mut self, value : u32) -> PyResult<u32> {
425    match LT_LINK_EN4.set(&mut self.ipbus, value) {
426      Ok(_) => {
427        return Ok(value);
428      }
429      Err(err) => {
430        return Err(PyValueError::new_err(err.to_string()));
431      }
432    }
433  }
434  ///get LT LINK AUTOMASK toggle status
435  fn get_lt_link_automask(&mut self) -> PyResult<bool> {
436    match LT_LINK_AUTOMASK.get(&mut self.ipbus) {
437      Ok(value) => {
438        return Ok(value != 0);
439      }
440      Err(err) => {
441        return Err(PyValueError::new_err(err.to_string()));
442      }
443    }
444  }
445  ///set LT LINK AUTOMASK toggle status
446  fn set_lt_link_automask(&mut self, toggle : bool) -> PyResult<bool> {
447    match LT_LINK_AUTOMASK.set(&mut self.ipbus, toggle as u32) {
448      Ok(_) => {
449        return Ok(true);
450      }
451      Err(err) => {
452        return Err(PyValueError::new_err(err.to_string()));
453      }
454    }
455  }
456fn get_gaps_trigger_prescale(&mut self) -> PyResult<f32> {
457  match GAPS_TRIG_PRESCALE.get(&mut self.ipbus) {
458    Ok (prescale_bus) => {
459      let prescale_val = (u32::MAX as f32 * prescale_bus as f32).floor() as f32;
460    return Ok(prescale_val)
461    }
462    Err(err) => {
463      return Err(PyValueError::new_err(err.to_string()));
464    }
465  }
466}
467
468fn set_gaps_trigger_prescale(&mut self, prescale : f32) -> PyResult<f32> {
469  let prescale_val = (f32::MAX * prescale as f32).floor() as u32;
470  match GAPS_TRIG_PRESCALE.set(&mut self.ipbus, prescale_val) {
471    Ok(_) => {
472      return Ok(prescale)
473    }
474    Err(err) => {
475      return Err(PyValueError::new_err(err.to_string()));
476    }
477  }
478}
479
480fn set_track_trigger_is_global(&mut self) -> PyResult<()> {
481    match TRACK_CENTRAL_IS_GLOBAL.set(&mut self.ipbus, 1) {
482      Ok(_) => {
483        return Ok(());
484      }
485      Err(err) => {
486        return Err(PyValueError::new_err(err.to_string()));
487      }
488    }
489  }
490
491
492  fn get_ltb_links_ready(&mut self) -> PyResult<HashMap<u8, u32>> {
493    let registers = [LT_LINK_READY0, LT_LINK_READY1,
494                     LT_LINK_READY2, LT_LINK_READY3,
495                     LT_LINK_READY4];
496    let mut ready = HashMap::<u8, u32>::new();
497    for (k,reg) in registers.iter().enumerate() {
498      match reg.get(&mut self.ipbus) {
499        Err(err) => {
500          return Err(PyValueError::new_err(err.to_string()));
501        }
502        Ok(cnt) => {
503          ready.insert(k as u8, cnt);
504        }
505      }
506    }
507    Ok(ready)
508  }
509
510  fn get_ltb_event_cnts(&mut self) -> PyResult<HashMap<u8, u32>> {
511    let registers = [LT0, LT1, LT2, LT3, LT4, LT5, LT6, LT7, LT8, LT9,
512                     LT10, LT11, LT12, LT13, LT14, LT15, LT16, LT17, LT18, LT19,
513                     LT20, LT21, LT22, LT23, LT24];
514    let mut counters = HashMap::<u8, u32>::new();
515    for (k,reg) in registers.iter().enumerate() {
516      match reg.get(&mut self.ipbus) {
517        Err(err) => {
518          return Err(PyValueError::new_err(err.to_string()));
519        }
520        Ok(cnt) => {
521          counters.insert(k as u8, cnt);
522        }
523      }
524    }
525    // print a table
526    let mut table = Table::new();
527    table
528      .load_preset(UTF8_FULL)
529      .apply_modifier(UTF8_ROUND_CORNERS)
530      .set_content_arrangement(ContentArrangement::Dynamic)
531      .set_width(80)
532      .set_header(vec!["LT 0", "LT 1", "LT 2", "LT 3", "LT 4"])
533      .add_row(vec![
534          Cell::new(&(format!("{}", counters[&0]))),
535          Cell::new(&(format!("{}", counters[&1]))),
536          Cell::new(&(format!("{}", counters[&2]))),
537          Cell::new(&(format!("{}", counters[&3]))),
538          Cell::new(&(format!("{}", counters[&4]))),
539          //Cell::new("Center aligned").set_alignment(CellAlignment::Center),
540      ])
541      .add_row(vec![
542          Cell::new(String::from("LT 5")),
543          Cell::new(String::from("LT 6")),
544          Cell::new(String::from("LT 7")),
545          Cell::new(String::from("LT 8")),
546          Cell::new(String::from("LT 9")),
547      ])
548      .add_row(vec![
549          Cell::new(&(format!("{}", counters[&5]))),
550          Cell::new(&(format!("{}", counters[&6]))),
551          Cell::new(&(format!("{}", counters[&7]))),
552          Cell::new(&(format!("{}", counters[&8]))),
553          Cell::new(&(format!("{}", counters[&9]))),
554      ])
555      .add_row(vec![
556          Cell::new(String::from("LT 10")),
557          Cell::new(String::from("LT 11")),
558          Cell::new(String::from("LT 12")),
559          Cell::new(String::from("LT 13")),
560          Cell::new(String::from("LT 14")),
561      ])
562      .add_row(vec![
563          Cell::new(&(format!("{}", counters[&10]))),
564          Cell::new(&(format!("{}", counters[&11]))),
565          Cell::new(&(format!("{}", counters[&12]))),
566          Cell::new(&(format!("{}", counters[&13]))),
567          Cell::new(&(format!("{}", counters[&14]))),
568      ])
569      .add_row(vec![
570          Cell::new(String::from("LT 15")),
571          Cell::new(String::from("LT 16")),
572          Cell::new(String::from("LT 17")),
573          Cell::new(String::from("LT 18")),
574          Cell::new(String::from("LT 19")),
575      ])
576      .add_row(vec![
577          Cell::new(&(format!("{}", counters[&15]))),
578          Cell::new(&(format!("{}", counters[&16]))),
579          Cell::new(&(format!("{}", counters[&17]))),
580          Cell::new(&(format!("{}", counters[&18]))),
581          Cell::new(&(format!("{}", counters[&19]))),
582      ])
583      .add_row(vec![
584          Cell::new(String::from("LT 20")),
585          Cell::new(String::from("LT 21")),
586          Cell::new(String::from("LT 22")),
587          Cell::new(String::from("LT 23")),
588          Cell::new(String::from("LT 24")),
589      ])
590      .add_row(vec![
591          Cell::new(&(format!("{}", counters[&20]))),
592          Cell::new(&(format!("{}", counters[&21]))),
593          Cell::new(&(format!("{}", counters[&22]))),
594          Cell::new(&(format!("{}", counters[&23]))),
595          Cell::new(&(format!("{}", counters[&24]))),
596      ]);
597
598    // Set the default alignment for the third column to right
599    let column = table.column_mut(2).expect("Our table has three columns");
600    column.set_cell_alignment(CellAlignment::Right);
601    println!("{table}");
602    Ok(counters)
603  }
604  
605  /// Readout the RB event counter registers
606  fn get_rb_event_cnts(&mut self) -> PyResult<HashMap<u8, u8>> {
607    let registers = [RB0_CNTS, RB1_CNTS, RB2_CNTS, RB3_CNTS, RB4_CNTS,
608                     RB5_CNTS, RB6_CNTS, RB7_CNTS, RB8_CNTS, RB9_CNTS,
609                     RB10_CNTS, RB11_CNTS, RB12_CNTS, RB13_CNTS, RB14_CNTS,
610                     RB15_CNTS, RB16_CNTS, RB17_CNTS, RB18_CNTS, RB19_CNTS,
611                     RB20_CNTS, RB21_CNTS, RB22_CNTS, RB23_CNTS, RB24_CNTS,
612                     RB25_CNTS, RB26_CNTS, RB27_CNTS, RB28_CNTS, RB29_CNTS,
613                     RB30_CNTS, RB31_CNTS, RB32_CNTS, RB33_CNTS, RB34_CNTS,
614                     RB35_CNTS, RB36_CNTS, RB37_CNTS, RB38_CNTS, RB39_CNTS,
615                     RB40_CNTS, RB41_CNTS, RB42_CNTS, RB43_CNTS, RB44_CNTS,
616                     RB45_CNTS, RB46_CNTS, RB47_CNTS, RB48_CNTS, RB49_CNTS];
617    let mut counters = HashMap::<u8, u8>::new();
618    for (k,reg) in registers.iter().enumerate() {
619      match reg.get(&mut self.ipbus) {
620        Err(err) => {
621          return Err(PyValueError::new_err(err.to_string()));
622        }
623        Ok(cnt) => {
624          counters.insert(k as u8, cnt as u8);
625        }
626      }
627    }
628    let mut table = Table::new();
629    table
630      .load_preset(UTF8_FULL)
631      .apply_modifier(UTF8_ROUND_CORNERS)
632      .set_content_arrangement(ContentArrangement::Dynamic)
633      .set_width(60)
634      .set_header(vec!["RB 0", "RB 1", "RB 2", "RB 3", "RB 4"])
635      .add_row(vec![
636          Cell::new(&(format!("{}", counters[&0]))),
637          Cell::new(&(format!("{}", counters[&1]))),
638          Cell::new(&(format!("{}", counters[&2]))),
639          Cell::new(&(format!("{}", counters[&3]))),
640          Cell::new(&(format!("{}", counters[&4]))),
641          //Cell::new("Center aligned").set_alignment(CellAlignment::Center),
642      ])
643      .add_row(vec![
644          Cell::new(String::from("RB 5")),
645          Cell::new(String::from("RB 6")),
646          Cell::new(String::from("RB 7")),
647          Cell::new(String::from("RB 8")),
648          Cell::new(String::from("RB 9")),
649      ])
650      .add_row(vec![
651          Cell::new(&(format!("{}", counters[&5]))),
652          Cell::new(&(format!("{}", counters[&6]))),
653          Cell::new(&(format!("{}", counters[&7]))),
654          Cell::new(&(format!("{}", counters[&8]))),
655          Cell::new(&(format!("{}", counters[&9]))),
656      ])
657      .add_row(vec![
658          Cell::new(String::from("RB 10")),
659          Cell::new(String::from("RB 11")),
660          Cell::new(String::from("RB 12")),
661          Cell::new(String::from("RB 13")),
662          Cell::new(String::from("RB 14")),
663      ])
664      .add_row(vec![
665          Cell::new(&(format!("{}", counters[&10]))),
666          Cell::new(&(format!("{}", counters[&11]))),
667          Cell::new(&(format!("{}", counters[&12]))),
668          Cell::new(&(format!("{}", counters[&13]))),
669          Cell::new(&(format!("{}", counters[&14]))),
670      ])
671      .add_row(vec![
672          Cell::new(String::from("RB 15")),
673          Cell::new(String::from("RB 16")),
674          Cell::new(String::from("RB 17")),
675          Cell::new(String::from("RB 18")),
676          Cell::new(String::from("RB 19")),
677      ])
678      .add_row(vec![
679          Cell::new(&(format!("{}", counters[&15]))),
680          Cell::new(&(format!("{}", counters[&16]))),
681          Cell::new(&(format!("{}", counters[&17]))),
682          Cell::new(&(format!("{}", counters[&18]))),
683          Cell::new(&(format!("{}", counters[&19]))),
684      ])
685      .add_row(vec![
686          Cell::new(String::from("RB 20")),
687          Cell::new(String::from("RB 21")),
688          Cell::new(String::from("RB 22")),
689          Cell::new(String::from("RB 23")),
690          Cell::new(String::from("RB 24")),
691      ])
692      .add_row(vec![
693          Cell::new(&(format!("{}", counters[&20]))),
694          Cell::new(&(format!("{}", counters[&21]))),
695          Cell::new(&(format!("{}", counters[&22]))),
696          Cell::new(&(format!("{}", counters[&23]))),
697          Cell::new(&(format!("{}", counters[&24]))),
698      ])
699      .add_row(vec![
700          Cell::new(String::from("RB 25")),
701          Cell::new(String::from("RB 26")),
702          Cell::new(String::from("RB 27")),
703          Cell::new(String::from("RB 28")),
704          Cell::new(String::from("RB 29")),
705      ])
706      .add_row(vec![
707          Cell::new(&(format!("{}", counters[&25]))),
708          Cell::new(&(format!("{}", counters[&26]))),
709          Cell::new(&(format!("{}", counters[&27]))),
710          Cell::new(&(format!("{}", counters[&28]))),
711          Cell::new(&(format!("{}", counters[&29]))),
712      ])
713      .add_row(vec![
714          Cell::new(String::from("RB 30")),
715          Cell::new(String::from("RB 31")),
716          Cell::new(String::from("RB 32")),
717          Cell::new(String::from("RB 33")),
718          Cell::new(String::from("RB 34")),
719      ])
720      .add_row(vec![
721          Cell::new(&(format!("{}", counters[&30]))),
722          Cell::new(&(format!("{}", counters[&31]))),
723          Cell::new(&(format!("{}", counters[&32]))),
724          Cell::new(&(format!("{}", counters[&33]))),
725          Cell::new(&(format!("{}", counters[&34]))),
726      ])
727      .add_row(vec![
728          Cell::new(String::from("RB 35")),
729          Cell::new(String::from("RB 36")),
730          Cell::new(String::from("RB 37")),
731          Cell::new(String::from("RB 38")),
732          Cell::new(String::from("RB 39")),
733      ])
734      .add_row(vec![
735          Cell::new(&(format!("{}", counters[&35]))),
736          Cell::new(&(format!("{}", counters[&36]))),
737          Cell::new(&(format!("{}", counters[&37]))),
738          Cell::new(&(format!("{}", counters[&38]))),
739          Cell::new(&(format!("{}", counters[&39]))),
740      ])
741      .add_row(vec![
742          Cell::new(String::from("RB 40")),
743          Cell::new(String::from("RB 41")),
744          Cell::new(String::from("RB 42")),
745          Cell::new(String::from("RB 43")),
746          Cell::new(String::from("RB 44")),
747      ])
748      .add_row(vec![
749          Cell::new(&(format!("{}", counters[&40]))),
750          Cell::new(&(format!("{}", counters[&41]))),
751          Cell::new(&(format!("{}", counters[&42]))),
752          Cell::new(&(format!("{}", counters[&43]))),
753          Cell::new(&(format!("{}", counters[&44]))),
754      ])
755      .add_row(vec![
756          Cell::new(String::from("RB 45")),
757          Cell::new(String::from("RB 46")),
758          Cell::new(String::from("RB 47")),
759          Cell::new(String::from("RB 48")),
760          Cell::new(String::from("RB 49")),
761      ])
762      .add_row(vec![
763          Cell::new(&(format!("{}", counters[&45]))),
764          Cell::new(&(format!("{}", counters[&46]))),
765          Cell::new(&(format!("{}", counters[&47]))),
766          Cell::new(&(format!("{}", counters[&48]))),
767          Cell::new(&(format!("{}", counters[&49]))),
768      ]);
769
770    // Set the default alignment for the third column to right
771    let column = table.column_mut(2).expect("Our table has three columns");
772    column.set_cell_alignment(CellAlignment::Right);
773    println!("{table}");
774    Ok(counters)
775  }
776  
777  /// Reset all the RB counters
778  fn reset_rb_counters(&mut self) -> PyResult<()> {
779    println!("{}", RB_CNTS_RESET);
780    match RB_CNTS_RESET.set(&mut self.ipbus, 1) {
781      Ok(_) => {
782        return Ok(());
783      }
784      Err(err) => {
785        return Err(PyValueError::new_err(err.to_string()));
786      }
787    }
788  }
789
790  /// Reset all the LTB counters
791  fn reset_ltb_counters(&mut self) -> PyResult<()> {
792    match LT_HIT_CNT_RESET.set(&mut self.ipbus, 1) {
793      Ok(_) => {
794        return Ok(());
795      }
796      Err(err) => {
797        return Err(PyValueError::new_err(err.to_string()));
798      }
799    }
800  }
801  
802  /// Set a channel mask for a LTB. 
803  ///
804  /// # Arguments
805  /// * lt_link : 0-24, dsi/j connection of the LTB on the MTB
806  /// * mask    : bitmask 1 = ch0 2 = ch1, etc. setting a channel
807  ///             to 1 will DISABLE the channel!
808  fn set_ltb_ch_mask(&mut self, lt_link : u8, mask : u8) -> PyResult<()> {
809    let registers = [LT0_CHMASK, LT1_CHMASK, LT2_CHMASK, LT3_CHMASK, LT4_CHMASK,
810                     LT5_CHMASK, LT6_CHMASK, LT7_CHMASK, LT8_CHMASK, LT9_CHMASK,
811                     LT10_CHMASK, LT11_CHMASK, LT12_CHMASK, LT13_CHMASK, LT14_CHMASK,
812                     LT15_CHMASK, LT16_CHMASK, LT17_CHMASK, LT18_CHMASK, LT19_CHMASK,
813                     LT20_CHMASK, LT21_CHMASK, LT22_CHMASK, LT23_CHMASK, LT24_CHMASK];
814    if lt_link as usize > registers.len() {
815      return Err(PyValueError::new_err(String::from("Mask has to be in range 0-24!")));
816    }
817
818    match registers[lt_link as usize].set(&mut self.ipbus, mask as u32) {
819      Ok(_) => {
820        return Ok(());
821      }
822      Err(err) => {
823        return Err(PyValueError::new_err(err.to_string()));
824      }
825    }
826  }
827
828  
829  fn set_trace_suppression(&mut self, trace_sup : bool) -> PyResult<()> {
830    let read_all_rb : u32;
831    if trace_sup {
832      read_all_rb = 0;
833    } else {
834      read_all_rb = 1;
835    }
836    match RB_READ_ALL_CHANNELS.set(&mut self.ipbus, read_all_rb) {
837      Ok(_)  => {
838        Ok(())
839      }
840      Err(err) => {
841        return Err(PyValueError::new_err(err.to_string()));
842      }
843    }
844  }
845
846  fn get_trace_suppression(&mut self) -> PyResult<u32> {
847    match RB_READ_ALL_CHANNELS.get(&mut self.ipbus) {
848      Ok(cnt) => {
849        return Ok(cnt);
850      }
851      Err(err) => {
852        return Err(PyValueError::new_err(err.to_string()));
853      }
854    }
855  }
856  
857  fn set_total_tof_thresh(&mut self, value : u32) -> PyResult<()> {
858    match TOTAL_TOF_THRESH.set(&mut self.ipbus, value) {
859      Ok(_)  => {
860        Ok(())
861      }
862      Err(err) => {
863        return Err(PyValueError::new_err(err.to_string()));
864      }
865    }
866  }
867
868  fn get_total_tof_thresh(&mut self) -> PyResult<u32> {
869    match TOTAL_TOF_THRESH.get(&mut self.ipbus) {
870      Ok(cnt) => {
871        return Ok(cnt);
872      }
873      Err(err) => {
874        return Err(PyValueError::new_err(err.to_string()));
875      }
876    }
877  }
878  
879  fn set_inner_tof_thresh(&mut self, value : u32) -> PyResult<()> {
880    match INNER_TOF_THRESH.set(&mut self.ipbus, value) {
881      Ok(_) =>  {
882        return Ok(());
883      }
884      Err(err) => {
885        return Err(PyValueError::new_err(err.to_string()));
886      }
887    }
888  }
889
890  fn get_inner_tof_thresh(&mut self) -> PyResult<u32> {
891    match INNER_TOF_THRESH.get(&mut self.ipbus) {
892      Ok(cnt) => {
893        return Ok(cnt);
894      }
895      Err(err) => {
896        return Err(PyValueError::new_err(err.to_string()));
897      }
898    }
899  }
900
901  fn set_outer_tof_thresh(&mut self, value : u32) -> PyResult<()> {
902    match OUTER_TOF_THRESH.set(&mut self.ipbus, value) {
903      Ok(_) =>  {
904        return Ok(());
905      }
906      Err(err) => {
907        return Err(PyValueError::new_err(err.to_string()));
908      }
909    }
910  }
911
912  fn get_outer_tof_thresh(&mut self) -> PyResult<u32> {
913    match OUTER_TOF_THRESH.get(&mut self.ipbus) {
914      Ok(cnt) => {
915        return Ok(cnt);
916      }
917      Err(err) => {
918        return Err(PyValueError::new_err(err.to_string()));
919      }
920    }
921  }
922
923  fn set_cube_side_thresh(&mut self, value : u32) -> PyResult<()> {
924    match CUBE_SIDE_THRESH.set(&mut self.ipbus, value) {
925      Ok(_) =>  {
926        return Ok(());
927      }
928      Err(err) => {
929        return Err(PyValueError::new_err(err.to_string()));
930      }
931    }
932  }
933
934  fn get_cube_side_thresh(&mut self) -> PyResult<u32> {
935    match CUBE_SIDE_THRESH.get(&mut self.ipbus) {
936      Ok(cnt) => {
937        return Ok(cnt);
938      }
939      Err(err) => {
940        return Err(PyValueError::new_err(err.to_string()));
941      }
942    }
943  }
944
945  fn set_cube_top_thresh(&mut self, value : u32) -> PyResult<()> {
946    match CUBE_TOP_THRESH.set(&mut self.ipbus, value) {
947      Ok(_) =>  {
948        return Ok(());
949      }
950      Err(err) => {
951        return Err(PyValueError::new_err(err.to_string()));
952      }
953    }
954  }
955
956  fn get_cube_top_thresh(&mut self) -> PyResult<u32> {
957    match CUBE_TOP_THRESH.get(&mut self.ipbus) {
958      Ok(cnt) => {
959        return Ok(cnt);
960      }
961      Err(err) => {
962        return Err(PyValueError::new_err(err.to_string()));
963      }
964    }
965  }
966
967  fn set_cube_bot_thresh(&mut self, value : u32) -> PyResult<()> {
968    match CUBE_BOT_THRESH.set(&mut self.ipbus, value) {
969      Ok(_) =>  {
970        return Ok(());
971      }
972      Err(err) => {
973        return Err(PyValueError::new_err(err.to_string()));
974      }
975    }
976  }
977
978  fn get_cube_bot_thresh(&mut self) -> PyResult<u32> {
979    match CUBE_BOT_THRESH.get(&mut self.ipbus) {
980      Ok(cnt) => {
981        return Ok(cnt);
982      }
983      Err(err) => {
984        return Err(PyValueError::new_err(err.to_string()));
985      }
986    }
987  }
988
989  fn set_cube_corner_thresh(&mut self, value : u32) -> PyResult<()> {
990    match CUBE_CORNER_THRESH.set(&mut self.ipbus, value) {
991      Ok(_) =>  {
992        return Ok(());
993      }
994      Err(err) => {
995        return Err(PyValueError::new_err(err.to_string()));
996      }
997    }
998  }
999
1000  fn get_cube_corner_thresh(&mut self) -> PyResult<u32> {
1001    match CUBE_CORNER_THRESH.get(&mut self.ipbus) {
1002      Ok(cnt) => {
1003        return Ok(cnt);
1004      }
1005      Err(err) => {
1006        return Err(PyValueError::new_err(err.to_string()));
1007      }
1008    }
1009  }
1010 
1011  fn set_umbrella_thresh(&mut self, value : u32) -> PyResult<()> {
1012    match UMBRELLA_THRESH.set(&mut self.ipbus, value) {
1013      Ok(_) =>  {
1014        return Ok(());
1015      }
1016      Err(err) => {
1017        return Err(PyValueError::new_err(err.to_string()));
1018      }
1019    }
1020  }
1021
1022  fn get_umbrella_thresh(&mut self) -> PyResult<u32> {
1023    match UMBRELLA_THRESH.get(&mut self.ipbus) {
1024      Ok(cnt) => {
1025        return Ok(cnt);
1026      }
1027      Err(err) => {
1028        return Err(PyValueError::new_err(err.to_string()));
1029      }
1030    }
1031  }
1032
1033  fn set_umbrella_center_thresh(&mut self, value : u32) -> PyResult<()> {
1034    match UMBRELLA_CENTER_THRESH.set(&mut self.ipbus, value) {
1035      Ok(_) =>  {
1036        return Ok(());
1037      }
1038      Err(err) => {
1039        return Err(PyValueError::new_err(err.to_string()));
1040      }
1041    }
1042  }
1043
1044  fn get_umbrella_center_thresh(&mut self) -> PyResult<u32> {
1045    match UMBRELLA_CENTER_THRESH.get(&mut self.ipbus) {
1046      Ok(cnt) => {
1047        return Ok(cnt);
1048      }
1049      Err(err) => {
1050        return Err(PyValueError::new_err(err.to_string()));
1051      }
1052    }
1053  }
1054
1055  fn set_cortina_thresh(&mut self, value : u32) -> PyResult<()> {
1056    match CORTINA_THRESH.set(&mut self.ipbus, value) {
1057      Ok(_) =>  {
1058        return Ok(());
1059      }
1060      Err(err) => {
1061        return Err(PyValueError::new_err(err.to_string()));
1062      }
1063    }
1064  }
1065  
1066  fn get_cortina_thresh(&mut self) -> PyResult<u32> {
1067    match CORTINA_THRESH.get(&mut self.ipbus) {
1068      Ok(cnt) => {
1069        return Ok(cnt);
1070      }
1071      Err(err) => {
1072        return Err(PyValueError::new_err(err.to_string()));
1073      }
1074    }
1075  }
1076
1077  fn set_configurable_trigger(&mut self, value : u32) -> PyResult<()> {
1078    match CONFIGURABLE_TRIGGER_EN.set(&mut self.ipbus, value) {
1079      Ok(_) => {
1080        return Ok(());
1081      }
1082      Err(err) => {
1083        return Err(PyValueError::new_err(err.to_string()));
1084      }
1085    }
1086  }
1087  
1088  fn get_configurable_trigger(&mut self) -> PyResult<u32> {
1089    match CONFIGURABLE_TRIGGER_EN.get(&mut self.ipbus) {
1090      Ok(cnt) => {
1091        return Ok(cnt);
1092      }
1093      Err(err) => {
1094        return Err(PyValueError::new_err(err.to_string()));
1095      }
1096    }
1097  }
1098
1099  fn set_any_trigger(&mut self, prescale : u32) -> PyResult<()> {
1100    match ANY_TRIG_PRESCALE.set(&mut self.ipbus, prescale) {
1101      Ok(_) =>  {
1102        return Ok(());
1103      }
1104      Err(err) => {
1105        return Err(PyValueError::new_err(err.to_string()));
1106      }
1107    }
1108  }
1109
1110  fn set_track_trigger(&mut self, prescale : u32) -> PyResult<()> {
1111    match TRACK_TRIG_PRESCALE.set(&mut self.ipbus, prescale) {
1112      Ok(_) =>  {
1113        return Ok(());
1114      }
1115      Err(err) => {
1116        return Err(PyValueError::new_err(err.to_string()));
1117      }
1118    }
1119  }
1120  
1121  fn set_central_track_trigger(&mut self, prescale : u32) -> PyResult<()> {
1122    match TRACK_CENTRAL_PRESCALE.set(&mut self.ipbus, prescale) {
1123      Ok(_) =>  {
1124        return Ok(());
1125      }
1126      Err(err) => {
1127        return Err(PyValueError::new_err(err.to_string()));
1128      }
1129    }
1130  }
1131
1132  fn use_tiu_aux_link(&mut self, use_it : bool) -> PyResult<()> {
1133    match mt_api::control::use_tiu_aux_link(&mut self.ipbus, use_it) {
1134      Ok(_) => {
1135        return Ok(());
1136      }
1137      Err(err) => {
1138        return Err(PyValueError::new_err(err.to_string()));
1139      }
1140    }
1141  }
1142
1143  fn stop_all_triggers(&mut self) -> PyResult<()> {
1144    match mt_api::control::unset_all_triggers(&mut self.ipbus) {
1145      Ok(_) => {
1146        return Ok(());
1147      }
1148      Err(err) => {
1149        return Err(PyValueError::new_err(err.to_string()));
1150      }
1151    }
1152  }
1153
1154  fn set_umbcube_trigger(&mut self) -> PyResult<()> {
1155    match mt_api::control::set_umbcube_trigger(&mut self.ipbus) {
1156      Ok(_) => {
1157        return Ok(());
1158      }
1159      Err(err) => {
1160        return Err(PyValueError::new_err(err.to_string()));
1161      }
1162    }
1163  }
1164  
1165  fn set_umbcubez_trigger(&mut self) -> PyResult<()> {
1166    match mt_api::control::set_umbcubez_trigger(&mut self.ipbus) {
1167      Ok(_) => {
1168        return Ok(());
1169      }
1170      Err(err) => {
1171        return Err(PyValueError::new_err(err.to_string()));
1172      }
1173    }
1174  }
1175
1176  fn set_umbcorcube_trigger(&mut self) -> PyResult<()> {
1177    match mt_api::control::set_umbcorcube_trigger(&mut self.ipbus) {
1178      Ok(_) => {
1179        return Ok(());
1180      }
1181      Err(err) => {
1182        return Err(PyValueError::new_err(err.to_string()));
1183      }
1184    }
1185  }
1186
1187  fn set_corcubeside_trigger(&mut self) -> PyResult<()> {
1188    match mt_api::control::set_corcubeside_trigger(&mut self.ipbus) {
1189      Ok(_) => {
1190        return Ok(());
1191      }
1192      Err(err) => {
1193        return Err(PyValueError::new_err(err.to_string()));
1194      }
1195    }
1196  }
1197  
1198  fn set_umb3cube_trigger(&mut self) -> PyResult<()> {
1199    match mt_api::control::set_umb3cube_trigger(&mut self.ipbus) {
1200      Ok(_) => {
1201        return Ok(());
1202      }
1203      Err(err) => {
1204        return Err(PyValueError::new_err(err.to_string()));
1205      }
1206    }
1207  }
1208
1209  #[getter]
1210  fn get_tiu_busy_ignore(&mut self) -> PyResult<bool> {
1211    match TIU_BUSY_IGNORE.get(&mut self.ipbus) {
1212      Ok(bsy) => {
1213        let res = bsy != 0;
1214        return Ok(res);
1215      }
1216      Err(err) => {
1217        return Err(PyValueError::new_err(err.to_string()));
1218      }
1219    }
1220  }
1221  
1222  #[setter]
1223  fn set_tiu_busy_ignore(&mut self, bsy : bool) -> PyResult<()> {
1224    match TIU_BUSY_IGNORE.set(&mut self.ipbus, bsy as u32) {
1225      Ok(_) => {
1226        return Ok(());
1227      }
1228      Err(err) => {
1229        return Err(PyValueError::new_err(err.to_string()));
1230      }
1231    }
1232  }
1233
1234  #[getter]
1235  fn get_tiu_busy_stuck(&mut self) -> PyResult<bool> {
1236    match TIU_BUSY_STUCK.get(&mut self.ipbus) {
1237      Ok(value) => {
1238        return Ok(value > 0);
1239      }
1240      Err(err) => {
1241        return Err(PyValueError::new_err(err.to_string()));
1242      }
1243    }
1244  }
1245
1246  #[getter]
1247  fn get_tiu_bad(&mut self) -> PyResult<bool> {
1248    match TIU_BAD.get(&mut self.ipbus) {
1249      Ok(value) => {
1250        return Ok(value > 0);
1251      }
1252      Err(err) => {
1253        return Err(PyValueError::new_err(err.to_string()));
1254      }
1255    }
1256  }
1257
1258  fn get_event_cnt(&mut self) -> PyResult<u32> {
1259    match EVENT_CNT.get(&mut self.ipbus) {
1260      Ok(cnt) => {
1261        return Ok(cnt);
1262      }
1263      Err(err) => {
1264        return Err(PyValueError::new_err(err.to_string()));
1265      }
1266    }
1267  }
1268  
1269  fn get_event_queue_size(&mut self)
1270    -> PyResult<u32> {
1271    match EVQ_SIZE.get(&mut self.ipbus) {
1272      Ok(cnt) => {
1273        return Ok(cnt);
1274      }
1275      Err(err) => {
1276        return Err(PyValueError::new_err(err.to_string()));
1277      }
1278    }
1279  }
1280  
1281  fn get_event_queue_full(&mut self)
1282    -> PyResult<u32> {
1283    match EVQ_FULL.get(&mut self.ipbus) {
1284      Ok(cnt) => {
1285        return Ok(cnt);
1286      }
1287      Err(err) => {
1288        return Err(PyValueError::new_err(err.to_string()));
1289      }
1290    }
1291  }
1292
1293  fn get_nevents_in_queue(&mut self) 
1294    -> PyResult<u32> {
1295    match EVQ_NUM_EVENTS.get(&mut self.ipbus) {
1296      Ok(cnt) => {
1297        return Ok(cnt);
1298      }
1299      Err(err) => {
1300        return Err(PyValueError::new_err(err.to_string()));
1301      }
1302    }
1303  }
1304
1305  
1306
1307  fn get_event(&mut self, read_until_footer : bool, verbose : bool, debug : bool)
1308    -> PyResult<PyMasterTriggerEvent> {
1309    let use_dbg_version = debug;
1310    if !use_dbg_version {
1311      let mut event = PyMasterTriggerEvent::new();
1312      match mt_api::get_event(&mut self.ipbus) {
1313        None => {
1314          // we just return an empty event!
1315          //warn!("Did not get an event, returning empty event!");
1316          Ok(event)
1317        }
1318        Some(Err(err)) => {
1319          //error!("Unable to obtain event from the MTB!");
1320          return Err(PyValueError::new_err(err.to_string()));
1321        }
1322        Some(Ok(mte)) => {
1323          event.set_event(mte);
1324          Ok(event)
1325        }
1326      }
1327    } else {
1328      // This can be great for debugging. However, at some point 
1329      // I'd like to introduce debugging features and have all 
1330      // the debugging at the same place
1331      let mut n_daq_words : u16;
1332      let mut n_daq_words_actual : u16;
1333      loop {
1334        match EVQ_NUM_EVENTS.get(&mut self.ipbus) {
1335          Err(_err) => {
1336            continue;
1337          }
1338          Ok(nevents_in_q) => {
1339            if nevents_in_q == 0 {
1340              if verbose {
1341                println!("[MasterTrigger::get_event] => EventQueue empty!!");
1342              }
1343              return Err(PyValueError::new_err(String::from("<MasterTriggerError: EventQueueEmpty>")));
1344            }
1345          }
1346        }
1347        match self.ipbus.read(0x13) { 
1348          Err(_err) => {
1349            // A timeout does not ncecessarily mean that there 
1350            // is no event, it can also just mean that 
1351            // the rate is low.
1352            //trace!("Timeout in read_register for MTB! {err}");
1353            continue;
1354          },
1355          Ok(_n_words) => {
1356            n_daq_words = (_n_words >> 16) as u16;
1357            if _n_words == 0 {
1358              continue;
1359            }
1360            //trace!("Got n_daq_words {n_daq_words}");
1361            let rest = n_daq_words % 2;
1362            n_daq_words /= 2 + rest; //mtb internally operates in 16bit words, but 
1363            //                  //registers return 32bit words.
1364            
1365            break;
1366          }
1367        }
1368      }
1369      let mut data : Vec<u32>;
1370      if verbose {
1371        println!("[MasterTrigger::get_event] => Will query DAQ for {n_daq_words} words!");
1372      }
1373      n_daq_words_actual = n_daq_words;
1374      match self.ipbus.read_multiple(
1375                                     0x11,
1376                                     n_daq_words as usize,
1377                                     false) {
1378        Err(err) => {
1379          if verbose {
1380            println!("[MasterTrigger::get_event] => failed! {err}");
1381          }
1382          return Err(PyValueError::new_err(err.to_string()));
1383        }
1384        Ok(_data) => {
1385          data = _data;
1386          for (i,word) in data.iter().enumerate() {
1387            let desc : &str;
1388            let desc_str : String;
1389            //let mut nhit_words = 0;
1390            match i {
1391              0 => desc = "HEADER",
1392              1 => desc = "EVENTID",
1393              2 => desc = "TIMESTAMP",
1394              3 => desc = "TIU_TIMESTAMP",
1395              4 => desc = "TIU_GPS32",
1396              5 => desc = "TIU_GPS16 + TRIG_SOURCE",
1397              6 => desc = "RB MASK 0",
1398              7 => desc = "RB MASK 1",
1399              8 => {
1400                //nhit_words = nhit_words / 2 + nhit_words % 2;
1401                desc_str  = format!("BOARD MASK ({} ltbs)", word.count_ones());
1402                desc  = &desc_str;
1403              },
1404              _ => desc = "?"
1405            }
1406            if verbose {
1407              println!("[MasterTrigger::get_event] => DAQ word {}    \t({:x})    \t[{}]", word, word, desc);
1408            }
1409          }
1410        }
1411      }
1412      if data[0] != 0xAAAAAAAA {
1413        if verbose {
1414          println!("[MasterTrigger::get_event] => Got MTB data, but the header is incorrect {}", data[0]);
1415        }
1416        return Err(PyValueError::new_err(String::from("Incorrect header value!")));
1417      }
1418      let foot_pos = (n_daq_words - 1) as usize;
1419      if data.len() <= foot_pos {
1420        if verbose {
1421          println!("[MasterTrigger::get_event] => Got MTB data, but the format is not correct");
1422        }
1423        return Err(PyValueError::new_err(String::from("Empty data!")));
1424      }
1425      if data[foot_pos] != 0x55555555 {
1426        if verbose {
1427          println!("[MasterTrigger::get_event] => Did not read unti footer!");
1428        }
1429        if read_until_footer {
1430          if verbose {
1431            println!("[MasterTrigger::get_event] => .. will read additional words!");
1432          }
1433          loop {
1434            match self.ipbus.read(0x11) {
1435              Err(err) => {
1436                if verbose {
1437                  println!("[MasterTrigger::get_event] => Issues reading from 0x11");
1438                }
1439                return Err(PyValueError::new_err(err.to_string()));
1440              },
1441              Ok(next_word) => {
1442                n_daq_words_actual += 1;
1443                data.push(next_word);
1444                if next_word == 0x55555555 {
1445                  break;
1446                }
1447              }
1448            }
1449          }
1450          if verbose {
1451            println!("[MasterTrigger::get_event] => We read {} additional words!", n_daq_words_actual - n_daq_words);
1452          }
1453        } else {
1454          if verbose {
1455            println!("[MasterTrigger::get_event] => Got MTB data, but the footer is incorrect {}", data[foot_pos]);
1456          }
1457          return Err(PyValueError::new_err(String::from("Footer incorrect!")));
1458        }
1459      }
1460
1461      // Number of words which will be always there. 
1462      // Min event size is +1 word for hits
1463      //const MTB_DAQ_PACKET_FIXED_N_WORDS : u32 = 9; 
1464      //let n_hit_packets = n_daq_words as u32 - MTB_DAQ_PACKET_FIXED_N_WORDS;
1465      //println!("We are expecting {}", n_hit_packets);
1466      let mut mte = MasterTriggerEvent::new();
1467      mte.event_id       = data[1];
1468      mte.timestamp      = data[2];
1469      mte.tiu_timestamp  = data[3];
1470      mte.tiu_gps32      = data[4];
1471      mte.tiu_gps16      = (data[5] & 0x0000ffff) as u16;
1472      mte.trigger_source = ((data[5] & 0xffff0000) >> 16) as u16;
1473      //mte.get_trigger_sources();
1474      let rbmask = (data[7] as u64) << 31 | data[6] as u64; 
1475      mte.mtb_link_mask  = rbmask;
1476      mte.dsi_j_mask     = data[8];
1477      let mut n_hit_words    = n_daq_words_actual - 9 - 2; // fixed part is 11 words
1478      if n_hit_words > n_daq_words_actual {
1479        n_hit_words = 0;
1480        println!("[MasterTrigger::get_event] N hit word calculation failed! fixing... {}", n_hit_words);
1481      }
1482      if verbose {
1483        println!("[MasterTrigger::get_event] => Will read {} hit word", n_hit_words);
1484      }
1485      for k in 1..n_hit_words+1 {
1486        if verbose {
1487          println!("[MasterTrigger::get_event] => Getting word {}", k);
1488        }
1489        let first  = (data[8 + k as usize] & 0x0000ffff) as u16;
1490        let second = ((data[8 + k as usize] & 0xffff0000) >> 16) as u16; 
1491        mte.channel_mask.push(first);
1492        if second != 0 {
1493          mte.channel_mask.push(second);
1494        }
1495      }
1496      if verbose {
1497        println!("[MasterTrigger::get_event] => Got MTE \n{}", mte);
1498      }
1499      let mut event = PyMasterTriggerEvent::new();
1500      event.set_event(mte);
1501      Ok(event)
1502    }
1503  }
1504}
1505