AlcapDAQ  1
crate.cpp
Go to the documentation of this file.
1 /*
2  Generic modular MIDAS readout program.
3 */
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <sys/time.h>
10 #include <sched.h>
11 
12 #include "midas.h"
13 #include "msystem.h"
14 
15 #include "odb_wrapper.h"
16 #include "crate.h"
17 #include "diag.h"
18 
19 /*
20  * MIDAS frontend boilerplate.
21  */
22 
23 /* from mfe.c */
24 extern int run_state;
25 extern int frontend_index;
26 
27 /* Interrupt state */
29 void (*interrupt_handler)() = NULL;
30 
31 /* The frontend name (client name) as seen by other MIDAS clients */
33 
34 /* The frontend file name, don't change it */
35 char *frontend_file_name = __FILE__;
36 
37 /* frontend_loop is called periodically if this variable is TRUE */
39 
40 /* a frontend status page is displayed with this frequency in ms */
41 //INT display_period = 500;
43 
44 /* maximum event size produced by this frontend */
45 #define MAX_DATA_SIZE 262144
47 
48 /* maximum event size for fragmented events (EQ_FRAGMENTED) */
50 
51 /* buffer size to hold events */
53 
54 /*-- Function declarations -----------------------------------------*/
55 extern "C" {
56  INT frontend_early_init();
57  INT frontend_init();
58  INT frontend_exit();
59  INT pre_begin_of_run(INT run_number, char *error);
60  INT begin_of_run(INT run_number, char *error);
61  INT end_of_run(INT run_number, char *error);
62  INT pause_run(INT run_number, char *error);
63  INT resume_run(INT run_number, char *error);
64  INT frontend_loop();
65  INT poll_event(INT source, INT count, BOOL test);
66  INT interrupt_configure(INT cmd, INT source, PTYPE adr);
67 };
68 INT read_trigger_event(char *pevent, INT off);
69 INT read_periodic_event(char *pevent, INT off);
70 
71 EQUIPMENT equipment[] = {
72  {"Crate ", /* equipment name */
73  {1000, TRIGGER_ALL, /* event ID, trigger mask */
74  "BUF", /* event buffer */
75  EQ_POLLED | EQ_EB, /* equipment type */
76  LAM_SOURCE(0, 0xFFFFFF), /* event source crate 0, all stations */
77  "MIDAS", /* format */
78  TRUE, /* enabled */
79  RO_RUNNING, /* read only when running */
80  500, /* poll for 500ms */
81  0, /* stop run after this event limit */
82  0, /* number of sub events */
83  0, /* don't log history */
84  "", "", ""},
85  read_trigger_event, /* readout routine */
86  },
87  {"Periodic N", /* equipment name */
88  {2000, 0, /* event ID, trigger mask */
89  "SYSTEM", /* event buffer */
90  EQ_PERIODIC, /* equipment type */
91  0, /* event source crate 0, all stations */
92  "MIDAS", /* format */
93  TRUE, /* enabled */
94  RO_RUNNING | RO_ODB, /* read only when running */
95  500, /* poll for 500ms */
96  0, /* stop run after this event limit */
97  0, /* number of sub events */
98  0, /* don't log history */
99  "", "", ""},
100  read_periodic_event, /* readout routine */
101  },
102  {""}
103 };
104 
105 /*
106  * List of modules in main fast event.
107  */
108 extern struct readout_module caenV767_module;
109 extern struct readout_module sis3600_module;
110 extern struct readout_module dl40x_module;
111 extern struct readout_module lrs2249_module;
112 extern struct readout_module vmic_ttl_module;
113 extern struct readout_module rpc_master_module;
114 extern struct readout_module rpc_slave_module;
115 
120  &dl40x_module,
123  &rpc_slave_module, // must be last!
124 };
125 int num_trigger_modules = sizeof(trigger_modules)/sizeof(trigger_modules[0]);
126 
127 struct timeval readout_finished_time;
128 
129 /*
130  * List of modules in periodic event.
131  */
132 extern struct readout_module s500_module;
133 
135  &s500_module,
136 };
137 int num_periodic_modules = sizeof(periodic_modules)/sizeof(periodic_modules[0]);
138 
139 int cycle_active = 0;
140 bool event_avail = false;
141 
142 bool between_runs = true;
143 
144 int crate_number = -1;
145 
146 /*
147  * frontend_early_init: Called before most MIDAS subsystems are initialized,
148  * so we can set the name (etc.) of the frontend here.
149  */
151 {
152  // Determine our crate ID by comparing against a list of hostnames
153 
154  char *hostnames[] = {"fe1", "fe2", "fe3", "turtle", "fe5", "fe6"};
155  int crate_numbers[] = {1, 2, 3, 4, 5, 6};
156  BOOL crate_has_periodic[] = {FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE};
157 
158  int num_hostnames = sizeof(hostnames)/sizeof(char *);
159  char my_hostname[256];
160 
161  gethostname(my_hostname, sizeof(my_hostname));
162 
163  BOOL has_periodic = FALSE;
164  for(int i = 0; i < num_hostnames; i++) {
165  if(!strcmp(my_hostname, hostnames[i])) {
166  crate_number = crate_numbers[i];
167  has_periodic = crate_has_periodic[i];
168  }
169  }
170 
171  if(crate_number > 0) {
172  frontend_name = new char[32];
173  strcpy(frontend_name, "Crate ");
174 
175 #if 0
176  sprintf(equipment[0].name, "Crate %d", crate_number);
177  sprintf(equipment[0].info.buffer, "BUF%d", crate_number);
178  equipment[0].info.event_id = 1000 + crate_number;
179 #endif
181 
182  if(has_periodic) {
183  sprintf(equipment[1].name, "Periodic %d", crate_number);
184  equipment[1].info.event_id = 2000 + crate_number;
185  } else {
186  sprintf(equipment[1].name, "");
187  }
188  }
189 
190  return SUCCESS;
191 }
192 
193 /* ********************************************************************* */
194 /*
195  * frontend_init: When the frontend program is started. This routine
196  * should initialize the hardware.
197  */
198 INT frontend_init()
199 {
200  INT run_state = odb_get_int("/Runinfo/State");
201  if (run_state != STATE_STOPPED) {
202  cm_msg(MERROR, "Crate",
203  "Run must be stopped before starting crate program.");
204  return FE_ERR_HW;
205  }
206 
207  for(int i = 0; i < num_trigger_modules; i++) {
208  if((*trigger_modules[i]).init != NULL) {
209  int status = (*trigger_modules[i]).init();
210  if(status != SUCCESS) {
211  return status;
212  }
213  }
214  }
215 
216  for(int i = 0; i < num_periodic_modules; i++) {
217  if((*periodic_modules[i]).init != NULL) {
218  int status = (*periodic_modules[i]).init();
219  if(status != SUCCESS) {
220  return status;
221  }
222  }
223  }
224 
225 
226  return SUCCESS;
227 }
228 
229 /* ********************************************************************* */
230 /*
231  * frontend_exit: When the frontend program is shut down. Can be used
232  * to release any locked resources like memory, commu-
233  * nications ports etc.
234  */
235 INT frontend_exit()
236 {
237  for(int i = 0; i < num_trigger_modules; i++) {
238  if((*trigger_modules[i]).exit != NULL) {
239  (*trigger_modules[i]).exit();
240  }
241  }
242 
243  for(int i = 0; i < num_periodic_modules; i++) {
244  if((*periodic_modules[i]).exit != NULL) {
245  (*periodic_modules[i]).exit();
246  }
247  }
248 
249  return SUCCESS;
250 }
251 
252 /*
253  * pre_begin_of_run: Called before a new run is started.
254  */
255 INT pre_begin_of_run(INT run_number, char *error)
256 {
257  diag_print(1, "*** Before begin of run %d ***\n", run_number);
258 
259  for(int i = 0; i < num_trigger_modules; i++) {
260  if((*trigger_modules[i]).pre_bor != NULL) {
261  int status = (*trigger_modules[i]).pre_bor();
262  if(status != SUCCESS) {
263  return status;
264  }
265  }
266  }
267 
268  for(int i = 0; i < num_periodic_modules; i++) {
269  if((*periodic_modules[i]).pre_bor != NULL) {
270  int status = (*periodic_modules[i]).pre_bor();
271  if(status != SUCCESS) {
272  return status;
273  }
274  }
275  }
276 
277 
278  return SUCCESS;
279 }
280 
281 /* ********************************************************************* */
282 /*
283  * begin_of_run: When a new run is started. Clear scalers, open
284  * rungates, etc.
285  */
286 INT begin_of_run(INT run_number, char *error)
287 {
288  diag_print(1, "*** Begin of run %d ***\n", run_number);
289 
290  for(int i = 0; i < num_trigger_modules; i++) {
291  if((*trigger_modules[i]).bor != NULL) {
292  int status = (*trigger_modules[i]).bor();
293  if(status != SUCCESS) {
294  return status;
295  }
296  }
297  }
298 
299  for(int i = 0; i < num_periodic_modules; i++) {
300  if((*periodic_modules[i]).bor != NULL) {
301  int status = (*periodic_modules[i]).bor();
302  if(status != SUCCESS) {
303  return status;
304  }
305  }
306  }
307 
308  cycle_active = 0;
309  event_avail = false;
310 
311  between_runs = false;
312 
313  return SUCCESS;
314 }
315 
316 /* ********************************************************************* */
317 /*
318  * end_of_run: Called on a request to stop a run. Can send
319  * end-of-run event and close run gates.
320  */
321 INT end_of_run(INT run_number, char *error)
322 {
323  diag_print(1, "*** End of run %d ***\n", run_number);
324 
325  between_runs = true;
326 
327  for(int i = 0; i < num_trigger_modules; i++) {
328  if((*trigger_modules[i]).eor != NULL) {
329  int status = (*trigger_modules[i]).eor();
330  if(status != SUCCESS) {
331  return status;
332  }
333  }
334  }
335 
336  for(int i = 0; i < num_periodic_modules; i++) {
337  if((*periodic_modules[i]).eor != NULL) {
338  int status = (*periodic_modules[i]).eor();
339  if(status != SUCCESS) {
340  return status;
341  }
342  }
343  }
344 
345 
346  return SUCCESS;
347 }
348 
349 /* ********************************************************************* */
350 /*
351  * pause_run: When a run is paused. Should disable trigger events.
352  */
353 INT pause_run(INT run_number, char *error)
354 {
355  return SUCCESS;
356 }
357 
358 /* ********************************************************************* */
359 /*
360  * resume_run: When a run is resumed. Should enable trigger events.
361  */
362 INT resume_run(INT run_number, char *error)
363 {
364  return SUCCESS;
365 }
366 
367 /* ********************************************************************* */
368 /*
369  * start_cycle
370  */
372 {
373  struct timeval restart_time;
374  gettimeofday(&restart_time, NULL);
375 
376  for(int i = 0; i < num_trigger_modules; i++) {
377  if((*trigger_modules[i]).start_cycle != NULL) {
378  (*trigger_modules[i]).start_cycle();
379  }
380  }
381 
382  diag_print(2, "Waited %f microseconds for restart.\n",
383  (restart_time.tv_sec-readout_finished_time.tv_sec)*1e6 +
384  (restart_time.tv_usec-readout_finished_time.tv_usec));
385 
386  cycle_active = 1;
387 }
388 
389 /*
390  * consider_start
391  */
393 {
394  for(int i = 0; i < num_trigger_modules; i++) {
395  if((*trigger_modules[i]).poll_dead != NULL) {
396  int status = (*trigger_modules[i]).poll_dead();
397 
398  if(status == FE_NEED_START && !event_avail) {
399  start_cycle();
400  } else if(status != SUCCESS) {
401  return status;
402  }
403  }
404  }
405 
406 }
407 
408 /*
409  * stop_cycle
410  */
412 {
413  for(int i = 0; i < num_trigger_modules; i++) {
414  if((*trigger_modules[i]).stop_cycle != NULL) {
415  (*trigger_modules[i]).stop_cycle();
416  }
417  }
418 }
419 
420 /* ********************************************************************* */
421 /*
422  * If frontend_call_loop is true, this routine gets called when
423  * the frontend is idle or once between every event
424  */
425 INT frontend_loop()
426 {
427  // If we're going to be pre-empted, get it over with during livetime
428  // rather than deadtime.
429  if (cycle_active || run_state != STATE_RUNNING || between_runs == TRUE) {
430  dm_area_flush();
431  sched_yield();
432  }
433 
434  // Exit immediately if no run in progress
435  if (run_state != STATE_RUNNING || between_runs == TRUE) {
436  return SUCCESS;
437  }
438 
439  // Call appropriate poll functions, depending on whether we're live or dead
440  if (cycle_active) {
441 
442  for(int i = 0; i < num_trigger_modules; i++) {
443  if((*trigger_modules[i]).poll_live != NULL) {
444 
445  // There are conditions that can lead to changes in run state between
446  // modules...
447  if (run_state != STATE_RUNNING || between_runs == TRUE) {
448  return SUCCESS;
449  }
450  int status = (*trigger_modules[i]).poll_live();
451 
452  if(status == FE_END_BLOCK) {
453  cycle_active = 0;
454  event_avail = true;
455  } else if(status == FE_NEED_STOP) {
456  stop_cycle();
457  } else if(status != SUCCESS) {
458  return status;
459  }
460  }
461  }
462  } else {
463  consider_start();
464  }
465 
466  return SUCCESS;
467 }
468 
469 /* ********************************************************************* */
470 /*
471  * Polling routine for events. Returns TRUE if event
472  * is available. If test equals TRUE, don't return. The test
473  * flag is used to time the polling.
474  */
475 INT poll_event(INT source, INT count, BOOL test)
476 {
477  INT retval = false;
478 
479  if(!test) {
480  count = 1;
481  }
482 
483  for (int i = 0; i < count; i++) {
484  frontend_loop();
485  if(event_avail) {
486  retval = true;
487  }
488  }
489 
490  return retval;
491 }
492 
493 /* ********************************************************************* */
494 INT interrupt_configure(INT cmd, INT source, PTYPE adr)
495 {
496  switch (cmd) {
497  case CMD_INTERRUPT_ENABLE:
499  break;
500  case CMD_INTERRUPT_DISABLE:
502  break;
503  case CMD_INTERRUPT_ATTACH:
504  interrupt_handler = (void (*)(void)) adr;
505  break;
506  case CMD_INTERRUPT_DETACH:
508  interrupt_handler = NULL;
509  break;
510  }
511  return SUCCESS;
512 }
513 
514 void print_diag_output(char *pevent)
515 {
516  printf("--------\n");
517 
518  printf("Event number: %d\n", (((EVENT_HEADER *)pevent)-1)->serial_number);
519 
520  BANK32 *pbk = NULL;
521  do {
522  DWORD *pdata;
523  int size = bk_iterate32(pevent, &pbk, &pdata);
524  if(pbk != NULL) {
525  printf("%c%c%c%c\t%d\t\t", pbk->name[0], pbk->name[1], pbk->name[2],
526  pbk->name[3], size);
527  for(int i = 0; i < MIN(4, size/4); i++) {
528  printf("0x%08x ", pdata[i]);
529  }
530  printf("\n");
531  }
532  } while(pbk != NULL);
533 
534  printf("--------\n");
535 }
536 
537 /* ********************************************************************* */
538 INT read_trigger_event(char *pevent, INT off)
539 {
540  diag_print(2, "Event has ended. Executing read_trigger_event.\n");
541 
542  // Remember that we have read out this event
543  event_avail = false;
544 
545  // Initialize the event
546  bk_init32(pevent);
547 
548  // Protection against readout after run has ended.
549  if (run_state != STATE_RUNNING) {
550  diag_print(1, "Readout after end of run!!!\n");
551  return bk_size(pevent);
552  }
553 
554  struct timeval readout_start_time;
555  gettimeofday(&readout_start_time, NULL);
556  // Ask trigger_modules to read out
557  for(int i = 0; i < num_trigger_modules; i++) {
558  if((*trigger_modules[i]).read != NULL) {
559  int status = (*trigger_modules[i]).read(pevent);
560  if(status != SUCCESS) {
561  return status;
562  }
563  }
564  }
565  gettimeofday(&readout_finished_time, NULL);
566  diag_print(2, "Spent %f microseconds for readout.\n",
567  (readout_finished_time.tv_sec-readout_start_time.tv_sec)*1e6 +
568  (readout_finished_time.tv_usec-readout_start_time.tv_usec));
569 
570  // Consider starting up the next block
571  consider_start();
572 
573  // Print a diagnostic
574  if(diag_print_threshold >= 2) {
575  print_diag_output(pevent);
576  }
577 
578  return bk_size(pevent);
579 }
580 
581 /* ********************************************************************* */
582 INT read_periodic_event(char *pevent, INT off)
583 {
584  diag_print(2, "Periodic event readout:\n");
585 
586  // Initialize the event
587  bk_init32(pevent);
588 
589  // Ask periodic_modules to read out
590  for(int i = 0; i < num_periodic_modules; i++) {
591  if((*periodic_modules[i]).read != NULL) {
592  int status = (*periodic_modules[i]).read(pevent);
593  if(status != SUCCESS) {
594  return status;
595  }
596  }
597  }
598 
599  // Print a diagnostic
600  if(diag_print_threshold >= 2) {
601  print_diag_output(pevent);
602  }
603 
604 
605  return bk_size(pevent);
606 }