tof_dataclasses/
commands.rs

1//! Commmands which can be issued
2//! to the various components of 
3//! the tof system.
4//!
5//!
6//!
7
8pub mod factory;
9pub mod config;
10
11use std::fmt;
12
13#[cfg(feature = "pybindings")]
14use pyo3::pyclass;
15
16use crate::serialization::{
17    Serialization,
18    Packable,
19    SerializationError,
20    parse_u8,
21    parse_u16,
22    parse_u32
23};
24
25use crate::packets::{
26    TofPacket,
27    PacketType
28};
29
30cfg_if::cfg_if! {
31  if #[cfg(feature = "random")]  {
32    use crate::FromRandom;
33    extern crate rand;
34    use rand::Rng;
35  }
36}
37
38pub use factory::*;
39
40#[derive(Debug, Copy, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
41#[cfg_attr(feature = "pybindings", pyclass(eq, eq_int))]
42#[repr(u8)]
43pub enum TofReturnCode {
44  Unknown = 0,
45  GeneralFail = 1,
46  GarbledCommand = 2,
47  Success = 200,
48}
49
50impl fmt::Display for TofReturnCode {
51  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52    let r = serde_json::to_string(self).unwrap_or(
53      String::from("Error: cannot unwrap this TofCommandCode"));
54    write!(f, "<TofReturnCode: {}>", r)
55  }
56}
57
58impl From<u8> for TofReturnCode {
59  fn from(value: u8) -> Self {
60    match value {
61      0   => TofReturnCode::Unknown,
62      1   => TofReturnCode::GeneralFail,
63      2   => TofReturnCode::GarbledCommand,
64      200 => TofReturnCode::Success,
65      _   => {
66        error!("Can not understand {}", value);
67        TofReturnCode::Unknown
68      }
69    }
70  }
71}
72
73#[cfg(feature = "random")]
74impl FromRandom for TofReturnCode {
75  fn from_random() -> Self {
76    let choices = [
77      TofReturnCode::Unknown,
78      TofReturnCode::GarbledCommand,
79      TofReturnCode::Success,
80      TofReturnCode::GeneralFail,
81    ];
82    let mut rng  = rand::thread_rng();
83    let idx = rng.gen_range(0..choices.len());
84    choices[idx]
85  }
86}
87
88#[derive(Debug, Copy, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
89#[cfg_attr(feature = "pybindings", pyclass(eq, eq_int))]
90#[repr(u8)]
91pub enum TofCommandCode {
92  Unknown                  = 0u8,
93  /// en empty command just to check if stuff is online
94  Ping                     = 1u8,
95  /// command code for getting the monitoring data from the component
96  Moni                     = 2u8,
97  /// Kill myself
98  Kill                     = 4u8, // Shi!
99  /// Reload a default (to be defined) config file
100  ResetConfigWDefault      = 5u8,
101  /// Make the current editable config the active config
102  SubmitConfig           = 6u8,
103  /// command code to configure the data publisher thread
104  SetDataPublisherConfig   = 20u8,
105  /// command code for "Set LTB Thresholds"
106  SetLTBThresholds         = 21u8,         
107  /// command code for "Configure MTB"
108  SetMTConfig              = 22u8,     
109  /// command code for chaning general run parameters
110  SetTofRunConfig          = 23u8,
111  /// command code for changing RB parameters
112  SetTofRBConfig           = 24u8,
113  /// command code for AnalysisEngineConfig
114  SetAnalysisEngineConfig  = 27u8,   
115  /// command code for "Set preamp bias"
116  SetPreampBias            = 28u8,         
117  /// Change the settings of the event builder
118  SetTOFEventBuilderConfig = 29u8,
119  /// command code for "Stop Data taking"
120  DataRunStop              = 30u8,  
121  /// command code for "Start Data taking"
122  DataRunStart             = 31u8,    
123  /// command code for "Start validation run"
124  StartValidationRun       = 32u8,         
125  /// command code for "Get all waveforms"
126  GetFullWaveforms         = 41u8,
127  /// command code for "Send the whole event cache over the wire"
128  UnspoolEventCache        = 44u8,
129  /// command code for "Run full calibration"
130  RBCalibration            = 53u8, 
131  /// command code for restarting systemd
132  RestartLiftofRBClients  = 60u8,
133  /// command code for putting liftof-cc in listening mode
134  Listen                  = 70u8,
135  /// command code for putting liftof-cc in staging mode
136  Staging                 = 71u8,
137  /// lock the cmd dispatcher
138  Lock                    = 80u8,
139  /// unlock the cmd dispatcher
140  Unlock                  = 81u8,
141  /// Enable sending of TOF packets
142  SendTofEvents           = 90u8,
143  /// Diesable sending of TofEventPacket
144  NoSendTofEvents         = 91u8,
145  /// Enable sending of RBWaveform packets
146  SendRBWaveforms         = 92u8,
147  /// Disable sending of RBWaveform packets
148  NoSendRBWaveforms       = 93u8,
149  /// Enable RB Channel Masks
150  SetRBChannelMask        = 99u8,
151  /// Shutdown RB - send shutdown now to RB
152  ShutdownRB              = 100u8,
153  /// Change the config file for the next run
154  ChangeNextRunConfig     = 101u8,
155  /// Shutdown RAT - send shutdown command to 2RBs in the same RAT
156  ShutdownRAT             = 102u8,
157  /// Shutdown a pair of RATs (as always two of them are hooked up to the 
158  /// same PDU channel)
159  ShutdownRATPair         = 103u8,
160  /// Shutdown the TOF CPU
161  ShutdownCPU             = 104u8,
162  /// Upload a new config file
163  UploadConfig            = 105u8,
164}
165
166impl fmt::Display for TofCommandCode {
167  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
168    let r = serde_json::to_string(self).unwrap_or(
169      String::from("Error: cannot unwrap this TofCommandCode"));
170    write!(f, "<TofCommandCode: {}>", r)
171  }
172}
173
174impl From<u8> for TofCommandCode {
175  fn from(value: u8) -> Self {
176    match value {
177      0   => TofCommandCode::Unknown,
178      1   => TofCommandCode::Ping,
179      2   => TofCommandCode::Moni,
180      4   => TofCommandCode::Kill,
181      5   => TofCommandCode::ResetConfigWDefault,
182      6   => TofCommandCode::SubmitConfig,
183      20  => TofCommandCode::SetDataPublisherConfig,
184      21  => TofCommandCode::SetLTBThresholds,
185      22  => TofCommandCode::SetMTConfig,
186      23  => TofCommandCode::SetTofRunConfig,
187      24  => TofCommandCode::SetTofRBConfig,
188      28  => TofCommandCode::SetPreampBias,
189      29  => TofCommandCode::SetTOFEventBuilderConfig,
190      30  => TofCommandCode::DataRunStop,
191      31  => TofCommandCode::DataRunStart,
192      32  => TofCommandCode::StartValidationRun,
193      41  => TofCommandCode::GetFullWaveforms,
194      53  => TofCommandCode::RBCalibration,
195      44  => TofCommandCode::UnspoolEventCache,
196      60  => TofCommandCode::RestartLiftofRBClients,
197      70  => TofCommandCode::Listen,
198      71  => TofCommandCode::Staging,
199      80  => TofCommandCode::Lock,
200      81  => TofCommandCode::Unlock,
201      90  => TofCommandCode::SendTofEvents,
202      91  => TofCommandCode::NoSendTofEvents,
203      92  => TofCommandCode::SendRBWaveforms,
204      93  => TofCommandCode::NoSendRBWaveforms,
205      100 => TofCommandCode::ShutdownRB,
206      101 => TofCommandCode::ChangeNextRunConfig,
207      102 => TofCommandCode::ShutdownRAT,
208      103 => TofCommandCode::ShutdownRATPair,
209      104 => TofCommandCode::ShutdownCPU,
210      105 => TofCommandCode::UploadConfig,
211      _   => TofCommandCode::Unknown
212    }
213  }
214}
215
216#[cfg(feature = "random")]
217impl FromRandom for TofCommandCode {
218  fn from_random() -> Self {
219    let choices = [
220      TofCommandCode::Unknown,
221      TofCommandCode::Ping,
222      TofCommandCode::Moni,
223      TofCommandCode::ResetConfigWDefault,
224      TofCommandCode::SubmitConfig,
225      TofCommandCode::SetDataPublisherConfig,
226      TofCommandCode::SetLTBThresholds,
227      TofCommandCode::SetMTConfig,
228      TofCommandCode::SetTofRunConfig,
229      TofCommandCode::SetTofRBConfig,
230      TofCommandCode::SetTOFEventBuilderConfig,
231      TofCommandCode::SetPreampBias,
232      TofCommandCode::DataRunStop,
233      TofCommandCode::DataRunStart,
234      TofCommandCode::StartValidationRun,
235      TofCommandCode::GetFullWaveforms,
236      TofCommandCode::RBCalibration,
237      TofCommandCode::UnspoolEventCache,
238      TofCommandCode::RestartLiftofRBClients,
239      TofCommandCode::Listen,
240      TofCommandCode::Staging,
241      TofCommandCode::Lock,
242      TofCommandCode::Unlock,
243      TofCommandCode::SendTofEvents,
244      TofCommandCode::NoSendTofEvents,
245      TofCommandCode::SendRBWaveforms,
246      TofCommandCode::NoSendRBWaveforms,
247      TofCommandCode::Kill,
248      TofCommandCode::ShutdownRB,
249      TofCommandCode::ChangeNextRunConfig,
250      TofCommandCode::ShutdownRAT,
251      TofCommandCode::ShutdownRATPair,
252      TofCommandCode::ShutdownCPU,
253      TofCommandCode::UploadConfig,
254    ];
255    let mut rng  = rand::thread_rng();
256    let idx = rng.gen_range(0..choices.len());
257    choices[idx]
258  }
259}
260
261///////////////////////////////////////////////////////////////////////////////
262
263/// A general command class with an arbitrary payload
264///
265/// Since the commands should in general be small
266/// the maixmal payload size is limited to 256 bytes
267///
268/// All commands will get broadcasted and the 
269/// receiver has to figure out if they have 
270/// to rect to that command
271#[derive(Debug, Clone, PartialEq)]
272pub struct TofCommandV2 {
273  pub command_code : TofCommandCode,
274  pub payload      : Vec<u8>,
275}
276
277impl TofCommandV2 {
278 // BFSW command header 144, 235, 86, 248, 70, 41, 7, 15,
279 pub fn new() -> Self {
280    Self {
281      command_code : TofCommandCode::Unknown,
282      payload      : Vec::<u8>::new(),
283    }
284  }
285
286  //pub fn from_config(cfg_file : String) -> Self {
287  //  let mut cmd = TofCommandV2::new();
288  //  cmd.command_code = TofCommandCode::UploadConfig:
289
290  //}
291
292  /// In case the command is supposed to change the next run configuration
293  /// we can create it with this function
294  ///
295  /// # Arguments
296  ///
297  ///   * key_value :  a list of keys and a single value (last item of the 
298  ///                  list
299  pub fn forge_changerunconfig(key_value : &Vec<String>) -> Self {
300    let mut cmd = TofCommandV2::new();
301    cmd.command_code = TofCommandCode::ChangeNextRunConfig;
302    if key_value.len() == 0 {
303      error!("Empty command!");
304      return cmd;
305    }
306    let mut payload_string = String::from("");
307    for k in 0..key_value.len() - 1 {
308      payload_string += &format!("{}::", key_value[k]);
309    }
310    payload_string += key_value.last().unwrap();
311    let mut payload = Vec::<u8>::new();
312    payload.extend_from_slice(payload_string.as_bytes());
313    cmd.payload = payload;
314    cmd
315  }
316
317  /// After the command has been unpackt, reconstruct the 
318  /// key/value string
319  pub fn extract_changerunconfig(&self) -> Option<Vec<String>> {
320    if self.command_code != TofCommandCode::ChangeNextRunConfig {
321      error!("Unable to extract configuration file changes from {}", self);
322      return None;
323    }
324    let mut liftof_config = Vec::<String>::new();
325    match String::from_utf8(self.payload.clone()) {
326      Err(err) => {
327        error!("Unable to extract the String payload! {err}");
328      }
329      Ok(concat_string) => {
330        let foo = concat_string.split("::").collect::<Vec<&str>>().into_iter();
331        for k in foo {
332          liftof_config.push(String::from(k));
333        }
334      }
335    }
336    Some(liftof_config)
337  }
338}
339
340impl Packable for TofCommandV2 {
341  const PACKET_TYPE : PacketType = PacketType::TofCommandV2;
342}
343
344impl Serialization for TofCommandV2 {
345  
346  const HEAD : u16 = 0xAAAA;
347  const TAIL : u16 = 0x5555;
348
349  fn from_bytestream(stream    : &Vec<u8>, 
350                     pos       : &mut usize) 
351    -> Result<Self, SerializationError>{
352    let mut command = TofCommandV2::new();
353    if parse_u16(stream, pos) != Self::HEAD {
354      error!("The given position {} does not point to a valid header signature of {}", pos, Self::HEAD);
355      return Err(SerializationError::HeadInvalid {});
356    }
357    command.command_code = TofCommandCode::from(parse_u8(stream, pos));
358    let payload_size     = parse_u8(stream, pos);
359    let payload          = stream[*pos..*pos + payload_size as usize].to_vec();
360    command.payload      = payload;
361    *pos += payload_size as usize;
362    let tail = parse_u16(stream, pos);
363    if tail != Self::TAIL {
364      error!("After parsing the event, we found an invalid tail signature {}", tail);
365      return Err(SerializationError::TailInvalid);
366    }
367    Ok(command)
368  }
369
370  fn to_bytestream(&self) -> Vec<u8> {
371    let mut stream = Vec::<u8>::with_capacity(9);
372    stream.extend_from_slice(&Self::HEAD.to_le_bytes());
373    stream.push(self.command_code as u8);
374    stream.push(self.payload.len() as u8);
375    stream.extend_from_slice(self.payload.as_slice());
376    stream.extend_from_slice(&Self::TAIL.to_le_bytes());
377    stream
378  }
379}
380
381impl Default for TofCommandV2 {
382  fn default() -> Self {
383    Self::new()
384  }
385}
386
387#[cfg(feature = "random")]
388impl FromRandom for TofCommandV2 {
389  fn from_random() -> Self {
390    let mut rng      = rand::thread_rng();
391    let command_code = TofCommandCode::from_random();
392    let payload_size = rng.gen::<u8>();
393    let mut payload  = Vec::<u8>::with_capacity(payload_size as usize);
394    for _ in 0..payload_size {
395      payload.push(rng.gen::<u8>());
396    }
397    Self {
398      command_code : command_code,
399      payload      : payload
400    }
401  }
402}
403
404impl fmt::Display for TofCommandV2 {
405  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
406    //let cc = RBCommand::command_code_to_string(self.command_code);
407    let mut repr = String::from("<TofCommandV2");
408    repr += &(format!("\n  cmd code : {}", self.command_code)); 
409    match self.command_code {
410      TofCommandCode::ShutdownRB 
411      | TofCommandCode::ShutdownRAT 
412      | TofCommandCode::ShutdownRATPair => {
413        repr += &(format!("\n Sending shutdown command to RBs {:?}>", self.payload));
414      }
415      _ => {
416        repr += ">";
417      }
418    }
419    write!(f, "{}", repr)
420  }
421}
422
423// Specific response codes
424// These are long (4 bytes) but 
425// this allows to convey more information
426// e.g. event id
427#[derive(Debug, Copy, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
428#[repr(u32)]
429pub enum TofResponseCode {
430  Unknown                            = 0u32,
431  /// response code for: Command can not be executed on the server side
432  RespErrUnexecutable                = 500u32,
433  RespErrAccessDenied                = 403u32,
434  RespErrNotImplemented              = 404u32, 
435  /// response code for: Something did not work quite right, 
436  /// however, the problem has either fixed itself or it is 
437  /// highly likely that if the command is issued again it 
438  /// will succeed.
439  RespErrLevelNoProblem              = 4000u32, 
440  RespErrLevelMedium                 = 4010u32, 
441  RespErrLevelSevere                 = 4020u32, 
442  /// response code for: A critical condition. This might need a fix somehow and can 
443  /// not be fixed automatically. Probably at least a power-cycle is necessary.
444  RespErrLevelCritical               = 4030u32, 
445  /// response code for: The severest error condition which can occur. This might
446  /// still be fixable, but it is probably a good advice to get help. Currently, 
447  /// the mission might be in a bad state.
448  RespErrLevelMissionCritical        = 4040u32, 
449  /// response code for: If you see this, it is probably reasonable to follow that advice..
450  /// Something unexplicable, which should never have happened, did happen and there is probably
451  /// no way to fix it. Call somebody if you see it, but probably the mission has failed.
452  RespErrLevelRunFoolRun             = 99999u32, 
453  /// response code for: The server has executed the command succesfully. 
454  /// THIS DOES NOT GUARANTEE THAT SERVER IS ACTUALLY DOING 
455  /// SOMETHING USEFUL, IT JUST ACKNOWLEDGES EXECUTION.
456  RespSuccFingersCrossed             = 200u32,
457  /// The command can't be executed since currently data taking is not active
458  RespErrNoRunActive                 = 501u32,
459  /// The command can't be executed since currently data taking is active
460  RespErrRunActive                   = 502u32,
461  /// The command got stuck somewhere and did not make it to the intended receiver
462  RespErrCmdStuck                    = 503u32
463}
464
465impl fmt::Display for TofResponseCode {
466  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
467    let r = serde_json::to_string(self).unwrap_or(
468      String::from("Error: cannot unwrap this TofResponseCode"));
469    write!(f, "<TofResponseCode: {}>", r)
470  }
471}
472
473impl From<u32> for TofResponseCode {
474  fn from(value: u32) -> Self {
475    match value {
476      500u32   => TofResponseCode::RespErrUnexecutable,
477      403u32   => TofResponseCode::RespErrAccessDenied,
478      404u32   => TofResponseCode::RespErrNotImplemented,
479      4000u32  => TofResponseCode::RespErrLevelNoProblem,
480      4010u32  => TofResponseCode::RespErrLevelMedium,
481      4020u32  => TofResponseCode::RespErrLevelSevere,
482      4030u32  => TofResponseCode::RespErrLevelCritical,
483      4040u32  => TofResponseCode::RespErrLevelMissionCritical,
484      99999u32 => TofResponseCode::RespErrLevelRunFoolRun,
485      200u32   => TofResponseCode::RespSuccFingersCrossed,
486      501u32   => TofResponseCode::RespErrNoRunActive,
487      502u32   => TofResponseCode::RespErrRunActive,
488      503u32   => TofResponseCode::RespErrCmdStuck,
489      _        => TofResponseCode::Unknown
490    }
491  }
492}
493
494#[cfg(feature = "random")]
495impl FromRandom for TofResponseCode {
496  
497  fn from_random() -> Self {
498    let choices = [
499      TofResponseCode::RespErrAccessDenied,
500      TofResponseCode::RespErrUnexecutable,
501      TofResponseCode::RespErrNotImplemented,
502      TofResponseCode::RespErrLevelNoProblem,
503      TofResponseCode::RespErrLevelMedium,
504      TofResponseCode::RespErrLevelSevere,
505      TofResponseCode::RespErrLevelCritical,
506      TofResponseCode::RespErrLevelMissionCritical,
507      TofResponseCode::RespErrLevelRunFoolRun,
508      TofResponseCode::RespSuccFingersCrossed,
509      TofResponseCode::RespErrNoRunActive,
510      TofResponseCode::RespErrRunActive,
511      TofResponseCode::RespErrCmdStuck
512    ];
513    let mut rng  = rand::thread_rng();
514    let idx = rng.gen_range(0..choices.len());
515    choices[idx]
516  }
517}
518
519/// How to operate the readout Default mode is to request
520/// events from the MasterTrigger. However, we can also stream
521/// all the waveforms.
522/// CAVEAT: For the whole tof, this will cap the rate at 
523/// 112 Hz, because of the capacity of the switches.
524#[derive(Debug, Copy, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
525#[repr(u8)]
526pub enum TofOperationMode {
527  Unknown          = 0u8,
528  Default          = 1u8,
529  //#[deprecated(since="0.8.3")] 
530  //StreamAny        = 10u8,
531  //#[deprecated(since="0.8.3")] 
532  //RequestReply     = 20u8,
533  /// Don't decode any of the event 
534  /// data on the RB, just push it 
535  /// onward
536  RBHighThroughput = 30u8,
537  RBCalcCRC32      = 40u8,
538  RBWaveform       = 50u8,
539}
540
541impl fmt::Display for TofOperationMode {
542  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
543    let r = serde_json::to_string(self).unwrap_or(
544      String::from("Error: cannot unwrap this TofOperationMode"));
545    write!(f, "<TofOperationMode: {}>", r)
546  }
547}
548
549impl From<u8> for TofOperationMode {
550  fn from(value: u8) -> Self {
551    match value {
552      0u8  => TofOperationMode::Unknown,
553      1u8  => TofOperationMode::Default,
554      //10u8 => TofOperationMode::StreamAny,
555      //20u8 => TofOperationMode::RequestReply,
556      30u8 => TofOperationMode::RBHighThroughput,
557      40u8 => TofOperationMode::RBCalcCRC32,
558      50u8 => TofOperationMode::RBWaveform,
559      _    => TofOperationMode::Unknown
560    }
561  }
562}
563
564#[cfg(feature = "random")]
565impl FromRandom for TofOperationMode {
566  
567  fn from_random() -> Self {
568    let choices = [
569      TofOperationMode::Unknown,
570      TofOperationMode::Default,
571      //TofOperationMode::RequestReply,
572      //TofOperationMode::StreamAny,
573      TofOperationMode::RBHighThroughput,
574      TofOperationMode::RBCalcCRC32,
575      TofOperationMode::RBWaveform,
576      TofOperationMode::Unknown
577    ];
578    let mut rng  = rand::thread_rng();
579    let idx = rng.gen_range(0..choices.len());
580    choices[idx]
581  }
582}
583
584//
585//
586//  pub fn command_code_to_string(cc : u8) -> String {
587//    match cc {
588//      Self::REQUEST_EVENT => {
589//        return String::from("GetReducedDataPacket");
590//      }
591//      _ => {
592//        return String::from("Unknown");
593//      }
594//    }
595//  }
596//}
597//
598
599/// General command class for ALL commands to the 
600/// tof C&C instance and readout boards
601///
602/// Each command can carry a 32bit field with further
603/// instructionns
604///
605#[derive(Debug, PartialEq, Copy, Clone, serde::Deserialize, serde::Serialize)]//, IntoEnumIterator)]
606pub enum TofCommand {
607  Unknown                 (u32),
608  Ping                    (u32),
609  Moni                    (u32),
610  Power                   (u32),
611  SetThresholds           (u32),
612  SetMTConfig             (u32),
613  SetPreampBias           (u32),
614  DataRunStop             (u32),
615  DataRunStart            (u32),
616  StartValidationRun      (u32),
617  GetFullWaveforms        (u32),
618  NoiCalibration          (u32),
619  VoltageCalibration      (u32),
620  TimingCalibration       (u32),
621  DefaultCalibration      (u32),
622  UnspoolEventCache       (u32),
623  TriggerModeForced       (u32),
624  TriggerModeForcedMTB    (u32),
625  SystemdReboot           (u32),
626  Listen                  (u32),
627  Lock                    (u32),
628  Unlock                  (u32),
629  Kill                    (u32),
630}
631
632impl Packable for TofCommand {
633  const PACKET_TYPE : PacketType = PacketType::TofCommand;
634}
635
636impl fmt::Display for TofCommand {
637  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
638    let r = serde_json::to_string(self).unwrap_or(
639      String::from("Error: cannot unwrap this TofCommand"));
640    write!(f, "<TofCommand: {}>", r)
641  }
642}
643
644impl TofCommand { 
645
646  // this can not fail
647  pub fn get_value(&self) -> u32 {
648    let value : u32;
649    match self {
650      TofCommand::Unknown                 (data) => { value = *data;}, 
651      TofCommand::Ping                    (data) => { value = *data;},
652      TofCommand::Moni                    (data) => { value = *data;},
653      TofCommand::Power                   (data) => { value = *data;},
654      TofCommand::SetThresholds           (data) => { value = *data;},
655      TofCommand::SetMTConfig             (data) => { value = *data;},
656      TofCommand::SetPreampBias           (data) => { value = *data;},
657      TofCommand::DataRunStop             (data) => { value = *data;},
658      TofCommand::DataRunStart            (data) => { value = *data;},
659      TofCommand::StartValidationRun      (data) => { value = *data;},
660      TofCommand::GetFullWaveforms        (data) => { value = *data;},
661      TofCommand::NoiCalibration          (data) => { value = *data;},
662      TofCommand::VoltageCalibration      (data) => { value = *data;},
663      TofCommand::TimingCalibration       (data) => { value = *data;},
664      TofCommand::DefaultCalibration      (data) => { value = *data;},
665      TofCommand::UnspoolEventCache       (data) => { value = *data;},
666      TofCommand::TriggerModeForced       (data) => { value = *data;},
667      TofCommand::TriggerModeForcedMTB    (data) => { value = *data;},
668      TofCommand::SystemdReboot           (data) => { value = *data;},
669      TofCommand::Listen                  (data) => { value = *data;}
670      TofCommand::Kill                    (data) => { value = *data;}
671      TofCommand::Lock                    (data) => { value = *data;}
672      TofCommand::Unlock                  (data) => { value = *data;}
673    }
674    value
675  }  
676
677  /// Generate a TofCommand from the specific bytecode
678  /// representation
679  pub fn from_command_code(cc : TofCommandCode, value : u32) -> TofCommand {
680    match cc {
681      TofCommandCode::Unknown                 => TofCommand::Unknown                 (value),
682      TofCommandCode::Ping                    => TofCommand::Ping                    (value),
683      TofCommandCode::Moni                    => TofCommand::Moni                    (value),
684      TofCommandCode::SetLTBThresholds        => TofCommand::SetThresholds           (value),
685      TofCommandCode::SetMTConfig             => TofCommand::SetMTConfig             (value),
686      TofCommandCode::SetPreampBias           => TofCommand::SetPreampBias           (value),
687      TofCommandCode::DataRunStop             => TofCommand::DataRunStop             (value),
688      TofCommandCode::DataRunStart            => TofCommand::DataRunStart            (value),
689      TofCommandCode::StartValidationRun      => TofCommand::StartValidationRun      (value),
690      TofCommandCode::GetFullWaveforms        => TofCommand::GetFullWaveforms        (value),
691      TofCommandCode::RBCalibration           => TofCommand::DefaultCalibration           (value),
692      TofCommandCode::UnspoolEventCache       => TofCommand::UnspoolEventCache       (value),
693      TofCommandCode::RestartLiftofRBClients  => TofCommand::SystemdReboot           (value),
694      TofCommandCode::Listen                  => TofCommand::Listen                  (value),
695      TofCommandCode::Kill                    => TofCommand::Kill                    (value),
696      TofCommandCode::Lock                    => TofCommand::Lock                    (value),
697      TofCommandCode::Unlock                  => TofCommand::Unlock                  (value),
698      _                                          => TofCommand::Unknown                 (value),
699    }
700  }
701    
702  /// Translate a TofCommand into its specific byte representation
703  pub fn to_command_code(cmd : &TofCommand) -> Option<TofCommandCode> {
704    match cmd {
705      TofCommand::Unknown                 (_) => Some(TofCommandCode::Unknown),
706      TofCommand::Power                   (_) => Some(TofCommandCode::Unknown),
707      TofCommand::NoiCalibration          (_) => Some(TofCommandCode::Unknown),
708      TofCommand::VoltageCalibration      (_) => Some(TofCommandCode::Unknown),
709      TofCommand::TimingCalibration       (_) => Some(TofCommandCode::Unknown),
710      TofCommand::TriggerModeForced       (_) => Some(TofCommandCode::Unknown),
711      TofCommand::TriggerModeForcedMTB    (_) => Some(TofCommandCode::Unknown),
712
713      TofCommand::Ping                    (_) => Some(TofCommandCode::Ping),
714      TofCommand::Moni                    (_) => Some(TofCommandCode::Moni),
715      TofCommand::SetThresholds           (_) => Some(TofCommandCode::SetLTBThresholds),
716      TofCommand::SetMTConfig             (_) => Some(TofCommandCode::SetMTConfig),
717      TofCommand::SetPreampBias           (_) => Some(TofCommandCode::SetPreampBias),
718      TofCommand::DataRunStop             (_) => Some(TofCommandCode::DataRunStop),
719      TofCommand::DataRunStart            (_) => Some(TofCommandCode::DataRunStart),
720      TofCommand::StartValidationRun      (_) => Some(TofCommandCode::StartValidationRun),
721      TofCommand::GetFullWaveforms        (_) => Some(TofCommandCode::GetFullWaveforms),
722      TofCommand::DefaultCalibration      (_) => Some(TofCommandCode::RBCalibration),
723      TofCommand::UnspoolEventCache       (_) => Some(TofCommandCode::UnspoolEventCache),
724      TofCommand::SystemdReboot           (_) => Some(TofCommandCode::RestartLiftofRBClients),
725      TofCommand::Listen                  (_) => Some(TofCommandCode::Listen),
726      TofCommand::Kill                    (_) => Some(TofCommandCode::Kill),
727      TofCommand::Lock                    (_) => Some(TofCommandCode::Lock),
728      TofCommand::Unlock                  (_) => Some(TofCommandCode::Unlock),
729    }
730  }
731
732  pub fn from_tof_packet(packet : &TofPacket) 
733    -> Option<TofCommand> {
734    match packet.packet_type {
735      PacketType::TofCommand => (),
736      _ => {
737        debug!("Packet doesn't have PacketType::TofCommand");
738        return None;
739        }
740    } // end match
741    let cmd_pk = TofCommand::from_bytestream(&packet.payload, &mut 0);
742    match cmd_pk {
743      Err(err) => {
744        warn!("Could not decode CMD packet, err {:?}", err);
745        return None;
746      }
747      Ok(cmd) => {
748        Some(cmd) 
749      }
750    } // end match
751  }
752} // end impl TofCommand
753
754//impl From<&TofPacket> for TofCommand {
755//  fn from(tp : &TofPacket) -> Self {
756
757impl From<(u8, u32)> for TofCommand {
758  
759  /// Generate a TofCommand from a pair of code, value
760  ///
761  /// The first argument must be the command code, the 
762  /// second the specific value of the command.
763  fn from(pair : (u8, u32)) -> TofCommand {
764    let (input, value) = pair;
765    trace!("Got in input {:?}", pair);
766    TofCommand::from_command_code(TofCommandCode::try_from(input).unwrap(), value)
767  }
768}
769
770#[cfg(feature = "random")]
771impl FromRandom for TofCommand {
772  
773  fn from_random() -> Self {
774    let mut rng  = rand::thread_rng();
775    let val = rng.gen::<u32>();
776    let choices = [
777      TofCommand::Unknown                 (val),
778      TofCommand::Ping                    (val),
779      TofCommand::Moni                    (val),
780      TofCommand::Power                   (val),
781      TofCommand::SetThresholds           (val),
782      TofCommand::SetMTConfig             (val),
783      TofCommand::SetPreampBias           (val),
784      TofCommand::DataRunStop             (val),
785      TofCommand::DataRunStart            (val),
786      TofCommand::StartValidationRun      (val),
787      TofCommand::GetFullWaveforms        (val),
788      TofCommand::NoiCalibration          (val),
789      TofCommand::VoltageCalibration      (val),
790      TofCommand::TimingCalibration       (val),
791      TofCommand::DefaultCalibration      (val),
792      TofCommand::UnspoolEventCache       (val),
793      TofCommand::TriggerModeForced       (val),
794      TofCommand::TriggerModeForcedMTB    (val),
795      TofCommand::SystemdReboot           (val),
796      TofCommand::Listen                  (val),
797      TofCommand::Kill                    (val),
798      TofCommand::Lock                    (val),
799      TofCommand::Unlock                  (val),
800    ];
801    let idx = rng.gen_range(0..choices.len());
802    choices[idx]
803  }
804}
805
806impl Serialization for TofCommand {
807  
808  const HEAD : u16 = 0xAAAA;
809  const TAIL : u16 = 0x5555;
810  ///// The size of TofCommand when 
811  ///// in byte representation is 
812  ///// fixed:
813  ///// it is 4 bytes (header/footer)
814  ///// + 1 byte command code
815  ///// + 4 bytes value
816  ///// => 9 bytes
817  const SIZE : usize = 9; 
818  
819  ///// Returns the serialized data stream
820  ///// as byte array
821  ///// 
822  ///// Might be faster thant its sister
823  ///// ::to_bytestream(), however is not
824  ///// a trait, since the return type 
825  ///// depends on the size. 
826  ///// FIXME - can we somehow make this 
827  ///// a trait? It seems we can not return 
828  ///// &[u8] when we have the corresponding
829  ///// array allocated in the function
830  //pub fn to_bytearray(&self) -> [u8;TofCommand::SIZE] {
831
832  //  let mut bytes = [0u8;TofCommand::SIZE];
833  //  bytes[0] = 0xAA;
834  //  bytes[1] = 0xAA;
835  //  bytes[2] = TofCommand::to_command_code(&self)
836  //    .expect("This can't fail, since this is implemented on MYSELF and I am a TofCommand!") as u8; 
837  //  let value_bytes = self.get_value().to_le_bytes();
838  // 
839  //  for n in 0..4 {
840  //    bytes[3+n] = value_bytes[n];
841  //  }
842  //  bytes[7] = 0x55;
843  //  bytes[8] = 0x55;
844  //  bytes
845  //}
846  
847  fn to_bytestream(&self) -> Vec<u8> {
848    //let mut stream = Vec::<u8>::with_capacity(TofCommand::SIZE);
849    let mut stream : Vec::<u8> = vec![0,0,0,0,0,0,0,0,0];
850    stream[0] = 0xAA;
851    stream[1] = 0xAA;
852    stream[2] = TofCommand::to_command_code(&self)
853      .expect("This can't fail, since this is implemented on MYSELF and I am a TofCommand!") as u8; 
854    let value_bytes = self.get_value().to_le_bytes();
855   
856    for n in 0..4 {
857      stream[3+n] = value_bytes[n];
858    }
859    stream[7] = 0x55;
860    stream[8] = 0x55;
861    stream
862  }
863
864
865  fn from_bytestream(stream    : &Vec<u8>, 
866                     pos       : &mut usize) 
867    -> Result<Self, SerializationError>{
868    Self::verify_fixed(stream, pos)?;  
869    let cc      = parse_u8(stream, pos);
870    let value   = parse_u32(stream, pos); 
871    let pair    = (cc, value);
872    let command = Self::from(pair);
873    *pos += 2; // for the TAIL
874    Ok(command)
875  }
876}
877
878/// Each `TofCommand` triggers a `TofResponse` in reply
879///
880/// The responses are general classes, which carry a more
881/// specific 32-bit response code.
882#[derive(Debug, Copy, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
883pub enum TofResponse {
884  Success(u32),
885  /// A unknown problem led to a non-execution
886  /// of the command. The error code should tell
887  /// more. A re-issue of the command might 
888  /// solve the problem.
889  GeneralFail(u32),
890  /// The requested event is not ready yet. This 
891  /// means, it is still lingering in the caches
892  /// of the readout boards. If this problem 
893  /// occurs many times, it might be helpful to 
894  /// reduce the cache size of the readoutboards 
895  /// to be more responsive.
896  /// The response code is the specific event id
897  /// we initially requested.
898  EventNotReady(u32),
899  /// Somehwere, a serialization error happened. 
900  /// It might be worth trying to execute that 
901  /// command again.
902  SerializationIssue(u32),
903  ZMQProblem(u32),
904  TimeOut(u32),
905  NotImplemented(u32),
906  AccessDenied(u32),
907  Unknown
908}
909
910impl Packable for TofResponse {
911  const PACKET_TYPE : PacketType = PacketType::TofResponse;
912}
913
914impl fmt::Display for TofResponse {
915  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
916    let r = serde_json::to_string(self).unwrap_or(
917      String::from("Error: cannot unwrap this TofResponse"));
918    write!(f, "<TofResponse: {}>", r)
919  }
920}
921
922#[cfg(feature = "random")]
923impl FromRandom for TofResponse {
924  
925  fn from_random() -> Self {
926    let mut rng  = rand::thread_rng();
927    let val = rng.gen::<u32>();
928    let choices = [
929      TofResponse::Success(val),
930      TofResponse::GeneralFail(val),
931      TofResponse::EventNotReady(val),
932      TofResponse::SerializationIssue(val),
933      TofResponse::ZMQProblem(val),
934      TofResponse::TimeOut(val),
935      TofResponse::NotImplemented(val),
936      TofResponse::AccessDenied(val),
937      TofResponse::Unknown,
938    ];
939    let idx = rng.gen_range(0..choices.len());
940    choices[idx]
941  }
942}
943
944
945impl Serialization for TofResponse {
946  const HEAD : u16   = 0xAAAA;
947  const TAIL : u16   = 0x5555;
948  const SIZE : usize = 9; //FIXME
949  
950  fn to_bytestream(&self) -> Vec<u8> {
951    let mut bytestream = Vec::<u8>::with_capacity(9);
952    bytestream.extend_from_slice(&Self::HEAD.to_le_bytes());
953    let cc = u8::from(*self);
954    bytestream.push(cc);
955    let mut value : u32 = 0;
956    match self {
957      TofResponse::Success(data)            => value = *data,
958      TofResponse::GeneralFail(data)        => value = *data,
959      TofResponse::EventNotReady(data)      => value = *data,
960      TofResponse::SerializationIssue(data) => value = *data,
961      TofResponse::ZMQProblem(data)         => value = *data,
962      TofResponse::TimeOut(data)            => value = *data,
963      TofResponse::NotImplemented(data)     => value = *data,
964      TofResponse::AccessDenied(data)       => value = *data,
965      TofResponse::Unknown => ()
966    }
967    bytestream.extend_from_slice(&value.to_le_bytes());
968    bytestream.extend_from_slice(&TofResponse::TAIL.to_le_bytes());
969    bytestream
970  }
971
972  fn from_bytestream(stream    : &Vec<u8>, 
973                     pos       : &mut usize) 
974    -> Result<TofResponse, SerializationError>{
975    Self::verify_fixed(stream, pos)?;  
976    let cc       = parse_u8(stream, pos);
977    let value    = parse_u32(stream, pos);
978    let pair     = (cc, value);
979    let response = TofResponse::from(pair);
980    *pos += 2; // acccount for TAIL
981    Ok(response)
982  }
983}
984
985impl From<TofResponse> for u8 {
986  fn from(input : TofResponse) -> u8 {
987    match input {
988      TofResponse::Success(_)            => 1,
989      TofResponse::GeneralFail(_)        => 2,
990      TofResponse::EventNotReady(_)      => 3,
991      TofResponse::SerializationIssue(_) => 4,
992      TofResponse::ZMQProblem(_)         => 5,
993      TofResponse::TimeOut(_)            => 6,
994      TofResponse::NotImplemented(_)     => 7,
995      TofResponse::AccessDenied(_)       => 8,
996      TofResponse::Unknown => 0
997    }
998  }
999}
1000
1001impl From<(u8, u32)> for TofResponse {
1002  fn from(pair : (u8, u32)) -> TofResponse {
1003    let (input, value) = pair;
1004    match input {
1005      1 => TofResponse::Success(value),
1006      2 => TofResponse::GeneralFail(value),
1007      3 => TofResponse::EventNotReady(value),
1008      4 => TofResponse::SerializationIssue(value),
1009      5 => TofResponse::ZMQProblem(value),
1010      6 => TofResponse::TimeOut(value),
1011      7 => TofResponse::NotImplemented(value),
1012      8 => TofResponse::AccessDenied(value),
1013      _ => TofResponse::Unknown
1014    }
1015  }
1016}
1017
1018#[cfg(feature = "random")]
1019#[test]
1020fn test_tofoperationmode() {
1021  let mut type_codes = Vec::<u8>::new();
1022  type_codes.push(TofOperationMode::Unknown as u8); 
1023  type_codes.push(TofOperationMode::Default as u8); 
1024  type_codes.push(TofOperationMode::RBHighThroughput as u8); 
1025  type_codes.push(TofOperationMode::RBWaveform as u8); 
1026  type_codes.push(TofOperationMode::RBCalcCRC32 as u8); 
1027  //type_codes.push(TofOperationMode::StreamAny as u8); 
1028  //type_codes.push(TofOperationMode::RequestReply as u8); 
1029  for tc in type_codes.iter() {
1030    assert_eq!(*tc,TofOperationMode::try_from(*tc).unwrap() as u8);  
1031  }
1032}
1033
1034#[cfg(feature = "random")]
1035#[test]
1036fn pack_tofresponse() {
1037  let resp = TofResponse::from_random();
1038  let test : TofResponse = resp.pack().unpack().unwrap();
1039  assert_eq!(resp, test);
1040}
1041
1042//#[cfg(feature = "random")]
1043//#[test]
1044//fn pack_tofcommand() {
1045//  for _ in 0..100 {
1046//    let cmd  = TofCommand::from_random();
1047//    let test : TofCommand = cmd.pack().unpack().unwrap();
1048//    assert_eq!(cmd, test);
1049//  }
1050//}
1051
1052#[cfg(feature = "random")]
1053#[test]
1054fn pack_tofcommandv2() {
1055  for _ in 0..100 {
1056    let cmd  = TofCommandV2::from_random();
1057    let test : TofCommandV2 = cmd.pack().unpack().unwrap();
1058    assert_eq!(cmd, test);
1059  }
1060}
1061
1062#[test]
1063fn forge_and_extract_tofcommandv2() {
1064  let input  = vec![String::from("foo"), String::from("bar"), String::from("baz")];
1065  let cmd    = TofCommandV2::forge_changerunconfig(&input);
1066  let output = cmd.extract_changerunconfig().unwrap();
1067  assert_eq!(input, output);
1068}