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