liftof_rb/
api.rs

1//! Higher level functions, to deal with events/binary reprentation of it, 
2//! configure the drs4, etc.
3
4use std::fs::read_to_string;
5
6use std::path::Path;
7use std::time::{
8    Duration,
9    Instant
10};
11use std::{
12    thread,
13    time
14};
15use std::env;
16use crossbeam_channel::{Sender};
17
18use crate::control::*;
19use crate::memory::*;
20
21// for calibration
22use tof_control::rb_control::rb_mode::{
23    select_noi_mode,
24    select_vcal_mode,
25    select_tcal_mode,
26    select_sma_mode
27};
28
29use tof_control::ltb_control::ltb_threshold;
30
31use gondola_core::prelude::*;
32
33// for general control over rb, ltb and pb
34//use tof_control::helper::pa_type::{
35//  PASetBias,
36//  PABiasError
37//};
38
39// for power
40//use liftof_lib::{
41//    LTBThresholdName
42//};
43
44const FIVE_SECONDS: Duration = time::Duration::from_millis(5000);
45
46
47//pub fn set_preamp_biases(cfg : &PreampBiasConfig) -> Result<(), PABiasError> {
48//  //PreampSetBias::set_manual_biases(cfg.biases)?;
49//  error!("Not setting actual biases, testing mode!");
50//  println!("Set preamp biases for all channels");
51//  Ok(())
52//}
53
54/// The poisson self trigger mode of the board
55/// triggers automatically, this means we don't 
56/// have to send a forced trigger signal every
57/// 1/rate.
58///
59/// It just sets the respective registers here
60pub fn enable_poisson_self_trigger(rate : f32) {
61  // we have to calculate the actual rate with Andrew's formula
62  //let clk_period : f64 = 1.0/33e6;
63  let max_val  : f32 = 4294967295.0;
64  let reg_val = (rate/(33e6/max_val)) as u32;
65  info!("Will use random self trigger with rate {reg_val} value for register, corresponding to {rate} Hz");
66  match set_self_trig_rate(reg_val) {
67    Err(err) => {
68      error!("Setting self trigger failed! Er {err}");
69      error!("To be clear, we are NOT RUNNING IN POISSON SELF-TRIGGER MODE!");
70    }
71    Ok(_)    => ()
72  }
73}
74
75
76/// Wait as long as a run is active.
77/// This call blocks the current thread 
78/// until no run is active anymore.
79///
80/// Check the trigger enabled register
81/// periodically to find out whether
82/// a run is active or not.
83///
84/// if n_errors is reached, decide the
85/// run to be inactive
86///
87/// # Arguments
88///
89/// * n_errors     : Unforgiveable number of errors
90///                  when querying the trigger status
91///                  register. If reached, return.
92/// * interval     : Check the trigger register every
93///                  interval
94/// * n_events_exp : Don't return before we have seen
95///                  this many events
96pub fn wait_while_run_active(n_errors     : u32,
97                             interval     : Duration,
98                             n_events_exp : u32,
99                             data_type    : &DataType,
100                             socket       : &zmq::Socket) -> Vec<RBEvent> {
101  // check if we are done
102  let mut events = Vec::<RBEvent>::new();
103  let mut errs : u32 = 0;
104  let start = Instant::now();
105  let mut triggers_have_stopped = false;
106  let mut kill_timer = Instant::now();
107  loop {
108    // listen to zmq here
109    debug!("Waiting for 0MQ socket...");
110    match socket.recv_bytes(0) {
111      Err(err) => {
112        error!("Unable to recv on socket! Err {err}");
113      },
114      Ok(bytes) => {
115        // the first 5 bytes are the identifier, in this case
116        // LOCAL
117        debug!("Received {} bytes over 0MQ!", bytes.len());
118        match TofPacket::from_bytestream(&bytes, &mut 5) {
119          Err(err) => {
120            error!("Can't unpack TofPacket, err {err}");
121          },
122          Ok(tp) => {
123            match RBEvent::from_bytestream(&tp.payload, &mut 0) {
124              Err(err) => {
125                error!("Can't unpack RBEvent, error {err}");
126              },
127              Ok(ev) => {
128                if ev.data_type == *data_type {
129                  events.push(ev);
130                }
131              }
132            }
133          }
134        }
135      }
136    }
137    if events.len() >= n_events_exp as usize {
138      info!("Acquired {} events!", events.len());
139      return events;
140    }
141    if triggers_have_stopped {
142      // wait for 10 more seconds..
143      if kill_timer.elapsed().as_secs() > 10 {
144        info!("Kill timer expired!");
145        return events;
146      } else {
147        continue;
148      }
149    }
150    if start.elapsed() > interval {
151      match get_triggers_enabled() {
152        Err(err) => {
153          error!("Unable to obtain trigger status! Err {err}");
154          errs += 1;
155        },
156        Ok(running) => {
157          if !running {
158            info!("Run has apparently terminated!");
159            triggers_have_stopped = true;
160            kill_timer = Instant::now();
161            //break;
162          } else { 
163            info!("We have waited the expected time, but there are still triggers...");
164            thread::sleep(interval);
165          }
166        }
167      }
168      //thread::sleep(interval);
169      if errs == n_errors {
170        error!("Can't wait anymore since we have seen the configured number of errors! {n_errors}");
171        return events;
172      }
173    //start = Instant::now();
174    }
175  }
176}
177
178// START Calibration stuff ====================================================
179// eventually, we have to rename that feature
180/// A full set of RB calibration
181///
182/// This includes
183/// - take voltage calbration data, 
184///   1000 events, save to disk, but 
185///   keep in memory
186/// - take timing calibration data,
187///   1000 events, save to disk but 
188///   keep in memory
189/// - no input data, 1000 events, save
190///   to disk but keep in memory
191/// - apply calibration script (Jamie)
192///   save result in binary and in textfile,
193///   send downstream
194///
195/// # Arguments
196///
197/// * rc_to_runner    : send calibration specific config
198///                     to the runner thread
199/// * tp_to_publisher : send calibration packets (wrapped 
200///                     in TofPacket) to publisher thread
201/// * save_waveforms  : save te waveforms wit the calibration
202/// * address         : the publisher's data address
203///                     We use a trick to get the event
204///                     packets for the calibration:
205///                     We are subscribing to the PUB 
206///                     socket of the publisher
207pub fn rb_calibration(rc_to_runner    : &Sender<RunConfig>,
208                      tp_to_publisher : &Sender<TofPacket>,
209                      save_waveforms  : bool,
210                      address         : String)
211-> Result<(), CalibrationError> {
212  warn!("Commencing full RB calibration routine! This will take the board out of datataking for a few minutes!");
213  // TODO this should become something that can be read from a local json file
214  // - I think this run config should be some standard setting
215  //let five_seconds   = time::Duration::from_millis(5000);
216  let mut run_config = RunConfig {
217    runid                   : 0,
218    nevents                 : 1300,
219    is_active               : true,
220    nseconds                : 0,
221    tof_op_mode             : TofOperationMode::Default,
222    trigger_poisson_rate    : 0,
223    trigger_fixed_rate      : 100,
224    data_type               : DataType::Noi,
225    rb_buff_size            : 100
226  };
227  // here is the general idea. We connect to our own 
228  // zmq socket, to gather the events and store them 
229  // here locally. Then we apply the calibration 
230  // and we simply have to send it back to the 
231  // data publisher.
232  // This saves us a mutex!!
233  let mut board_id = 0u8;
234  match get_board_id() {
235    Err(err) => {
236      error!("Unable to obtain board id. Calibration might be orphaned. Err {err}");
237    },
238    Ok(rb_id) => {
239      board_id = rb_id as u8;
240    }
241  }
242  let mut calibration = RBCalibrations::new(board_id);
243  calibration.serialize_event_data = save_waveforms;
244
245  let ctx = zmq::Context::new();
246  let socket : zmq::Socket; 
247  match ctx.socket(zmq::SUB) {
248    Err(err) => {
249      error!("Unable to create zmq socket! Err {err}. This is BAD!");
250      return Err(CalibrationError::CanNotConnectToMyOwnZMQSocket);
251    }
252    Ok(sock) => {
253      socket = sock;
254    }
255  }
256  match socket.connect(&address) {
257    Err(err) => {
258      error!("Unable to connect to data (PUB) socket {address}, Err {err}");
259      return Err(CalibrationError::CanNotConnectToMyOwnZMQSocket);
260    },
261    Ok(_) => ()
262  }
263  
264  // The packets relevant for us here in this context, will 
265  // all be prefixed with "LOCAL"
266  // See the respective section in data_publisher 
267  // (search for prefix_local)
268  let topic_local = String::from("LOCAL");
269  match socket.set_subscribe(&topic_local.as_bytes()) {
270    Err(err) => error!("Can not subscribe to {topic_local}, err {err}"),
271    Ok(_)    => info!("Subscribing to local packages!"),
272  }
273  // at this point, the zmq socket should be set up!
274  run_config.data_type = DataType::Noi; 
275  match run_noi_calibration(rc_to_runner, &socket, &mut calibration, run_config) {
276    Err(err) => {
277      error!("Unable to run no input calibration step. Err {err}");
278      return Err(CalibrationError::CalibrationFailed);
279    },
280    Ok(_) => {
281      info!("Noi calibration step done!")
282    }
283  };
284
285  run_config.data_type = DataType::VoltageCalibration; 
286  match run_voltage_calibration(rc_to_runner, &socket, &mut calibration, run_config) {
287    Err(err) => {
288      error!("Unable to run voltage calibration step. Err {err}");
289      return Err(CalibrationError::CalibrationFailed);
290    },
291    Ok(_) => {
292      info!("Voltage calibration step done!")
293    }
294  };
295  
296  run_config.data_type = DataType::TimingCalibration;
297  match run_timing_calibration(rc_to_runner, &socket, &mut calibration, run_config) {
298    Err(err) => {
299      error!("Unable to run timing calibration step. Err {err}");
300      return Err(CalibrationError::CalibrationFailed);
301    },
302    Ok(_) => {
303      info!("Timing calibration step done!")
304    }
305  };
306
307  println!("==> Calibration data taking complete!"); 
308  println!("Calibration : {}", calibration);
309  println!("Cleaning data...");
310  calibration.clean_input_data();
311  println!("Calibration : {}", calibration);
312
313  info!("Will set board to sma mode!");
314  match select_sma_mode() {
315    Err(_) => {
316      error!("Unable to set sma mode.");
317      return Err(CalibrationError::CalibrationFailed);
318    },
319    Ok(_) => {
320      info!("Timing calibration step done!")
321    }
322  };
323  run_config.is_active = false;  
324  match rc_to_runner.send(run_config) {
325    Err(err) => {
326      warn!("Can not send runconfig!, Err {err}");
327      return Err(CalibrationError::CalibrationFailed);
328    }
329    Ok(_)    => trace!("Success!")
330  }
331  thread::sleep(FIVE_SECONDS);
332
333  // Do this only with the full calib
334  calibration.calibrate()?;
335  println!("== ==> [rb_calibration] Calibration : {}", calibration);
336  // now it just needs to be send to 
337  // the publisher
338  //for k in 0..10 {
339  //  println!("cali vcal  {}", calibration.v_offsets[0][k]);
340  //  println!("cali vincs {}", calibration.v_inc[0][k]);
341  //  println!("cali vdips {}", calibration.v_dips[0][k]);
342  //  println!("cali tbins {}", calibration.tbin[0][k]);
343  //}
344  let calib_pack = calibration.pack();
345  match tp_to_publisher.send(calib_pack) {
346    Err(err) => {
347      error!("Unable to send RBCalibration package! Error {err}");
348      return Err(CalibrationError::CanNotConnectToMyOwnZMQSocket);
349    },
350    Ok(_) => ()
351  }
352  info!("Calibration done!");
353  Ok(())
354}
355
356// TODO The following two functions are placeholder for subset of the
357// calibration routine. It is not clear whether these make sense or not.
358//
359// Only no input and publish.
360pub fn rb_noi_subcalibration(rc_to_runner    : &Sender<RunConfig>,
361                             tp_to_publisher : &Sender<TofPacket>)
362-> Result<(), CalibrationError> {
363  warn!("Commencing RB No input sub-calibration routine! This will take the board out of datataking for a few minutes!");
364  // TODO this should become something that can be read from a local json file
365  let mut run_config = RunConfig {
366    runid                   : 0,
367    nevents                 : 1300,
368    is_active               : true,
369    nseconds                : 0,
370    tof_op_mode             : TofOperationMode::Default,
371    trigger_poisson_rate    : 0,
372    trigger_fixed_rate      : 100,
373    data_type               : DataType::Noi,
374    rb_buff_size            : 100
375  }; 
376  let socket = connect_to_zmq().expect("Not able to connect to socket, something REAL strange happened.");
377
378  let mut board_id = 0u8;
379  match get_board_id() {
380    Err(err) => {
381      error!("Unable to obtain board id. Calibration might be orphaned. Err {err}");
382    },
383    Ok(rb_id) => {
384      board_id = rb_id as u8;
385    }
386  }
387  let mut calibration = RBCalibrations::new(board_id);
388  calibration.serialize_event_data = true;
389
390  run_config.data_type = DataType::Noi; 
391  match run_noi_calibration(rc_to_runner, &socket, &mut calibration, run_config) {
392    Err(err) => {
393      error!("Unable to run noi calibration step. Err {err}");
394      return Err(CalibrationError::CalibrationFailed);
395    },
396    Ok(_) => {
397      info!("Noi calibration step done!");
398    }
399  };
400
401  println!("==> No input data taking complete!"); 
402  println!("Calibration : {}", calibration);
403  println!("Cleaning data...");
404  calibration.clean_input_data();
405  println!("Calibration : {}", calibration);
406
407  info!("Will set board to sma mode!");
408  match select_sma_mode() {
409    Err(err) => error!("Unable to select sma mode! {err:?}"),
410    Ok(_)    => ()
411  }
412  run_config.is_active = false;  
413  match rc_to_runner.send(run_config) {
414    Err(err) => {
415      warn!("Can not send runconfig!, Err {err}");
416      return Err(CalibrationError::CanNotConnectToMyOwnZMQSocket);
417    },
418    Ok(_)    => trace!("Success!")
419  }
420  thread::sleep(FIVE_SECONDS);
421
422  println!("Calibration won't start cause the calibration data taking chain is not complete!");
423
424  // Send it
425  let calib_pack = calibration.pack();
426  match tp_to_publisher.send(calib_pack) {
427    Err(err) => {
428      error!("Unable to send RBCalibration package! Error {err}");
429      return Err(CalibrationError::CanNotConnectToMyOwnZMQSocket);
430    },
431    Ok(_) => ()
432  }
433  info!("Calibration done!");
434  Ok(())
435}
436
437// Noi -> Voltage chain and publish.
438pub fn rb_voltage_subcalibration(rc_to_runner    : &Sender<RunConfig>,
439                                 tp_to_publisher : &Sender<TofPacket>,
440                                 _voltage_level   : u16) // where do we put this bad boi?
441-> Result<(), CalibrationError> {
442  warn!("Commencing RB no input + voltage sub-calibration routine! This will take the board out of datataking for a few minutes!");
443  // TODO this should become something that can be read from a local json file
444  let mut run_config = RunConfig {
445    runid                   : 0,
446    nevents                 : 1300,
447    is_active               : true,
448    nseconds                : 0,
449    tof_op_mode             : TofOperationMode::Default,
450    trigger_poisson_rate    : 0,
451    trigger_fixed_rate      : 100,
452    data_type               : DataType::VoltageCalibration,
453    rb_buff_size            : 1000
454  }; 
455  let socket = connect_to_zmq().expect("Not able to connect to socket, something REAL strange happened.");
456
457  let mut board_id = 0u8;
458  match get_board_id() {
459    Err(err) => {
460      error!("Unable to obtain board id. Calibration might be orphaned. Err {err}");
461    },
462    Ok(rb_id) => {
463      board_id = rb_id as u8;
464    }
465  }
466  let mut calibration = RBCalibrations::new(board_id);
467  calibration.serialize_event_data = true;
468
469  run_config.data_type = DataType::Noi; 
470  match run_noi_calibration(rc_to_runner, &socket, &mut calibration, run_config) {
471    Err(err) => {
472      error!("Unable to run noi calibration step. Err {err}");
473      return Err(CalibrationError::CalibrationFailed);
474    },
475    Ok(_) => {
476      info!("Noi calibration step done!")
477    }
478  };
479
480  run_config.data_type = DataType::VoltageCalibration; 
481  match run_voltage_calibration(rc_to_runner, &socket, &mut calibration, run_config) {
482    Err(err) => {
483      error!("Unable to run voltage calibration step. Err {err}");
484      return Err(CalibrationError::CalibrationFailed);
485    },
486    Ok(_) => {
487      info!("Voltage calibration step done!")
488    }
489  };
490
491  println!("==> No input + voltage data taking complete!"); 
492  println!("Calibration : {}", calibration);
493  println!("Cleaning data...");
494  calibration.clean_input_data();
495  println!("Calibration : {}", calibration);
496
497  info!("Will set board to sma mode!");
498  match select_sma_mode() {
499    Err(err) => error!("Unable to select SMA mode! {err:?}"),
500    Ok(_)    => ()
501  }
502  run_config.is_active = false;  
503  match rc_to_runner.send(run_config) {
504    Err(err) => {
505      warn!("Can not send runconfig!, Err {err}");
506      return Err(CalibrationError::CanNotConnectToMyOwnZMQSocket);
507    },
508    Ok(_)    => trace!("Success!")
509  }
510  thread::sleep(FIVE_SECONDS);
511
512  println!("Calibration won't start cause the calibration data taking chain is not complete!");
513
514  // Send it
515  let calib_pack = calibration.pack();
516  match tp_to_publisher.send(calib_pack) {
517    Err(err) => {
518      error!("Unable to send RBCalibration package! Error {err}");
519      return Err(CalibrationError::CanNotConnectToMyOwnZMQSocket);
520    },
521    Ok(_) => ()
522  }
523  info!("Calibration done!");
524  Ok(())
525}
526
527// Noi -> Voltage -> Timing chain and publish (no calib!).
528pub fn rb_timing_subcalibration(rc_to_runner    : &Sender<RunConfig>,
529                                tp_to_publisher : &Sender<TofPacket>,
530                                _voltage_level   : u16)
531-> Result<(), CalibrationError> {
532  warn!("Commencing RB no input + voltage + timing sub-calibration routine! This will take the board out of datataking for a few minutes!");
533  // TODO this should become something that can be read from a local json file
534  let mut run_config = RunConfig {
535    runid                   : 0,
536    nevents                 : 1300,
537    is_active               : true,
538    nseconds                : 0,
539    tof_op_mode             : TofOperationMode::Default,
540    trigger_poisson_rate    : 0,
541    trigger_fixed_rate      : 100,
542    data_type               : DataType::TimingCalibration,
543    rb_buff_size            : 1000
544  }; 
545  let socket = connect_to_zmq().expect("Not able to connect to socket, something REAL strange happened.");
546
547  let mut board_id = 0u8;
548  match get_board_id() {
549    Err(err) => {
550      error!("Unable to obtain board id. Calibration might be orphaned. Err {err}");
551    },
552    Ok(rb_id) => {
553      board_id = rb_id as u8;
554    }
555  }
556  let mut calibration = RBCalibrations::new(board_id);
557  calibration.serialize_event_data = true;
558
559  run_config.data_type = DataType::Noi; 
560  match run_noi_calibration(rc_to_runner, &socket, &mut calibration, run_config) {
561    Err(err) => {
562      error!("Unable to run no input calibration step. Err {err}");
563      return Err(CalibrationError::CalibrationFailed);
564    },
565    Ok(_) => {
566      info!("Noi calibration step done!")
567    }
568  };
569
570  run_config.data_type = DataType::VoltageCalibration; 
571  match run_voltage_calibration(rc_to_runner, &socket, &mut calibration, run_config) {
572    Err(err) => {
573      error!("Unable to run voltage calibration step. Err {err}");
574      return Err(CalibrationError::CalibrationFailed);
575    },
576    Ok(_) => {
577      info!("Voltage calibration step done!")
578    }
579  };
580  
581  run_config.data_type = DataType::TimingCalibration;
582  match run_timing_calibration(rc_to_runner, &socket, &mut calibration, run_config) {
583    Err(err) => {
584      error!("Unable to run timing calibration step. Err {err}");
585      return Err(CalibrationError::CalibrationFailed);
586    },
587    Ok(_) => {
588      info!("Timing calibration step done!")
589    }
590  };
591
592  println!("==> No input + voltage + timing data taking complete!"); 
593  println!("Calibration : {}", calibration);
594  println!("Cleaning data...");
595  calibration.clean_input_data();
596  println!("Calibration : {}", calibration);
597
598  info!("Will set board to sma mode!");
599  match select_sma_mode() {
600    Err(err) => error!("Unable to select SMA mode! {err:?}"),
601    Ok(_) => ()
602  }
603  run_config.is_active = false;  
604  match rc_to_runner.send(run_config) {
605    Err(err) => {
606      warn!("Can not send runconfig! {err}");
607      return Err(CalibrationError::CanNotConnectToMyOwnZMQSocket);
608    },
609    Ok(_)    => trace!("Success!")
610  }
611  thread::sleep(FIVE_SECONDS);
612
613  println!("Calibration won't start. The data taking chain is complete, but a sub-calibration routine was called!");
614
615  // Send it
616  let calib_pack = calibration.pack();
617  match tp_to_publisher.send(calib_pack) {
618    Err(err) => {
619      error!("Unable to send RBCalibration package! Error {err}");
620      return Err(CalibrationError::CanNotConnectToMyOwnZMQSocket);
621    },
622    Ok(_) => ()
623  }
624  info!("Calibration done!");
625  Ok(())
626}
627
628fn connect_to_zmq() -> Result<zmq::Socket, CalibrationError> {
629  // here is the general idea. We connect to our own 
630  // zmq socket, to gather the events and store them 
631  // here locally. Then we apply the calibration 
632  // and we simply have to send it back to the 
633  // data publisher.
634  // This saves us a mutex!!
635  //let this_board_ip = local_ip().expect("Unable to obtain local board IP. Something is messed up!");
636  let mut board_id = 0u8;
637  match get_board_id() {
638    Err(err) => {
639      error!("Unable to obtain board id. Calibration might be orphaned. Err {err}");
640    },
641    Ok(rb_id) => {
642      board_id = rb_id as u8;
643    }
644  }
645  let data_address = format!("tcp://10.0.1.1{:02}:{}", board_id, DATAPORT);
646  //let data_address = liftof_lib::build_tcp_from_ip(this_board_ip.to_string(), DATAPORT.to_string());
647
648  let ctx = zmq::Context::new();
649  let socket : zmq::Socket; 
650  match ctx.socket(zmq::SUB) {
651    Err(err) => {
652      error!("Unable to create zmq socket! Err {err}. This is BAD!");
653      return Err(CalibrationError::CanNotConnectToMyOwnZMQSocket);
654    }
655    Ok(sock) => {
656      socket = sock;
657    }
658  }
659  match socket.connect(&data_address) {
660    Err(err) => {
661      error!("Unable to connect to data (PUB) socket {data_address}, Err {err}");
662      return Err(CalibrationError::CanNotConnectToMyOwnZMQSocket);
663    },
664    Ok(_) => ()
665  }
666  
667  // The packets relevant for us here in this context, will 
668  // all be prefixed with "LOCAL"
669  // See the respective section in data_publisher 
670  // (search for prefix_local)
671  let topic_local = String::from("LOCAL");
672  match socket.set_subscribe(&topic_local.as_bytes()) {
673    Err(err) => error!("Can not subscribe to {topic_local}, err {err}"),
674    Ok(_)    => info!("Subscribing to local packages!"),
675  }
676  Ok(socket)
677}
678
679fn run_noi_calibration(rc_to_runner: &Sender<RunConfig>,
680                       socket: &zmq::Socket,
681                       calibration: &mut RBCalibrations,
682                       run_config: RunConfig)
683                       -> Result<(), CalibrationError> {
684  info!("Will set board to no input mode!");
685  match select_noi_mode() {
686    Err(err) => error!("Unable to select SMA mode! {err:?}"),
687    Ok(_)     => (),
688  }
689  match rc_to_runner.send(run_config) {
690    Err(err) => warn!("Can not send runconfig!, Err {err}"),
691    Ok(_)    => trace!("Success!")
692  }
693  let cal_dtype = DataType::Noi;
694  calibration.noi_data = wait_while_run_active(20, 4*FIVE_SECONDS, 1000, &cal_dtype, &socket);
695
696  println!("==> {} events for no-input (Voltage calibration) data taken!", calibration.noi_data.len());
697  Ok(())
698}
699
700fn run_voltage_calibration(rc_to_runner: &Sender<RunConfig>,
701                           socket: &zmq::Socket,
702                           calibration: &mut RBCalibrations,
703                           mut run_config: RunConfig)
704                           -> Result<(), CalibrationError> {
705  info!("Will set board to vcal mode!");
706  match select_vcal_mode() {
707    Err(err) => error!("Unable to select VCAL mode! {err:?}"),
708    Ok(_)     => ()
709  }
710  run_config.data_type = DataType::VoltageCalibration;
711  match rc_to_runner.send(run_config) {
712    Err(err) => warn!("Can not send runconfig! {err}"),
713    Ok(_)    => trace!("Success!")
714  }  
715  let cal_dtype         = DataType::VoltageCalibration;
716  calibration.vcal_data = wait_while_run_active(20, 4*FIVE_SECONDS, 1000, &cal_dtype, &socket);
717  
718  println!("==> {} events for vcal (voltage calibration) data taken!", calibration.vcal_data.len());
719  Ok(())
720}
721
722fn run_timing_calibration(rc_to_runner: &Sender<RunConfig>,
723                          socket: &zmq::Socket,
724                          calibration: &mut RBCalibrations,
725                          mut run_config: RunConfig)
726                          -> Result<(), CalibrationError> {
727  info!("Will set board to tcal mode!");
728  run_config.trigger_poisson_rate  = 80;
729  run_config.nevents               = 1800; // make sure we get 1000 events
730  run_config.trigger_fixed_rate    = 0;
731  //run_config.rb_buff_size          = 500;
732  run_config.data_type = DataType::TimingCalibration;  
733  match select_tcal_mode() {
734    Err(err) => error!("Can not set board to TCAL mode! {err:?}"),
735    Ok(_)     => (),
736  }
737  match rc_to_runner.send(run_config) {
738    Err(err) => warn!("Can not send runconfig! {err}"),
739    Ok(_)    => trace!("Success!")
740  }
741  
742  let cal_dtype         = DataType::TimingCalibration;
743  calibration.tcal_data = wait_while_run_active(20, 4*FIVE_SECONDS, 1000,&cal_dtype, &socket);
744  println!("==> {} events for tcal (timing calibration) data taken!", calibration.tcal_data.len());
745
746  //run_config.is_active  = false;  
747  //match rc_to_runner.send(run_config) {
748  //  Err(err) => warn!("Can not send runconfig! {err}"),
749  //  Ok(_)    => trace!("Success!")
750  //}
751  //info!("Waiting 5 seconds");
752  //thread::sleep(FIVE_SECONDS);
753  //info!("Will set board to sma mode!");
754  //match select_sma_mode() {
755  //  Err(err) => error!("Can not set SMA mode! {err:?}"),
756  //  Ok(_)    => (),
757  //}
758  //println!("==> Timing calibration data taken!");
759  //println!("==> Calibration data taking complete!"); 
760  //println!("Calibration : {}", calibration);
761  //println!("Cleaning data...");
762  //calibration.clean_input_data();
763  //println!("Calibration : {}", calibration);
764
765  //info!("Will set board to sma mode!");
766  //match select_sma_mode() {
767  //  Err(err) => error!("Unable to select SMA mode! {err:?}"),
768  //  Ok(_)    => ()
769  //}
770  //run_config.is_active = false;  
771  //match rc_to_runner.send(run_config) {
772  //  Err(err) => warn!("Can not send runconfig!, Err {err}"),
773  //  Ok(_)    => trace!("Success!")
774  //}
775  //thread::sleep(FIVE_SECONDS);
776  //calibration.calibrate()?;
777  //println!("Calibration : {}", calibration);
778  //// now it just needs to be send to 
779  //// the publisher
780  ////for k in 0..10 {
781  ////  println!("cali vcal  {}", calibration.v_offsets[0][k]);
782  ////  println!("cali vincs {}", calibration.v_inc[0][k]);
783  ////  println!("cali vdips {}", calibration.v_dips[0][k]);
784  ////  println!("cali tbins {}", calibration.tbin[0][k]);
785  ////}
786  //info!("Calibration done!");
787  Ok(())
788}
789// END Calibration stuff ======================================================
790
791// BEGIN Run stuff ============================================================
792pub fn rb_start_run(rc_to_runner    : &Sender<RunConfig>,
793                    rc_config       : RunConfig,
794                    _run_type        : u8,
795                    _rb_id           : u8,
796                    _event_no        : u8) -> Result<(), RunError> {
797  println!("==> Will initialize new run!");
798  match rc_to_runner.send(rc_config) {
799    Err(err) => error!("Error initializing run! {err}"),
800    Ok(_)    => ()
801  };
802  println!("==> Run successfully started!");
803  Ok(())
804}
805
806pub fn rb_stop_run(rc_to_runner    : &Sender<RunConfig>,
807                   _rb_id           : u8) -> Result<(), RunError> {
808  println!("==> Will initialize new run!");
809  println!("Received command to end run!");
810  // default is not active for run config
811
812  let  rc = RunConfig::new();
813  match rc_to_runner.send(rc) {
814    Err(err) => error!("Error stopping run! {err}"),
815    Ok(_)    => ()
816  }
817  println!("==> Run successfully stopped!");
818  Ok(())
819}
820// END Run stuff ==============================================================
821
822const DMA_RESET_TRIES : u8 = 10;   // if we can not reset the DMA after this number
823                                   // of retries, we'll panic!
824
825
826// Using the same approach as the flight computer, we use
827// two ports for communication/data
828// 1) PUB for the data
829// 2) SUB for the commands.
830// - _A comment here_ while we usually would prefer REP?REQ for 
831// comms, this will avoid deadlocks in any case and makes it in 
832// general much easier for command servers to connect to the boards.
833
834/// Dataport is 0MQ PUB for publishing waveform/event data
835pub const DATAPORT : u32 = 42000;
836
837
838/// Check for the environmental 
839/// variable LIFTOF_IS_SYSTEMD
840/// which is set in the liftof.service file
841/// to determine wether liftof is executed 
842/// through systemd.
843///
844/// WARN - this is not elegant, but all other
845/// approaches did not work!
846pub fn is_systemd_process() -> bool {
847  // this custom variable must be set in the 
848  // liftof.service file!!
849  if env::var("LIFTOF_IS_SYSTEMD").is_ok() {
850    info!("Running under systemd");
851    true
852  } else {
853    info!("Not running under systemd");
854    false
855  }
856}
857
858/// Get a runconfig from a file. 
859///
860/// FIXME - panics...
861pub fn get_runconfig(rcfile : &Path) -> RunConfig {
862  //match get_json_from_file(rcfile) {
863  match read_to_string(rcfile) {
864    Err(err) => {
865      panic!("Unable to read the configuration file! Error {err}");
866    }
867    Ok(rc_from_file) => {
868      println!("==> Found configuration file {}!", rcfile.display());
869      match serde_json::from_str(&rc_from_file) {
870        Err(err) => panic!("Can not read json from configuration file. Error {err}"),
871        Ok(rc_json) => {
872          rc_json
873        }
874      }
875    }
876  }
877}
878
879/// Get the active half of the RAM buffer
880/// 
881/// This uses the know regions of the RAM 
882/// buffers together with the dma pointer
883/// to get the correct half.
884///
885pub fn get_active_buffer() -> Result<RamBuffer, RegisterError> {
886  let dma_ptr = get_dma_pointer()?;
887  if dma_ptr >= UIO1_MAX_OCCUPANCY {
888    return Ok(RamBuffer::B);
889  }
890  Ok(RamBuffer::A)
891}
892
893/// Add the prefix "LOCAL" to a bytestream.
894///
895/// This will allow for the central C&C server 
896/// to ignore this packet, but the board can 
897/// still send it to itself
898pub fn prefix_local(input : &mut Vec<u8>) -> Vec<u8> {
899  let mut bytestream : Vec::<u8>;
900  let local = String::from("LOCAL");
901  bytestream = local.as_bytes().to_vec();
902  bytestream.append(input);
903  bytestream
904}
905
906pub fn prefix_board_id(input : &mut Vec<u8>) -> Vec<u8> {
907  // FIUXME - this should not panic
908  let board_id = get_board_id()//
909                 .unwrap_or(0);
910                               //.expect("Need to be able to obtain board id!");
911  let mut bytestream : Vec::<u8>;
912  let board = format!("RB{:02}", board_id);
913
914  //let mut response = 
915  bytestream = board.as_bytes().to_vec();
916  //bytestream.append(&mut resp.to_bytestream());
917  bytestream.append(input);
918  bytestream
919}
920
921/// add the board id to the bytestream in front of the 
922/// tof response
923pub fn prefix_board_id_noquery(board_id : u8, input : &mut Vec<u8>) -> Vec<u8> {
924  // FIUXME - this should not panic
925  //let board_id = get_board_id()//
926  //               .unwrap_or(0);
927  //                             //.expect("Need to be able to obtain board id!");
928  let mut bytestream : Vec::<u8>;
929  let board = format!("RB{:02}", board_id);
930  //let board : String;
931  //if board_id < 10 {
932  //  board = String::from("RB0") + &board_id.to_string();
933  //} else {
934  //  board = String::from("RB")  + &board_id.to_string();
935  //}
936  //let mut response = 
937  bytestream = board.as_bytes().to_vec();
938  //bytestream.append(&mut resp.to_bytestream());
939  bytestream.append(input);
940  bytestream
941}
942
943/// Reset DMA pointer and buffer occupancy registers
944///
945/// If there are any errors, we will wait for a short
946/// time and then try again
947/// FIXME - this should return Result
948pub fn reset_dma_and_buffers() {
949  // register writing is on the order of microseconds 
950  // (MHz clock) so one_milli is plenty
951  let one_milli   = time::Duration::from_millis(1);
952  let buf_a = RamBuffer::A;
953  let buf_b = RamBuffer::B;
954  let mut n_tries = 0u8;
955  let mut failed  = true;
956  loop {
957    if failed && n_tries < DMA_RESET_TRIES {
958      match reset_dma() {
959        Ok(_)    => (),
960        Err(err) => {
961          error!("Resetting dma failed, err {:?}", err);
962          n_tries += 1;
963          thread::sleep(one_milli);
964          continue;
965        }
966      } 
967      match reset_ram_buffer_occ(&buf_a) {
968        Ok(_)    => (), 
969        Err(err) => {
970          error!("Problem resetting buffer /dev/uio1 {:?}", err);
971          n_tries += 1;
972          thread::sleep(one_milli);
973          continue;
974        }
975      }
976      match reset_ram_buffer_occ(&buf_b) {
977        Ok(_)    => (), 
978        Err(err) => {
979          error!("Problem resetting buffer /dev/uio2 {:?}", err);
980          n_tries += 1;
981          thread::sleep(one_milli);
982          continue;
983        }
984      }
985    failed = false;      
986    } else {
987      break;
988    }
989  }
990  // in any case, relax a bit
991  thread::sleep(10*one_milli);
992}
993
994/// Check if the buffers are actually filling
995/// 
996///  - if not, panic. We can't go on like that
997pub fn run_check() {
998  let buf_a = RamBuffer::A;
999  let buf_b = RamBuffer::B;
1000
1001  let interval = Duration::from_secs(5);
1002  let mut n_iter = 0;
1003  
1004  let mut last_occ_a = get_blob_buffer_occ(&buf_a).unwrap();
1005  let mut last_occ_b = get_blob_buffer_occ(&buf_b).unwrap();
1006  match enable_trigger() {
1007    Err(err) => error!("Unable to enable trigger! Err {err}"),
1008    Ok(_)    => info!("Triggers enabled")
1009  }
1010  loop {
1011    n_iter += 1;
1012    thread::sleep(interval);
1013    let occ_a = get_blob_buffer_occ(&buf_a).unwrap();
1014    let occ_b = get_blob_buffer_occ(&buf_b).unwrap();
1015    if occ_a - last_occ_a == 0 && occ_b - last_occ_b == 0 {
1016      panic!("We did not observe a change in occupancy for either one of the buffers!");
1017    }
1018    println!("-- buff size A {}", occ_a - last_occ_a);
1019    println!("-- buff size B {}", occ_b - last_occ_b);
1020    println!("---> Iter {n_iter}");
1021    last_occ_a = occ_a;
1022    last_occ_b = occ_b;
1023  }
1024}
1025
1026///  Get the blob buffer size from occupancy register
1027///
1028///  Read out the occupancy register and compare to 
1029///  a previously recoreded value. 
1030///  Everything is u32 (the register can't hold more)
1031///
1032///  The size of the buffer can only be defined compared
1033///  to a start value. If the value rools over, the 
1034///  size then does not make no longer sense and needs
1035///  to be updated.
1036///
1037///  #Arguments: 
1038///
1039pub fn get_buff_size(which : &RamBuffer) ->Result<usize, RegisterError> {
1040  let size : u32;
1041  let occ = get_blob_buffer_occ(&which)?;
1042  trace!("Got occupancy of {occ} for buff {which:?}");
1043
1044  // the buffer sizes is UIO1_MAX_OCCUPANCY -  occ
1045  match which {
1046    RamBuffer::A => {size = occ - UIO1_MIN_OCCUPANCY;},
1047    RamBuffer::B => {size = occ - UIO2_MIN_OCCUPANCY;}
1048  }
1049  let result = size as usize;
1050  Ok(result)
1051}
1052/// Manage the RAM buffers for event data
1053/// 
1054/// This experimental version of the ram buffer
1055/// handler will directly push the content of 
1056/// the ram buffer into an RBEventMemoryStreamer.
1057///
1058/// EXPERIMENTAL - there is some unsafe stuff 
1059///                going on, which I am not sure 
1060///                about. 
1061///
1062/// Rationale    - this avoids at least 2 clones 
1063///                and possibly an entire thread.
1064///                So it might boost performance.
1065///
1066/// Difference to previous approach:
1067///
1068/// Instead of sending the resulting vector of 
1069/// bytes away, we fed the streamer. Then in 
1070/// a second step, either the streamer has 
1071/// to digest its data, or we need to send
1072/// the streamer somewhere.
1073///
1074/// # Arguments:
1075///
1076/// * buff_trip : size which triggers buffer readout.
1077/// * streamer  : RBEventMemoryStreamer which will consume
1078///               the ram buffer
1079pub fn experimental_ram_buffer_handler(buff_trip : usize,
1080                                       streamer  : &mut RBEventMemoryStreamer)
1081    -> Result<(RamBuffer, usize), RegisterError> {
1082  let mut switch_buff = false;
1083  if buff_trip < DATABUF_TOTAL_SIZE {
1084    switch_buff = true;
1085  }
1086
1087  let which          = get_active_buffer()?;
1088  let mut buff_size  = get_buff_size(&which)?;
1089  if buff_size >= buff_trip {
1090    info!("Buff {which:?} tripped at a size of {buff_size}");  
1091    debug!("Buff handler switch buffers {switch_buff}");
1092    // 1) switch buffer
1093    // 2) read out
1094    // 3) reset
1095    if switch_buff {
1096      match switch_ram_buffer() {
1097        Ok(_)  => {
1098          info!("Ram buffer switched!");
1099        },
1100        Err(_) => error!("Unable to switch RAM buffers!") 
1101      }
1102    }
1103    match read_buffer_into_streamer(&which, buff_size as usize, streamer) {
1104      Err(err) => error!("Can not read data buffer into RBEventMemoryStreamer! {err}"),
1105      Ok(_)    => (),
1106    }
1107    match reset_ram_buffer_occ(&which) {
1108      Ok(_)  => debug!("Successfully reset the buffer occupancy value"),
1109      Err(_) => error!("Unable to reset buffer!")
1110    }
1111    buff_size = 0;
1112  }
1113  Ok((which, buff_size))
1114}
1115
1116/// Manage the RAM buffers for event data
1117///
1118/// This will make a decision based on the 
1119/// buff_trip value if a buffer is "full", 
1120/// and in that case, read it out, send 
1121/// the data over the channel elsewhere 
1122/// and switch to the other half of the 
1123/// buffer.
1124/// If buff_trip == DATABUF_TOTAL_SIZE, the 
1125/// buffer will be switched by the firmware.
1126///
1127/// # Arguments:
1128///
1129/// * buff_trip : size which triggers buffer readout.
1130pub fn ram_buffer_handler(buff_trip     : usize,
1131                          bs_sender     : &Sender<Vec<u8>>)
1132    -> Result<(RamBuffer, usize, bool), RegisterError> {
1133  let mut switch_buff = false;
1134  let mut has_tripped = false;
1135  if buff_trip < DATABUF_TOTAL_SIZE {
1136    switch_buff = true;
1137  }
1138
1139  let which          = get_active_buffer()?;
1140  let mut buff_size  = get_buff_size(&which)?;
1141  if buff_size >= buff_trip {
1142    info!("Buff {which:?} tripped at a size of {buff_size}");  
1143    debug!("Buff handler switch buffers {switch_buff}");
1144    // 1) switch buffer
1145    // 2) read out
1146    // 3) reset
1147    has_tripped = true;
1148    if switch_buff {
1149      // maybe do the switch when the DRS4 is not 
1150      // busy atm
1151      loop {
1152        match daq_is_busy() {
1153          Err(err) => {
1154            trace!("DAQ is busy, not reading out RAM buffers..! {err}");
1155            continue;
1156          }
1157          Ok(busy) => {
1158            if busy {
1159              continue;
1160            }
1161            match switch_ram_buffer() {
1162              Ok(_)  => {
1163                info!("Ram buffer switched!");
1164              },
1165              Err(_) => error!("Unable to switch RAM buffers!") 
1166            }
1167            break;
1168          }
1169        }
1170      }
1171    }
1172    // make sure buffsize is up to date
1173    buff_size  = get_buff_size(&which)?;
1174    let mut bytestream = Vec::<u8>::new(); 
1175    match read_data_buffer(&which, buff_size as usize) {
1176      Err(err) => error!("Can not read data buffer {err}"),
1177      Ok(bs)    => bytestream = bs,
1178    }
1179    let bs_len = bytestream.len();
1180    
1181    // check what is the last signature of the stream
1182    // (debugging)
1183    //let mut foo_pos : usize = bs_len - 2;
1184    //let foo = parse_u16(&bytestream,&mut foo_pos);
1185    //println!("[api::ram_buffer_handler] - stream ends with {}", foo);
1186
1187    match bs_sender.send(bytestream) {
1188      Err(err) => error!("error sending {err}"),
1189      Ok(_)    => {
1190        info!("We are sending {} event bytes for further processing!", bs_len);
1191      }
1192    }
1193    match reset_ram_buffer_occ(&which) {
1194      Ok(_)  => debug!("Successfully reset the buffer occupancy value"),
1195      Err(_) => error!("Unable to reset buffer!")
1196    }
1197    buff_size = 0;
1198  }
1199  Ok((which, buff_size, has_tripped))
1200}
1201
1202///  Prepare the whole readoutboard for data taking.
1203///
1204///  This sets up the drs4 and c
1205///  lears the memory of 
1206///  the data buffers.
1207///  
1208///  This will make several writes to the /dev/uio0
1209///  memory map.
1210pub fn setup_drs4() -> Result<(), RegisterError> {
1211
1212  let buf_a = RamBuffer::A;
1213  let buf_b = RamBuffer::B;
1214
1215  let one_milli   = time::Duration::from_millis(1);
1216  // DAQ defaults
1217  //let num_samples     : u32 = 3000;
1218  //let duration        : u32 = 0; // Default is 0 min (=> use events) 
1219  //let roi_mode        : u32 = 1;
1220  //let transp_mode     : u32 = 1;
1221  //let run_mode        : u32 = 0;
1222  //let run_type        : u32 = 0;        // 0 -> Events, 1 -> Time (default is Events)
1223  //let config_drs_flag : u32 = 1; // By default, configure the DRS chip
1224  // run mode info
1225  // 0 = free run (must be manually halted), ext. trigger
1226  // 1 = finite sample run, ext. trigger
1227  // 2 = finite sample run, software trigger
1228  // 3 = finite sample run, software trigger, random delays/phase for timing calibration
1229  let spike_clean     : bool = true;
1230  //let read_ch9        : u32  = 1;
1231
1232  // before we do anything, set the DRS in idle mode 
1233  // and set the configure bit
1234  //idle_drs4_daq()?;
1235  //thread::sleep(one_milli);
1236  //set_drs4_configure()?;
1237  //thread::sleep(one_milli);
1238
1239  // Sanity checking
1240  //let max_samples     : u32 = 65000;
1241  //let max_duration    : u32 = 1440; // Minutes in 1 day
1242
1243  //reset_daq()?;
1244  //thread::sleep(one_milli);
1245  //reset_drs()?;
1246  //thread::sleep(one_milli);
1247  //reset_dma()?;
1248  //thread::sleep(one_milli);
1249  clear_dma_memory()?;
1250  thread::sleep(one_milli);
1251  
1252  
1253  // for some reason, sometimes it 
1254  // takes a bit until the blob
1255  // buffers reset. Let's try a 
1256  // few times
1257  info!("Resetting event memory buffers..");
1258  for _ in 0..5 {
1259    reset_ram_buffer_occ(&buf_a)?;
1260    thread::sleep(one_milli);
1261    reset_ram_buffer_occ(&buf_b)?;
1262    thread::sleep(one_milli);
1263  }
1264
1265  // register 04 contains a lot of stuff:
1266  // roi mode, busy, adc latency
1267  // sample  count and spike removal
1268  let spike_clean_enable : u32 = 4194304; //bit 22
1269  if spike_clean {
1270    let mut value = read_control_reg(0x40).unwrap();  
1271    value = value | spike_clean_enable;
1272    write_control_reg(0x40, value)?;
1273    thread::sleep(one_milli);
1274  }
1275 
1276  // we don't want to do that anymore
1277  //set_readout_all_channels_and_ch9()?;
1278  thread::sleep(one_milli);
1279  set_master_trigger_mode()?;
1280  thread::sleep(one_milli);
1281  Ok(())
1282}
1283
1284
1285//pub fn send_preamp_bias_set_all(bias_voltage: u16) -> Result<(), RunError> {
1286//  match PreampSetBias::set_manual_bias(None, bias_voltage as f32) {
1287//    Ok(_) => (),
1288//    Err(_) => {
1289//      error!("Unable to set preamp bias! Error LTBThresholdError!");
1290//    }
1291//  };
1292//  Ok(())
1293//}
1294
1295
1296//pub fn send_preamp_bias_set(preamp_id: u8, bias_voltage: u16) -> Result<(), RunError> {
1297//  // TODO add check for LTB of interest
1298//  match PreampSetBias::set_manual_bias(Some(preamp_id), bias_voltage as f32) {
1299//    Ok(_) => (),
1300//    Err(_) => {
1301//      error!("Unable to set preamp bias! Error LTBThresholdError!");
1302//    }
1303//  };
1304//  Ok(())
1305//}
1306
1307
1308pub fn send_ltb_all_thresholds_set() -> Result<(), RunError> {
1309  match ltb_threshold::set_default_threshold() {
1310    Ok(_) => return Ok(()),
1311    Err(_) => {
1312      error!("Unable to set preamp bias! Error LTBThresholdError!");
1313      return Err(RunError::CanNotConnectToMyOwnZMQSocket)
1314    }
1315  };
1316}
1317
1318
1319pub fn send_ltb_all_thresholds_reset() -> Result<(), RunError> {
1320  match ltb_threshold::reset_threshold() {
1321    Ok(_) => (),
1322    Err(_) => {
1323      error!("Unable to set preamp bias! Error LTBThresholdError!");
1324    }
1325  };
1326  Ok(())
1327}
1328
1329
1330pub fn send_ltb_threshold_set(_ltb_id: u8, threshold: LTBThreshold, threshold_level: u16) -> Result<(), RunError> {
1331  // TODO add check for LTB of interest
1332  match ltb_threshold::set_threshold(threshold as u8, threshold_level as f32) {
1333    Ok(_)  => {
1334      info!("LTB threshold set!");
1335    },
1336    Err(_) => {
1337      error!("Unable to set preamp bias! Error LTBThresholdError!");
1338    }
1339  };
1340  Ok(())
1341}
1342
1343
1344
1345