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