AlcapDAQ  1
mfe_mucap.c
Go to the documentation of this file.
1 /********************************************************************\
2 
3  Name: mfe.c
4  Created by: Stefan Ritt
5 
6  Contents: The system part of the MIDAS frontend. Has to be
7  linked with user code to form a complete frontend
8 
9  ** muCap patches **
10  - added frontend_early_init() to allow the frontend to modify its name
11  and equipment structure.
12  - added extra transition function pre_begin_of_run().
13  - turned off buffer caching, which doesn't make sense for our large
14  event sizes and which seemed to lead to instability.
15  - turned on "event channel."
16 
17  $Log: mfe.c,v $
18  Revision 1.71 2004/10/01 23:35:53 midas
19  Removed PRE/POST transitions and implemented sequence order of transitions
20 
21  Revision 1.70 2004/09/29 19:38:20 midas
22  Decreased run stop polling time from 500ms to 100ms
23 
24  Revision 1.69 2004/09/29 00:16:21 midas
25  Fixed shutdown problem with EB frontends
26 
27  Revision 1.68 2004/09/28 23:56:53 midas
28  Added -i flag and EQ_EB flag for event building
29 
30  Revision 1.67 2004/09/24 21:42:17 midas
31  Send manually triggered events in scheduler
32 
33  Revision 1.66 2004/09/21 21:09:15 midas
34  Updated event statistics to ODB properly at EOR
35 
36  Revision 1.65 2004/05/07 19:40:11 midas
37  Replaced min/max by MIN/MAX macros
38 
39  Revision 1.64 2004/03/26 09:31:56 midas
40  Converted pritnf() to cm_msg() for statistics record error
41 
42  Revision 1.63 2004/03/19 09:31:43 midas
43  Re-formatted comments
44 
45  Revision 1.62 2004/01/08 08:40:10 midas
46  Implemented standard indentation
47 
48  Revision 1.61 2003/11/24 08:22:46 midas
49  Changed timeouts from INT to DWORD, added ignore_timeout to cm_cleanup, adde '-f' flag to ODBEdit 'cleanup'
50 
51  Revision 1.60 2003/11/20 11:29:44 midas
52  Implemented db_check_record and use it in most places instead of db_create_record
53 
54  Revision 1.59 2003/11/01 00:48:14 olchansk
55  abort if cannot read /runinfo/run number
56  abort if run number resets to zero
57 
58  Revision 1.58 2003/10/29 15:33:48 midas
59  Properly display message about stopped previous frontend
60 
61  Revision 1.57 2003/09/30 19:47:57 midas
62  Removed tabs
63 
64  Revision 1.56 2003/09/30 18:30:07 midas
65  Put CNAF functionality under #ifdef HAVE_CAMAC
66 
67  Revision 1.55 2003/05/09 07:40:04 midas
68  Added extra parameter to cm_get_environment
69 
70  Revision 1.54 2003/05/07 10:57:10 midas
71  Removed tabs
72 
73  Revision 1.53 2003/04/25 10:41:42 midas
74  Removed FTCP mode in update_odb()
75 
76  Revision 1.52 2003/04/25 07:45:03 midas
77  Write first event to ODB only if logger uses ROOT format
78 
79  Revision 1.51 2003/04/14 12:40:23 midas
80  Create ODB entries for structured banks derived from BANK_LIST in frontend.c
81 
82  Revision 1.50 2003/04/14 05:12:54 pierre
83  fix send_event for handle=0
84 
85  Revision 1.49 2003/04/01 19:22:44 pierre
86  fix update_odb for hKeyl copy
87 
88  Revision 1.48 2003/03/31 08:27:34 midas
89  Fixed alignment bug for strings
90 
91  Revision 1.47 2003/03/28 09:13:05 midas
92  Added warning for uncreated structured banks
93 
94  Revision 1.46 2003/03/28 08:55:11 midas
95  Added code for structured banks
96 
97  Revision 1.45 2002/10/15 18:44:23 olchansk
98  fix printf() and cm_msg() format mismatches
99 
100  Revision 1.44 2002/10/15 18:15:25 olchansk
101  disable dtsout, stderr buffering,
102  catch-ignore SIGPIPE
103 
104  Revision 1.43 2002/10/15 18:13:59 olchansk
105  always recreate the statistics record.
106 
107  Revision 1.42 2002/10/15 18:09:59 olchansk
108  catch bm_xxx() errors and bail out from schedule(). This fixes infinite looping after rpc timeouts.
109 
110  Revision 1.41 2002/09/13 07:32:47 midas
111  Added client name to cm_cleanup()
112 
113  Revision 1.40 2002/06/03 06:07:15 midas
114  Added extra parameter to ss_daemon_init to keep stdout
115 
116  Revision 1.39 2002/05/15 23:43:56 midas
117  Added event fragmentation
118 
119  Revision 1.38 2002/05/10 01:41:19 midas
120  Added optional debug output to cm_transition
121 
122  Revision 1.37 2002/05/08 19:54:40 midas
123  Added extra parameter to function db_get_value()
124 
125  Revision 1.36 2001/11/21 08:37:32 midas
126  Took out db_delete_key for statistics again (not needed)
127 
128  Revision 1.35 2001/11/20 19:22:07 pierre
129  - Add rpc_flush_event in case no periodic eqp
130  - Force rpc_flush_event for low trigger rate
131  - Patch /Statistics in case it exists but size=0
132 
133  Revision 1.34 2001/06/27 12:34:49 midas
134  Added -D flag to become a daemon
135 
136  Revision 1.33 2001/04/06 04:13:40 midas
137  Put cm_cleanup() in init code
138 
139  Revision 1.32 2001/01/29 09:50:53 midas
140  Changed send_event() parameter from event_id to equipment index
141 
142  Revision 1.31 2000/11/14 08:30:03 midas
143  SLOW events are not any more sent to the ODB when the history is on
144 
145  Revision 1.30 2000/11/06 10:10:23 midas
146  Flush events for set-ups with only non-periodic events
147 
148  Revision 1.29 2000/10/23 14:19:06 midas
149  Added idle period for slow control equipment
150 
151  Revision 1.28 2000/09/28 13:16:02 midas
152  Fixed bug that MANUAL_TRIG only events are not read out during transitions
153 
154  Revision 1.27 2000/09/28 13:02:03 midas
155  Added manual triggered events
156 
157  Revision 1.26 2000/08/21 11:01:11 midas
158  Changed comments
159 
160  Revision 1.25 2000/08/21 10:44:58 midas
161  Removed reconnect functionality, it's better to restart the frontend via
162  /programs/frontend/auto restart.
163 
164  Revision 1.24 2000/08/21 10:36:41 midas
165  Reworked event and event buffer sizes:
166  - Both max_event_size and event_buffer_size must be defined in user code
167  - While max_event_size is used for frontend buffers, MAX_EVENT_SIZE is the
168  system limit which must be larger than max_event_size
169  - Event size returned from user readout routine is now checked against event
170  size limits
171  - Buffer settings are now always displayed, not only under VxWorks
172 
173  Revision 1.23 2000/08/09 12:02:43 midas
174  Evaluate return status in tr_xxx functions properly
175 
176  Revision 1.22 2000/08/09 11:37:56 midas
177  Rearranged serial number increments
178 
179  Revision 1.21 2000/07/11 16:43:40 pierre
180  - Fix serial number for POLL super event.
181 
182  Revision 1.20 2000/04/03 12:27:43 midas
183  Changed auto restart to 20 seconds in main loop
184 
185  Revision 1.19 2000/03/22 14:42:48 midas
186  Fixed bug with invalid pointer
187 
188  Revision 1.18 2000/03/17 13:00:05 midas
189  Frontends use default timeout fo 60 sec.
190 
191  Revision 1.17 2000/03/01 23:29:20 midas
192  Fixed bug with wrong event header data size in super eventsvents mfe.c
193 
194  Revision 1.16 2000/02/29 21:59:45 midas
195  Added auto restart
196 
197  Revision 1.15 2000/02/26 01:25:54 midas
198  Fixed bug that number of sent events was not cleared at start
199 
200  Revision 1.14 2000/02/25 20:22:49 midas
201  Added super-event scheme
202 
203  Revision 1.13 2000/02/24 22:38:19 midas
204  Outcommented USE_EVENT_CHANNEL
205 
206  Revision 1.12 2000/02/24 22:29:24 midas
207  Added deferred transitions
208 
209  Revision 1.11 1999/12/08 00:50:29 pierre
210  - fix EVID (ybos: strncpy to strncmp)
211 
212  Revision 1.10 1999/11/24 00:49:59 pierre
213  - YBOS reject EVID bank in udpate_odb with eb_functions
214 
215  Revision 1.9 1999/11/23 18:25:25 pierre
216  - YBOS reject EVID bank in udpate_odb
217 
218  Revision 1.8 1999/10/18 14:41:51 midas
219  Use /programs/<name>/Watchdog timeout in all programs as timeout value. The
220  default value can be submitted by calling cm_connect_experiment1(..., timeout)
221 
222  Revision 1.7 1999/10/15 12:17:52 midas
223  Increased timeout
224 
225  Revision 1.6 1999/09/27 13:49:04 midas
226  Added bUnique parameter to cm_shutdown
227 
228  Revision 1.5 1999/09/23 12:45:48 midas
229  Added 32 bit banks
230 
231  Revision 1.4 1999/06/23 09:38:51 midas
232  - Added D8_BKTYPE
233  - Fixed CAMAC server F24 bug
234  - cm_synchronize only called for VxWorks
235 
236  Revision 1.3 1998/12/10 12:50:47 midas
237  Program abort with "!" now works without a return under UNIX
238 
239  Revision 1.2 1998/10/12 12:19:01 midas
240  Added Log tag in header
241 
242 
243 \********************************************************************/
244 
245 #include <stdio.h>
246 #include <assert.h>
247 #include "midas.h"
248 #include "msystem.h"
249 #include "mcstd.h"
250 
251 #ifdef YBOS_SUPPORT
252 #include "ybos.h"
253 #endif
254 
255 /*------------------------------------------------------------------*/
256 
257 /* items defined in frontend.c */
258 
259 extern char *frontend_name;
260 extern char *frontend_file_name;
261 extern int crate_number;
262 extern BOOL frontend_call_loop;
263 extern INT max_event_size;
264 extern INT max_event_size_frag;
265 extern INT event_buffer_size;
266 extern INT display_period;
267 extern INT frontend_init(void);
268 extern INT frontend_exit(void);
269 extern INT frontend_loop(void);
270 extern INT begin_of_run(INT run_number, char *error);
271 extern INT end_of_run(INT run_number, char *error);
272 extern INT pause_run(INT run_number, char *error);
273 extern INT resume_run(INT run_number, char *error);
274 extern INT poll_event(INT source, INT count, BOOL test);
275 extern INT interrupt_configure(INT cmd, INT source, PTYPE adr);
276 
277 #ifdef PART_OF_MUCAP
278 extern INT frontend_early_init(void);
279 extern INT pre_begin_of_run(INT run_number, char *error);
280 #endif
281 
282 /*------------------------------------------------------------------*/
283 
284 /* globals */
285 
286 #ifdef PART_OF_MUCAP
287 #define USE_EVENT_CHANNEL 1
288 #define SERVER_CACHE_SIZE 0
289 #else
290 #undef USE_EVENT_CHANNEL
291 #define SERVER_CACHE_SIZE 100000 /* event cache before buffer */
292 #endif
293 
294 
295 #define ODB_UPDATE_TIME 1000 /* 1 seconds for ODB update */
296 
297 #define DEFAULT_FE_TIMEOUT 60000 /* 60 seconds for watchdog timeout */
298 
299 INT run_state; /* STATE_RUNNING, STATE_STOPPED, STATE_PAUSED */
301 DWORD actual_time; /* current time in seconds since 1970 */
302 DWORD actual_millitime; /* current time in milliseconds */
303 
304 char host_name[HOST_NAME_LENGTH];
305 char exp_name[NAME_LENGTH];
307 
309 INT optimize = 0; /* set this to one to opimize TCP buffer size */
310 INT fe_stop = 0; /* stop switch for VxWorks */
311 BOOL debug; /* disable watchdog messages from server */
312 DWORD auto_restart = 0; /* restart run after event limit reached stop */
313 INT manual_trigger_event_id = 0; /* set from the manual_trigger callback */
314 INT frontend_index = -1; /* frontend index for event building */
315 
316 HNDLE hDB;
317 
318 #ifdef YBOS_SUPPORT
319 struct {
320  DWORD ybos_type;
321  DWORD odb_type;
322  INT tsize;
323 } id_map[] = {
324  {
325  A1_BKTYPE, TID_CHAR, 1}, {
326  I1_BKTYPE, TID_BYTE, 1}, {
327  I2_BKTYPE, TID_WORD, 2}, {
328  I4_BKTYPE, TID_DWORD, 4}, {
329  F4_BKTYPE, TID_FLOAT, 4}, {
330  D8_BKTYPE, TID_DOUBLE, 8}, {
331  0, 0}
332 };
333 #endif
334 
335 extern EQUIPMENT equipment[];
336 
337 EQUIPMENT *interrupt_eq = NULL;
338 EVENT_HEADER *interrupt_odb_buffer;
340 
341 int send_event(INT index);
342 void send_all_periodic_events(INT transition);
343 void interrupt_routine(void);
344 void interrupt_enable(BOOL flag);
345 void display(BOOL bInit);
346 
347 /*---- ODB records -------------------------------------------------*/
348 
349 #define EQUIPMENT_COMMON_STR "\
350 Event ID = WORD : 0\n\
351 Trigger mask = WORD : 0\n\
352 Buffer = STRING : [32] SYSTEM\n\
353 Type = INT : 0\n\
354 Source = INT : 0\n\
355 Format = STRING : [8] FIXED\n\
356 Enabled = BOOL : 0\n\
357 Read on = INT : 0\n\
358 Period = INT : 0\n\
359 Event limit = DOUBLE : 0\n\
360 Num subevents = DWORD : 0\n\
361 Log history = INT : 0\n\
362 Frontend host = STRING : [32] \n\
363 Frontend name = STRING : [32] \n\
364 Frontend file name = STRING : [256] \n\
365 "
366 
367 #define EQUIPMENT_STATISTICS_STR "\
368 Events sent = DOUBLE : 0\n\
369 Events per sec. = DOUBLE : 0\n\
370 kBytes per sec. = DOUBLE : 0\n\
371 "
372 
373 /*-- transition callbacks ------------------------------------------*/
374 
375 /*-- start ---------------------------------------------------------*/
376 
377 #ifdef PART_OF_MUCAP
378 /*-- prestart ---------------------------------------------------------*/
379 
380 INT tr_prestart(INT rn, char *error)
381 {
382  INT status;
383  status = pre_begin_of_run(rn, error);
384  return status;
385 }
386 #endif
387 
388 INT tr_start(INT rn, char *error)
389 {
390  INT i, status;
391 
392  /* reset serial numbers */
393  for (i = 0; equipment[i].name[0]; i++) {
394  equipment[i].serial_number = 1;
395  equipment[i].subevent_number = 0;
396  equipment[i].stats.events_sent = 0;
397  equipment[i].odb_in = equipment[i].odb_out = 0;
398  }
399 
400  status = begin_of_run(rn, error);
401 
402  if (status == CM_SUCCESS) {
403  run_state = STATE_RUNNING;
404  run_number = rn;
405 
406  send_all_periodic_events(TR_START);
407 
408  if (display_period) {
409  ss_printf(14, 2, "Running ");
410  ss_printf(36, 2, "%d", rn);
411  }
412 
413  /* enable interrupts */
415  }
416 
417  return status;
418 }
419 
420 /*-- prestop -------------------------------------------------------*/
421 
422 INT tr_stop(INT rn, char *error)
423 {
424  INT status, i;
425  EQUIPMENT *eq;
426 
427  /* disable interrupts */
429 
430  status = end_of_run(rn, error);
431 
432  if (status == CM_SUCCESS) {
433  /* don't send events if already stopped */
434  if (run_state != STATE_STOPPED)
435  send_all_periodic_events(TR_STOP);
436 
437  run_state = STATE_STOPPED;
438  run_number = rn;
439 
440  if (display_period)
441  ss_printf(14, 2, "Stopped ");
442  } else
444 
445  /* flush remaining buffered events */
446  rpc_flush_event();
447  for (i = 0; equipment[i].name[0]; i++)
448  if (equipment[i].buffer_handle) {
449  INT err = bm_flush_cache(equipment[i].buffer_handle, SYNC);
450  if (err != BM_SUCCESS) {
451  cm_msg(MERROR, "tr_prestop", "bm_flush_cache(SYNC) error %d", err);
452  return err;
453  }
454  }
455 
456  /* update final statistics record in ODB */
457  for (i = 0; equipment[i].name[0]; i++) {
458  eq = &equipment[i];
459  eq->stats.events_sent += eq->events_sent;
460  eq->bytes_sent = 0;
461  eq->events_sent = 0;
462  }
463 
464  db_send_changed_records();
465 
466  return status;
467 }
468 
469 /*-- pause ---------------------------------------------------------*/
470 
471 INT tr_pause(INT rn, char *error)
472 {
473  INT status;
474 
475  /* disable interrupts */
477 
478  status = pause_run(rn, error);
479 
480  if (status == CM_SUCCESS) {
481  run_state = STATE_PAUSED;
482  run_number = rn;
483 
484  send_all_periodic_events(TR_PAUSE);
485 
486  if (display_period)
487  ss_printf(14, 2, "Paused ");
488  } else
490 
491  return status;
492 }
493 
494 /*-- resume --------------------------------------------------------*/
495 
496 INT tr_resume(INT rn, char *error)
497 {
498  INT status;
499 
500  status = resume_run(rn, error);
501 
502  if (status == CM_SUCCESS) {
503  run_state = STATE_RUNNING;
504  run_number = rn;
505 
506  send_all_periodic_events(TR_RESUME);
507 
508  if (display_period)
509  ss_printf(14, 2, "Running ");
510 
511  /* enable interrupts */
513  }
514 
515  return status;
516 }
517 
518 /*------------------------------------------------------------------*/
519 
520 INT manual_trigger(INT index, void *prpc_param[])
521 {
522  manual_trigger_event_id = CWORD(0);
523  return SUCCESS;
524 }
525 
526 /*------------------------------------------------------------------*/
527 
529 {
530  INT index, count, size, status, i, j, k, n;
531  char str[256];
532  EQUIPMENT_INFO *eq_info;
533  EQUIPMENT_STATS *eq_stats;
534  DWORD start_time, delta_time;
535  HNDLE hKey;
536  BOOL manual_trig_flag = FALSE;
537  BANK_LIST *bank_list;
538  DWORD dummy;
539 
540  /* get current ODB run state */
541  size = sizeof(run_state);
542  run_state = STATE_STOPPED;
543  db_get_value(hDB, 0, "/Runinfo/State", &run_state, &size, TID_INT, TRUE);
544  size = sizeof(run_number);
545  run_number = 1;
546  status =
547  db_get_value(hDB, 0, "/Runinfo/Run number", &run_number, &size, TID_INT, TRUE);
548  assert(status == SUCCESS);
549 
550  /* scan EQUIPMENT table from FRONTEND.C */
551  for (index = 0; equipment[index].name[0]; index++) {
552  eq_info = &equipment[index].info;
553  eq_stats = &equipment[index].stats;
554 
555  if (eq_info->event_id == 0) {
556  printf("\nEvent ID 0 for %s not allowed\n", equipment[index].name);
557  cm_disconnect_experiment();
558  ss_sleep(5000);
559  exit(0);
560  }
561 
562  /* init status */
563  equipment[index].status = FE_SUCCESS;
564 
565  /* check for event builder event */
566  if (eq_info->eq_type & EQ_EB) {
567 
568  if (frontend_index == -1) {
569  printf("\nEquipment \"%s\" has EQ_EB set, but no", equipment[index].name);
570  printf(" index specified via \"-i\" flag.\nExiting.");
571  cm_disconnect_experiment();
572  ss_sleep(5000);
573  exit(0);
574  }
575 
576  /* modify equipment name to <name>xx where xx is the frontend index*/
577  sprintf(equipment[index].name+strlen(equipment[index].name), "%02d", frontend_index);
578 
579  /* modify event buffer name to <name>xx where xx is the frontend index*/
580  sprintf(eq_info->buffer+strlen(eq_info->buffer), "%02d", frontend_index);
581  }
582 
583  sprintf(str, "/Equipment/%s/Common", equipment[index].name);
584 
585  /* get last event limit from ODB */
586  if (eq_info->eq_type != EQ_SLOW) {
587  db_find_key(hDB, 0, str, &hKey);
588  size = sizeof(double);
589  if (hKey)
590  db_get_value(hDB, hKey, "Event limit", &eq_info->event_limit, &size,
591  TID_DOUBLE, TRUE);
592  }
593 
594  /* Create common subtree */
595  status = db_check_record(hDB, 0, str, EQUIPMENT_COMMON_STR, TRUE);
596  if (status != DB_SUCCESS) {
597  printf("Cannot check equipment record, status = %d\n", status);
598  ss_sleep(3000);
599  }
600  db_find_key(hDB, 0, str, &hKey);
601 
602  if (equal_ustring(eq_info->format, "YBOS"))
603  equipment[index].format = FORMAT_YBOS;
604  else if (equal_ustring(eq_info->format, "FIXED"))
605  equipment[index].format = FORMAT_FIXED;
606  else /* default format is MIDAS */
607  equipment[index].format = FORMAT_MIDAS;
608 
609  gethostname(eq_info->frontend_host, sizeof(eq_info->frontend_host));
610  strcpy(eq_info->frontend_name, full_frontend_name);
611  strcpy(eq_info->frontend_file_name, frontend_file_name);
612 
613  /* set record from equipment[] table in frontend.c */
614  db_set_record(hDB, hKey, eq_info, sizeof(EQUIPMENT_INFO), 0);
615 
616  /* open hot link to equipment info */
617  db_open_record(hDB, hKey, eq_info, sizeof(EQUIPMENT_INFO), MODE_READ, NULL, NULL);
618 
619  /*---- Create variables record ---------------------------------*/
620  sprintf(str, "/Equipment/%s/Variables", equipment[index].name);
621  if (equipment[index].event_descrip) {
622  if (equipment[index].format == FORMAT_FIXED)
623  db_check_record(hDB, 0, str, (char *) equipment[index].event_descrip, TRUE);
624  else {
625  /* create bank descriptions */
626  bank_list = (BANK_LIST *) equipment[index].event_descrip;
627 
628  for (; bank_list->name[0]; bank_list++) {
629  /* mabye needed later...
630  if (bank_list->output_flag == 0)
631  continue;
632  */
633 
634  if (bank_list->type == TID_STRUCT) {
635  sprintf(str, "/Equipment/%s/Variables/%s", equipment[index].name,
636  bank_list->name);
637  status =
638  db_check_record(hDB, 0, str, strcomb(bank_list->init_str), TRUE);
639  if (status != DB_SUCCESS) {
640  printf("Cannot check/create record \"%s\", status = %d\n", str,
641  status);
642  ss_sleep(3000);
643  }
644  } else {
645  sprintf(str, "/Equipment/%s/Variables/%s", equipment[index].name,
646  bank_list->name);
647  dummy = 0;
648  db_set_value(hDB, 0, str, &dummy, rpc_tid_size(bank_list->type), 1,
649  bank_list->type);
650  }
651  }
652  }
653  } else
654  db_create_key(hDB, 0, str, TID_KEY);
655 
656  sprintf(str, "/Equipment/%s/Variables", equipment[index].name);
657  db_find_key(hDB, 0, str, &hKey);
658  equipment[index].hkey_variables = hKey;
659 
660  /*---- Create and initialize statistics tree -------------------*/
661 
662  sprintf(str, "/Equipment/%s/Statistics", equipment[index].name);
663 
664  status = db_check_record(hDB, 0, str, EQUIPMENT_STATISTICS_STR, TRUE);
665  if (status != DB_SUCCESS) {
666  printf("Cannot create/check statistics record, error %d\n", status);
667  ss_sleep(3000);
668  }
669 
670  status = db_find_key(hDB, 0, str, &hKey);
671  if (status != DB_SUCCESS) {
672  printf("Cannot find statistics record, error %d\n", status);
673  ss_sleep(3000);
674  }
675 
676  eq_stats->events_sent = 0;
677  eq_stats->events_per_sec = 0;
678  eq_stats->kbytes_per_sec = 0;
679 
680  /* open hot link to statistics tree */
681  status =
682  db_open_record(hDB, hKey, eq_stats, sizeof(EQUIPMENT_STATS), MODE_WRITE, NULL,
683  NULL);
684  if (status != DB_SUCCESS) {
685  cm_msg(MERROR, "register_equipment",
686  "Cannot open statistics record, error %d. Probably other FE is using it",
687  status);
688  ss_sleep(3000);
689  }
690 
691  /*---- open event buffer ---------------------------------------*/
692 
693  if (eq_info->buffer[0]) {
694  status =
695  bm_open_buffer(eq_info->buffer, EVENT_BUFFER_SIZE,
696  &equipment[index].buffer_handle);
697  if (status != BM_SUCCESS && status != BM_CREATED) {
698  cm_msg(MERROR, "register_equipment",
699  "Cannot open event buffer. Try to reduce EVENT_BUFFER_SIZE in midas.h \
700 and rebuild the system.");
701  return 0;
702  }
703 
704  /* set the default buffer cache size */
705  bm_set_cache_size(equipment[index].buffer_handle, 0, SERVER_CACHE_SIZE);
706  } else
707  equipment[index].buffer_handle = 0;
708 
709  /*---- evaluate polling count ----------------------------------*/
710  if (eq_info->eq_type & EQ_POLLED) {
711  if (display_period)
712  printf("\nCalibrating");
713 
714  count = 1;
715  do {
716  if (display_period)
717  printf(".");
718 
719  start_time = ss_millitime();
720 
721  poll_event(equipment[index].info.source, count, TRUE);
722 
723  delta_time = ss_millitime() - start_time;
724 
725  if (delta_time > 0)
726  count = (INT) ((double) count * 100 / delta_time);
727  else
728  count *= 100;
729  } while (delta_time > 120 || delta_time < 80);
730 
731  equipment[index].poll_count = (INT) ((double) eq_info->period / 100 * count);
732 
733  if (display_period)
734  printf("OK\n");
735  }
736 
737  /*---- initialize interrupt events -----------------------------*/
738  if (eq_info->eq_type & EQ_INTERRUPT) {
739  /* install interrupt for interrupt events */
740 
741  for (i = 0; equipment[i].name[0]; i++)
742  if (equipment[i].info.eq_type & EQ_POLLED) {
743  equipment[index].status = FE_ERR_DISABLED;
744  cm_msg(MINFO, "register_equipment",
745  "Interrupt readout cannot be combined with polled readout");
746  }
747 
748  if (equipment[index].status != FE_ERR_DISABLED) {
749  if (eq_info->enabled) {
750  if (interrupt_eq) {
751  equipment[index].status = FE_ERR_DISABLED;
752  cm_msg(MINFO, "register_equipment",
753  "Defined more than one equipment with interrupt readout");
754  } else {
755  interrupt_configure(CMD_INTERRUPT_ATTACH, eq_info->source,
756  (PTYPE) interrupt_routine);
757  interrupt_eq = &equipment[index];
758  interrupt_odb_buffer = malloc(MAX_EVENT_SIZE + sizeof(EVENT_HEADER));
759  }
760  } else {
761  equipment[index].status = FE_ERR_DISABLED;
762  cm_msg(MINFO, "register_equipment",
763  "Equipment %s disabled in file \"frontend.c\"",
764  equipment[index].name);
765  }
766  }
767  }
768 
769  /*---- initialize slow control equipment -----------------------*/
770  if (eq_info->eq_type & EQ_SLOW) {
771  /* resolve duplicate device names */
772  for (i = 0; equipment[index].driver[i].name[0]; i++)
773  for (j = i + 1; equipment[index].driver[j].name[0]; j++)
774  if (equal_ustring(equipment[index].driver[i].name,
775  equipment[index].driver[j].name)) {
776  strcpy(str, equipment[index].driver[i].name);
777  for (k = 0, n = 0; equipment[index].driver[k].name[0]; k++)
778  if (equal_ustring(str, equipment[index].driver[k].name))
779  sprintf(equipment[index].driver[k].name, "%s_%d", str, n++);
780 
781  break;
782  }
783 
784  /* loop over equipment list and call class driver's init method */
785  if (eq_info->enabled)
786  equipment[index].status = equipment[index].cd(CMD_INIT, &equipment[index]);
787  else {
788  equipment[index].status = FE_ERR_DISABLED;
789  cm_msg(MINFO, "register_equipment",
790  "Equipment %s disabled in file \"frontend.c\"", equipment[index].name);
791  }
792 
793  /* let user read error messages */
794  if (equipment[index].status != FE_SUCCESS)
795  ss_sleep(3000);
796  }
797 
798  /*---- register callback for manual triggered events -----------*/
799  if (eq_info->eq_type & EQ_MANUAL_TRIG) {
800  if (!manual_trig_flag)
801  cm_register_function(RPC_MANUAL_TRIG, manual_trigger);
802 
803  manual_trig_flag = TRUE;
804  }
805  }
806 
807  return SUCCESS;
808 }
809 
810 /*------------------------------------------------------------------*/
811 
812 void update_odb(EVENT_HEADER * pevent, HNDLE hKey, INT format)
813 {
814  INT size, i, ni4, tsize, status, n_data;
815  void *pdata;
816  char name[5];
817  BANK_HEADER *pbh;
818  BANK *pbk;
819  BANK32 *pbk32;
820  void *pydata;
821  DWORD odb_type;
822  DWORD *pyevt, bkname;
823  WORD bktype;
824  HNDLE hKeyRoot, hKeyl;
825  KEY key;
826 
827  /* outcommented sind db_find_key does not work in FTCP mode, SR 25.4.03
828  rpc_set_option(-1, RPC_OTRANSPORT, RPC_FTCP); */
829 
830  if (format == FORMAT_FIXED) {
831  if (db_set_record(hDB, hKey, (char *) (pevent + 1),
832  pevent->data_size, 0) != DB_SUCCESS)
833  cm_msg(MERROR, "update_odb", "event #%d size mismatch", pevent->event_id);
834  } else if (format == FORMAT_MIDAS) {
835  pbh = (BANK_HEADER *) (pevent + 1);
836  pbk = NULL;
837  pbk32 = NULL;
838  do {
839  /* scan all banks */
840  if (bk_is32(pbh)) {
841  size = bk_iterate32(pbh, &pbk32, &pdata);
842  if (pbk32 == NULL)
843  break;
844  bkname = *((DWORD *) pbk32->name);
845  bktype = (WORD) pbk32->type;
846  } else {
847  size = bk_iterate(pbh, &pbk, &pdata);
848  if (pbk == NULL)
849  break;
850  bkname = *((DWORD *) pbk->name);
851  bktype = (WORD) pbk->type;
852  }
853 
854  n_data = size;
855  if (rpc_tid_size(bktype & 0xFF))
856  n_data /= rpc_tid_size(bktype & 0xFF);
857 
858  /* get bank key */
859  *((DWORD *) name) = bkname;
860  name[4] = 0;
861 
862  if (bktype == TID_STRUCT) {
863  status = db_find_key(hDB, hKey, name, &hKeyRoot);
864  if (status != DB_SUCCESS) {
865  cm_msg(MERROR, "update_odb",
866  "please define bank %s in BANK_LIST in frontend.c", name);
867  continue;
868  }
869 
870  /* write structured bank */
871  for (i = 0;; i++) {
872  status = db_enum_key(hDB, hKeyRoot, i, &hKeyl);
873  if (status == DB_NO_MORE_SUBKEYS)
874  break;
875 
876  db_get_key(hDB, hKeyl, &key);
877 
878  /* adjust for alignment */
879  if (key.type != TID_STRING && key.type != TID_LINK)
880  pdata =
881  (void *) VALIGN(pdata, MIN(ss_get_struct_align(), key.item_size));
882 
883  status = db_set_data(hDB, hKeyl, pdata, key.item_size * key.num_values,
884  key.num_values, key.type);
885  if (status != DB_SUCCESS) {
886  cm_msg(MERROR, "update_odb", "cannot write %s to ODB", name);
887  continue;
888  }
889 
890  /* shift data pointer to next item */
891  pdata = (char *) pdata + key.item_size * key.num_values;
892  }
893  } else {
894  /* write variable length bank */
895  if (n_data > 0)
896  db_set_value(hDB, hKey, name, pdata, size, n_data, bktype & 0xFF);
897  }
898 
899  } while (1);
900  } else if (format == FORMAT_YBOS) {
901 #ifdef YBOS_SUPPORT
902  YBOS_BANK_HEADER *pybkh;
903 
904  /* skip the lrl (4 bytes per event) */
905  pyevt = (DWORD *) (pevent + 1);
906  pybkh = NULL;
907  do {
908  /* scan all banks */
909  ni4 = ybk_iterate(pyevt, &pybkh, &pydata);
910  if (pybkh == NULL || ni4 == 0)
911  break;
912 
913  /* find the corresponding odb type */
914  tsize = odb_type = 0;
915  for (i = 0; id_map[0].ybos_type > 0; i++) {
916  if (pybkh->type == id_map[i].ybos_type) {
917  odb_type = id_map[i].odb_type;
918  tsize = id_map[i].tsize;
919  break;
920  }
921  }
922 
923  /* extract bank name (key name) */
924  *((DWORD *) name) = pybkh->name;
925  name[4] = 0;
926 
927  /* reject EVID bank */
928  if (strncmp(name, "EVID", 4) == 0)
929  continue;
930 
931  /* correct YBS number of entries */
932  if (pybkh->type == D8_BKTYPE)
933  ni4 /= 2;
934  if (pybkh->type == I2_BKTYPE)
935  ni4 *= 2;
936  if (pybkh->type == I1_BKTYPE || pybkh->type == A1_BKTYPE)
937  ni4 *= 4;
938 
939  /* write bank to ODB, ni4 always in I*4 */
940  size = ni4 * tsize;
941  if ((status =
942  db_set_value(hDB, hKey, name, pydata, size, ni4,
943  odb_type & 0xFF)) != DB_SUCCESS) {
944  printf("status:%i odb_type:%li name:%s ni4:%i size:%i tsize:%i\n", status,
945  odb_type, name, ni4, size, tsize);
946  for (i = 0; i < 6; i++) {
947  float * fpydata = (float *) pydata;
948  printf("data: %f\n", *(fpydata)++);
949  }
950  }
951  } while (1);
952 #endif /* YBOS_SUPPORT */
953  }
954 
955  rpc_set_option(-1, RPC_OTRANSPORT, RPC_TCP);
956 }
957 
958 /*------------------------------------------------------------------*/
959 
960 int send_event(INT index)
961 {
962  EQUIPMENT_INFO *eq_info;
963  EVENT_HEADER *pevent, *pfragment;
964  char *pdata;
965  unsigned char *pd;
966  INT i, status;
967  DWORD sent, size;
968  static void *frag_buffer = NULL;
969 
970  eq_info = &equipment[index].info;
971 
972  /* check for fragmented event */
973  if (eq_info->eq_type & EQ_FRAGMENTED) {
974  if (frag_buffer == NULL)
975  frag_buffer = malloc(max_event_size_frag);
976 
977  if (frag_buffer == NULL) {
978  cm_msg(MERROR, "send_event",
979  "Not enough memory to allocate buffer for fragmented events");
980  return SS_NO_MEMORY;
981  }
982 
983  pevent = frag_buffer;
984  } else {
985  /* return value should be valid pointer. if NULL BIG error ==> abort */
986  pevent = dm_pointer_get();
987  if (pevent == NULL) {
988  cm_msg(MERROR, "send_event", "dm_pointer_get not returning valid pointer");
989  return SS_NO_MEMORY;
990  }
991  }
992 
993  /* compose MIDAS event header */
994  pevent->event_id = eq_info->event_id;
995  pevent->trigger_mask = eq_info->trigger_mask;
996  pevent->data_size = 0;
997  pevent->time_stamp = ss_time();
998  pevent->serial_number = equipment[index].serial_number++;
999 
1000  equipment[index].last_called = ss_millitime();
1001 
1002  /* call user readout routine */
1003  *((EQUIPMENT **) (pevent + 1)) = &equipment[index];
1004  pevent->data_size = equipment[index].readout((char *) (pevent + 1), 0);
1005 
1006  /* send event */
1007  if (pevent->data_size) {
1008  if (eq_info->eq_type & EQ_FRAGMENTED) {
1009  /* fragment event */
1010  if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size_frag) {
1011  cm_msg(MERROR, "send_event",
1012  "Event size %ld larger than maximum size %d for frag. ev.",
1013  (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1014  max_event_size_frag);
1015  return SS_NO_MEMORY;
1016  }
1017 
1018  /* compose fragments */
1019  pfragment = dm_pointer_get();
1020  if (pfragment == NULL) {
1021  cm_msg(MERROR, "send_event", "dm_pointer_get not returning valid pointer");
1022  return SS_NO_MEMORY;
1023  }
1024 
1025  /* compose MIDAS event header */
1026  memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
1027  pfragment->event_id |= EVENTID_FRAG1;
1028 
1029  /* store total event size */
1030  pd = (char *) (pfragment + 1);
1031  size = pevent->data_size;
1032  for (i = 0; i < 4; i++) {
1033  pd[i] = (unsigned char) (size & 0xFF); /* little endian, please! */
1034  size >>= 8;
1035  }
1036 
1037  pfragment->data_size = sizeof(DWORD);
1038 
1039  pdata = (char *) (pevent + 1);
1040 
1041  for (i = 0, sent = 0; sent < pevent->data_size; i++) {
1042  if (i > 0) {
1043  pfragment = dm_pointer_get();
1044 
1045  /* compose MIDAS event header */
1046  memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
1047  pfragment->event_id |= EVENTID_FRAG;
1048 
1049  /* copy portion of event */
1050  size = pevent->data_size - sent;
1051  if (size > max_event_size - sizeof(EVENT_HEADER))
1052  size = max_event_size - sizeof(EVENT_HEADER);
1053 
1054  memcpy(pfragment + 1, pdata, size);
1055  pfragment->data_size = size;
1056  sent += size;
1057  pdata += size;
1058  }
1059 
1060  /* send event to buffer */
1061  if (equipment[index].buffer_handle) {
1062 #ifdef USE_EVENT_CHANNEL
1063  dm_pointer_increment(equipment[index].buffer_handle,
1064  pfragment->data_size + sizeof(EVENT_HEADER));
1065 #else
1066  rpc_flush_event();
1067  status = bm_send_event(equipment[index].buffer_handle, pfragment,
1068  pfragment->data_size + sizeof(EVENT_HEADER), SYNC);
1069  if (status != BM_SUCCESS) {
1070  cm_msg(MERROR, "send_event", "bm_send_event(SYNC) error %d", status);
1071  return status;
1072  }
1073 #endif
1074  }
1075  }
1076 
1077  if (equipment[index].buffer_handle) {
1078 #ifndef USE_EVENT_CHANNEL
1079  status = bm_flush_cache(equipment[index].buffer_handle, SYNC);
1080  if (status != BM_SUCCESS) {
1081  cm_msg(MERROR, "send_event", "bm_flush_cache(SYNC) error %d", status);
1082  return status;
1083  }
1084 #endif
1085  }
1086  } else {
1087  /* send unfragmented event */
1088 
1089  if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
1090  cm_msg(MERROR, "send_event", "Event size %ld larger than maximum size %d",
1091  (long) (pevent->data_size + sizeof(EVENT_HEADER)), max_event_size);
1092  return SS_NO_MEMORY;
1093  }
1094 
1095  /* send event to buffer */
1096  if (equipment[index].buffer_handle) {
1097 #ifdef USE_EVENT_CHANNEL
1098  dm_pointer_increment(equipment[index].buffer_handle,
1099  pevent->data_size + sizeof(EVENT_HEADER));
1100 #else
1101  rpc_flush_event();
1102  status = bm_send_event(equipment[index].buffer_handle, pevent,
1103  pevent->data_size + sizeof(EVENT_HEADER), SYNC);
1104  if (status != BM_SUCCESS) {
1105  cm_msg(MERROR, "send_event", "bm_send_event(SYNC) error %d", status);
1106  return status;
1107  }
1108  status = bm_flush_cache(equipment[index].buffer_handle, SYNC);
1109  if (status != BM_SUCCESS) {
1110  cm_msg(MERROR, "send_event", "bm_flush_cache(SYNC) error %d", status);
1111  return status;
1112  }
1113 #endif
1114  }
1115 
1116  /* send event to ODB if RO_ODB flag is set or history is on. Do not
1117  send SLOW events since the class driver does that */
1118  if ((eq_info->read_on & RO_ODB) ||
1119  (eq_info->history > 0 && (eq_info->eq_type & ~EQ_SLOW))) {
1120  update_odb(pevent, equipment[index].hkey_variables, equipment[index].format);
1121  equipment[index].odb_out++;
1122  }
1123  }
1124 
1125  equipment[index].bytes_sent += pevent->data_size + sizeof(EVENT_HEADER);
1126  equipment[index].events_sent++;
1127 
1128  equipment[index].stats.events_sent += equipment[index].events_sent;
1129  equipment[index].events_sent = 0;
1130  } else
1131  equipment[index].serial_number--;
1132 
1133  /* emtpy event buffer */
1134 #ifdef USE_EVENT_CHANNEL
1135  if ((status = dm_area_flush()) != CM_SUCCESS)
1136  cm_msg(MERROR, "send_event", "dm_area_flush: %i", status);
1137 #endif
1138 
1139  for (i = 0; equipment[i].name[0]; i++)
1140  if (equipment[i].buffer_handle) {
1141  status = bm_flush_cache(equipment[i].buffer_handle, SYNC);
1142  if (status != BM_SUCCESS) {
1143  cm_msg(MERROR, "send_event", "bm_flush_cache(SYNC) error %d", status);
1144  return status;
1145  }
1146  }
1147 
1148  return CM_SUCCESS;
1149 }
1150 
1151 /*------------------------------------------------------------------*/
1152 
1153 void send_all_periodic_events(INT transition)
1154 {
1155  EQUIPMENT_INFO *eq_info;
1156  INT i;
1157 
1158  for (i = 0; equipment[i].name[0]; i++) {
1159  eq_info = &equipment[i].info;
1160 
1161  if (!eq_info->enabled || equipment[i].status != FE_SUCCESS)
1162  continue;
1163 
1164  if (transition == TR_START && (eq_info->read_on & RO_BOR) == 0)
1165  continue;
1166  if (transition == TR_STOP && (eq_info->read_on & RO_EOR) == 0)
1167  continue;
1168  if (transition == TR_PAUSE && (eq_info->read_on & RO_PAUSE) == 0)
1169  continue;
1170  if (transition == TR_RESUME && (eq_info->read_on & RO_RESUME) == 0)
1171  continue;
1172 
1173  send_event(i);
1174  }
1175 }
1176 
1177 /*------------------------------------------------------------------*/
1178 
1180 
1181 void interrupt_enable(BOOL flag)
1182 {
1183  interrupt_enabled = flag;
1184 
1185  if (interrupt_eq) {
1186  if (interrupt_enabled)
1187  interrupt_configure(CMD_INTERRUPT_ENABLE, 0, 0);
1188  else
1189  interrupt_configure(CMD_INTERRUPT_DISABLE, 0, 0);
1190  }
1191 }
1192 
1193 /*------------------------------------------------------------------*/
1194 
1195 void interrupt_routine(void)
1196 {
1197  EVENT_HEADER *pevent;
1198 
1199  /* get pointer for upcoming event.
1200  This is a blocking call if no space available */
1201  if ((pevent = dm_pointer_get()) == NULL)
1202  cm_msg(MERROR, "interrupt_routine", "interrupt, dm_pointer_get returned NULL");
1203 
1204  /* compose MIDAS event header */
1205  pevent->event_id = interrupt_eq->info.event_id;
1206  pevent->trigger_mask = interrupt_eq->info.trigger_mask;
1207  pevent->data_size = 0;
1208  pevent->time_stamp = actual_time;
1209  pevent->serial_number = interrupt_eq->serial_number++;
1210 
1211  /* call user readout routine */
1212  pevent->data_size = interrupt_eq->readout((char *) (pevent + 1), 0);
1213 
1214  /* send event */
1215  if (pevent->data_size) {
1216  interrupt_eq->bytes_sent += pevent->data_size + sizeof(EVENT_HEADER);
1217  interrupt_eq->events_sent++;
1218 
1219  if (interrupt_eq->buffer_handle) {
1220 #ifdef USE_EVENT_CHANNEL
1221  dm_pointer_increment(interrupt_eq->buffer_handle,
1222  pevent->data_size + sizeof(EVENT_HEADER));
1223 #else
1224  rpc_send_event(interrupt_eq->buffer_handle, pevent,
1225  pevent->data_size + sizeof(EVENT_HEADER), SYNC);
1226 #endif
1227  }
1228 
1229  /* send event to ODB */
1230  if (interrupt_eq->info.read_on & RO_ODB || interrupt_eq->info.history) {
1231  if (actual_millitime - interrupt_eq->last_called > ODB_UPDATE_TIME) {
1232  interrupt_eq->last_called = actual_millitime;
1233  memcpy(interrupt_odb_buffer, pevent,
1234  pevent->data_size + sizeof(EVENT_HEADER));
1236  interrupt_eq->odb_out++;
1237  }
1238  }
1239  } else
1240  interrupt_eq->serial_number--;
1241 
1242 }
1243 
1244 /*------------------------------------------------------------------*/
1245 
1246 int message_print(const char *msg)
1247 {
1248  char str[160];
1249 
1250  memset(str, ' ', 159);
1251  str[159] = 0;
1252 
1253  if (msg[0] == '[')
1254  msg = strchr(msg, ']') + 2;
1255 
1256  memcpy(str, msg, strlen(msg));
1257  ss_printf(0, 20, str);
1258 
1259  return 0;
1260 }
1261 
1262 /*------------------------------------------------------------------*/
1263 
1264 void display(BOOL bInit)
1265 {
1266  INT i, status;
1267  time_t full_time;
1268  char str[30];
1269 
1270  if (bInit) {
1271  ss_clear_screen();
1272 
1273  if (host_name[0])
1274  strcpy(str, host_name);
1275  else
1276  strcpy(str, "<local>");
1277 
1278  ss_printf(0, 0, "%s connected to %s. Press \"!\" to exit", full_frontend_name, str);
1279  ss_printf(0, 1,
1280  "================================================================================");
1281  ss_printf(0, 2, "Run status: %s",
1282  run_state == STATE_STOPPED ? "Stopped" : run_state ==
1283  STATE_RUNNING ? "Running" : "Paused");
1284  ss_printf(25, 2, "Run number %d ", run_number);
1285  ss_printf(0, 3,
1286  "================================================================================");
1287  ss_printf(0, 4,
1288  "Equipment Status Events Events/sec Rate[kB/s] ODB->FE FE->ODB");
1289  ss_printf(0, 5,
1290  "--------------------------------------------------------------------------------");
1291  for (i = 0; equipment[i].name[0]; i++)
1292  ss_printf(0, i + 6, "%s", equipment[i].name);
1293  }
1294 
1295  /* display time */
1296  time(&full_time);
1297  strcpy(str, ctime(&full_time) + 11);
1298  str[8] = 0;
1299  ss_printf(72, 0, "%s", str);
1300 
1301  for (i = 0; equipment[i].name[0]; i++) {
1302  status = equipment[i].status;
1303 
1304  if ((status == 0 || status == FE_SUCCESS) && equipment[i].info.enabled)
1305  ss_printf(14, i + 6, "OK ");
1306  else if (!equipment[i].info.enabled)
1307  ss_printf(14, i + 6, "Disabled ");
1308  else if (status == FE_ERR_ODB)
1309  ss_printf(14, i + 6, "ODB Error");
1310  else if (status == FE_ERR_HW)
1311  ss_printf(14, i + 6, "HW Error ");
1312  else if (status == FE_ERR_DISABLED)
1313  ss_printf(14, i + 6, "Disabled ");
1314  else
1315  ss_printf(14, i + 6, "Unknown ");
1316 
1317  if (equipment[i].stats.events_sent > 1E9)
1318  ss_printf(25, i + 6, "%1.3lfG ", equipment[i].stats.events_sent / 1E9);
1319  else if (equipment[i].stats.events_sent > 1E6)
1320  ss_printf(25, i + 6, "%1.3lfM ", equipment[i].stats.events_sent / 1E6);
1321  else
1322  ss_printf(25, i + 6, "%1.0lf ", equipment[i].stats.events_sent);
1323  ss_printf(36, i + 6, "%1.1lf ", equipment[i].stats.events_per_sec);
1324  ss_printf(47, i + 6, "%1.1lf ", equipment[i].stats.kbytes_per_sec);
1325  ss_printf(58, i + 6, "%ld ", equipment[i].odb_in);
1326  ss_printf(69, i + 6, "%ld ", equipment[i].odb_out);
1327  }
1328 
1329  /* go to next line */
1330  ss_printf(0, i + 6, "");
1331 }
1332 
1333 /*------------------------------------------------------------------*/
1334 
1336 /* check if logger uses ROOT format */
1337 {
1338  int size, i, status;
1339  char str[80];
1340  HNDLE hKeyRoot, hKey;
1341 
1342  if (db_find_key(hDB, 0, "/Logger/Channels", &hKeyRoot) == DB_SUCCESS) {
1343  for (i = 0;; i++) {
1344  status = db_enum_key(hDB, hKeyRoot, i, &hKey);
1345  if (status == DB_NO_MORE_SUBKEYS)
1346  break;
1347 
1348  strcpy(str, "MIDAS");
1349  size = sizeof(str);
1350  db_get_value(hDB, hKey, "Settings/Format", str, &size, TID_STRING, TRUE);
1351 
1352  if (equal_ustring(str, "ROOT"))
1353  return TRUE;
1354  }
1355  }
1356 
1357  return FALSE;
1358 }
1359 
1360 /*------------------------------------------------------------------*/
1361 
1362 INT scheduler(void)
1363 {
1364  EQUIPMENT_INFO *eq_info;
1365  EQUIPMENT *eq;
1366  EVENT_HEADER *pevent;
1367  DWORD last_time_network = 0, last_time_display = 0, last_time_flush = 0, readout_start;
1368  INT i, j, index, status, ch, source, size, state;
1369  char str[80];
1370  BOOL buffer_done, flag, force_update = FALSE;
1371 
1372  INT opt_max = 0, opt_index = 0, opt_tcp_size = 128, opt_cnt = 0;
1373  INT err;
1374 
1375 #ifdef OS_VXWORKS
1376  rpc_set_opt_tcp_size(1024);
1377 #ifdef PPCxxx
1378  rpc_set_opt_tcp_size(NET_TCP_SIZE);
1379 #endif
1380 #endif
1381 
1382  /*----------------- MAIN equipment loop ------------------------------*/
1383 
1384  do {
1385  actual_millitime = ss_millitime();
1386  actual_time = ss_time();
1387 
1388  /*---- loop over equipment table -------------------------------*/
1389  for (index = 0;; index++) {
1390  eq = &equipment[index];
1391  eq_info = &eq->info;
1392 
1393  /* check if end of equipment list */
1394  if (!eq->name[0])
1395  break;
1396 
1397  if (!eq_info->enabled)
1398  continue;
1399 
1400  if (eq->status != FE_SUCCESS)
1401  continue;
1402 
1403  /*---- call idle routine for slow control equipment ----*/
1404  if ((eq_info->eq_type & EQ_SLOW) && eq->status == FE_SUCCESS) {
1405  if (eq_info->event_limit > 0 && run_state == STATE_RUNNING) {
1406  if (actual_time - eq->last_idle >= (DWORD) eq_info->event_limit) {
1407  eq->cd(CMD_IDLE, eq);
1408  eq->last_idle = actual_time;
1409  }
1410  } else
1411  eq->cd(CMD_IDLE, eq);
1412  }
1413 
1414  if (run_state == STATE_STOPPED && (eq_info->read_on & RO_STOPPED) == 0)
1415  continue;
1416  if (run_state == STATE_PAUSED && (eq_info->read_on & RO_PAUSED) == 0)
1417  continue;
1418  if (run_state == STATE_RUNNING && (eq_info->read_on & RO_RUNNING) == 0)
1419  continue;
1420 
1421  /*---- check periodic events ----*/
1422  if ((eq_info->eq_type & EQ_PERIODIC) || (eq_info->eq_type & EQ_SLOW)) {
1423  if (eq_info->period == 0)
1424  continue;
1425 
1426  /* check if period over */
1427  if (actual_millitime - eq->last_called >= (DWORD) eq_info->period) {
1428  /* disable interrupts during readout */
1430 
1431  /* readout and send event */
1432  status = send_event(index);
1433 
1434  if (status != CM_SUCCESS) {
1435  cm_msg(MERROR, "scheduler", "send_event error %d", status);
1436  goto net_error;
1437  }
1438 
1439  /* re-enable the interrupt after periodic */
1441  }
1442  }
1443 
1444  /* end of periodic equipments */
1445  /*---- check polled events ----*/
1446  if (eq_info->eq_type & EQ_POLLED) {
1447  readout_start = actual_millitime;
1448  pevent = NULL;
1449 
1450  while ((source = poll_event(eq_info->source, eq->poll_count, FALSE)) > 0) {
1451  pevent = dm_pointer_get();
1452  if (pevent == NULL) {
1453  cm_msg(MERROR, "scheduler",
1454  "polled, dm_pointer_get not returning valid pointer");
1455  status = SS_NO_MEMORY;
1456  goto net_error;
1457  }
1458 
1459  /* compose MIDAS event header */
1460  pevent->event_id = eq_info->event_id;
1461  pevent->trigger_mask = eq_info->trigger_mask;
1462  pevent->data_size = 0;
1463  pevent->time_stamp = actual_time;
1464  pevent->serial_number = eq->serial_number;
1465 
1466  /* put source at beginning of event, will be overwritten by
1467  user readout code, just a special feature used by some
1468  multi-source applications */
1469  *(INT *) (pevent + 1) = source;
1470 
1471  if (eq->info.num_subevents) {
1472  eq->subevent_number = 0;
1473  do {
1474  *(INT *) ((char *) (pevent + 1) + pevent->data_size) = source;
1475 
1476  /* call user readout routine for subevent indicating offset */
1477  size = eq->readout((char *) (pevent + 1), pevent->data_size);
1478  pevent->data_size += size;
1479  if (size > 0) {
1480  if (pevent->data_size + sizeof(EVENT_HEADER) >
1481  (DWORD) max_event_size) {
1482  cm_msg(MERROR, "scheduler",
1483  "Event size %ld larger than maximum size %d",
1484  (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1485  max_event_size);
1486  }
1487 
1488  eq->subevent_number++;
1489  eq->serial_number++;
1490  }
1491 
1492  /* wait for next event */
1493  do {
1494  source = poll_event(eq_info->source, eq->poll_count, FALSE);
1495 
1496  if (source == FALSE) {
1497  actual_millitime = ss_millitime();
1498 
1499  /* repeat no more than period */
1500  if (actual_millitime - readout_start > (DWORD) eq_info->period)
1501  break;
1502  }
1503  } while (source == FALSE);
1504 
1505  } while (eq->subevent_number < eq->info.num_subevents && source);
1506 
1507  /* notify readout routine about end of super-event */
1508  pevent->data_size = eq->readout((char *) (pevent + 1), -1);
1509  } else {
1510  /* call user readout routine indicating event source */
1511  pevent->data_size = eq->readout((char *) (pevent + 1), 0);
1512 
1513  /* check event size */
1514  if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
1515  cm_msg(MERROR, "scheduler",
1516  "Event size %ld larger than maximum size %d",
1517  (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1518  max_event_size);
1519  }
1520 
1521  /* increment serial number if event read out sucessfully */
1522  if (pevent->data_size)
1523  eq->serial_number++;
1524  }
1525 
1526  /* send event */
1527  if (pevent->data_size) {
1528  if (eq->buffer_handle) {
1529  /* send first event to ODB if logger writes in root format */
1530  if (pevent->serial_number == 1)
1531  if (logger_root())
1532  update_odb(pevent, eq->hkey_variables, eq->format);
1533 
1534 #ifdef USE_EVENT_CHANNEL
1535  dm_pointer_increment(eq->buffer_handle,
1536  pevent->data_size + sizeof(EVENT_HEADER));
1537 #else
1538  status = rpc_send_event(eq->buffer_handle, pevent,
1539  pevent->data_size + sizeof(EVENT_HEADER),
1540  SYNC);
1541 
1542  if (status != SUCCESS) {
1543  cm_msg(MERROR, "scheduler", "rpc_send_event error %d", status);
1544  goto net_error;
1545  }
1546 #endif
1547 
1548  eq->bytes_sent += pevent->data_size + sizeof(EVENT_HEADER);
1549 
1550  if (eq->info.num_subevents)
1551  eq->events_sent += eq->subevent_number;
1552  else
1553  eq->events_sent++;
1554  }
1555  }
1556 
1557  actual_millitime = ss_millitime();
1558 
1559  /* repeat no more than period */
1560  if (actual_millitime - readout_start > (DWORD) eq_info->period)
1561  break;
1562 
1563  /* quit if event limit is reached */
1564  if (eq_info->event_limit > 0 &&
1565  eq->stats.events_sent + eq->events_sent >= eq_info->event_limit)
1566  break;
1567  }
1568 
1569  /* send event to ODB */
1570  if (pevent && (eq_info->read_on & RO_ODB || eq_info->history)) {
1571  if (actual_millitime - eq->last_called > ODB_UPDATE_TIME && pevent != NULL) {
1572  eq->last_called = actual_millitime;
1573  update_odb(pevent, eq->hkey_variables, eq->format);
1574  eq->odb_out++;
1575  }
1576  }
1577  }
1578 
1579  /*---- send interrupt events ----*/
1580  if (eq_info->eq_type & EQ_INTERRUPT) {
1581  /* not much to do as work being done independently in interrupt_routine() */
1582 
1583  /* update ODB */
1585  update_odb(interrupt_odb_buffer, interrupt_eq->hkey_variables,
1586  interrupt_eq->format);
1588  }
1589 
1590  }
1591 
1592  /*---- check if event limit is reached ----*/
1593  if (eq_info->eq_type != EQ_SLOW &&
1594  eq_info->event_limit > 0 &&
1595  eq->stats.events_sent + eq->events_sent >= eq_info->event_limit &&
1596  run_state == STATE_RUNNING) {
1597  /* stop run */
1598  if (cm_transition(TR_STOP, 0, str, sizeof(str), SYNC, FALSE) != CM_SUCCESS)
1599  cm_msg(MERROR, "scheduler", "cannot stop run: %s", str);
1600 
1601  /* check if autorestart, main loop will take care of it */
1602  size = sizeof(BOOL);
1603  flag = FALSE;
1604  db_get_value(hDB, 0, "/Logger/Auto restart", &flag, &size, TID_BOOL, TRUE);
1605 
1606  if (flag)
1607  auto_restart = ss_time() + 20; /* restart in 20 sec. */
1608 
1609  /* update event display correctly */
1610  force_update = TRUE;
1611  }
1612  }
1613 
1614  /*---- call frontend_loop periodically -------------------------*/
1615  if (frontend_call_loop) {
1616  status = frontend_loop();
1617  if (status != CM_SUCCESS)
1618  status = RPC_SHUTDOWN;
1619  }
1620 
1621  /*---- check for deferred transitions --------------------------*/
1622  cm_check_deferred_transition();
1623 
1624  /*---- check for manual triggered events -----------------------*/
1627 
1628  /* readout and send event */
1629  status = BM_INVALID_PARAM;
1630  for (i = 0; equipment[i].name[0]; i++)
1631  if (equipment[i].info.event_id == manual_trigger_event_id) {
1632  status = send_event(i);
1633  break;
1634  }
1635 
1637 
1638  if (status != CM_SUCCESS) {
1639  cm_msg(MERROR, "scheduler", "send_event error %d", status);
1640  goto net_error;
1641  }
1642 
1643  /* re-enable the interrupt after periodic */
1645  }
1646 
1647  /*---- calculate rates and update status page periodically -----*/
1648  if (force_update ||
1650  && actual_millitime - last_time_display > (DWORD) display_period)
1651  || (!display_period && actual_millitime - last_time_display > 3000)) {
1652  force_update = FALSE;
1653 
1654  /* calculate rates */
1655  if (actual_millitime != last_time_display) {
1656  max_bytes_per_sec = 0;
1657  for (i = 0; equipment[i].name[0]; i++) {
1658  eq = &equipment[i];
1659  eq->stats.events_sent += eq->events_sent;
1660  eq->stats.events_per_sec =
1661  eq->events_sent / ((actual_millitime - last_time_display) / 1000.0);
1662  eq->stats.kbytes_per_sec =
1663  eq->bytes_sent / 1024.0 / ((actual_millitime - last_time_display) /
1664  1000.0);
1665 
1666  if ((INT) eq->bytes_sent > max_bytes_per_sec)
1667  max_bytes_per_sec = eq->bytes_sent;
1668 
1669  eq->bytes_sent = 0;
1670  eq->events_sent = 0;
1671  }
1672 
1674  ((double) max_bytes_per_sec /
1675  ((actual_millitime - last_time_display) / 1000.0));
1676 
1677  /* tcp buffer size evaluation */
1678  if (optimize) {
1679  opt_max = MAX(opt_max, (INT) max_bytes_per_sec);
1680  ss_printf(0, opt_index, "%6d : %5.1lf %5.1lf", opt_tcp_size,
1681  opt_max / 1024.0, max_bytes_per_sec / 1024.0);
1682  if (++opt_cnt == 10) {
1683  opt_cnt = 0;
1684  opt_max = 0;
1685  opt_index++;
1686  opt_tcp_size = 1 << (opt_index + 7);
1687  rpc_set_opt_tcp_size(opt_tcp_size);
1688  if (1 << (opt_index + 7) > 0x8000) {
1689  opt_index = 0;
1690  opt_tcp_size = 1 << 7;
1691  rpc_set_opt_tcp_size(opt_tcp_size);
1692  }
1693  }
1694  }
1695 
1696  }
1697 
1698  /* propagate changes in equipment to ODB */
1699  rpc_set_option(-1, RPC_OTRANSPORT, RPC_FTCP);
1700  db_send_changed_records();
1701  rpc_set_option(-1, RPC_OTRANSPORT, RPC_TCP);
1702 
1703  if (display_period) {
1704  display(FALSE);
1705 
1706  /* check keyboard */
1707  ch = 0;
1708  status = 0;
1709  while (ss_kbhit()) {
1710  ch = ss_getchar(0);
1711  if (ch == -1)
1712  ch = getchar();
1713 
1714  if (ch == '!')
1715  status = RPC_SHUTDOWN;
1716  }
1717 
1718  if (ch > 0)
1719  display(TRUE);
1720  if (status == RPC_SHUTDOWN)
1721  break;
1722  }
1723 
1724  last_time_display = actual_millitime;
1725  }
1726 
1727  /*---- check to flush cache ------------------------------------*/
1728  if (actual_millitime - last_time_flush > 1000) {
1729  last_time_flush = actual_millitime;
1730 
1731  /* if cache on server is not filled in one second at current
1732  data rate, flush it now to make events available to consumers */
1733 
1736 
1737 #ifdef USE_EVENT_CHANNEL
1738  if ((status = dm_area_flush()) != CM_SUCCESS)
1739  cm_msg(MERROR, "scheduler", "dm_area_flush: %i", status);
1740 #endif
1741 
1742  for (i = 0; equipment[i].name[0]; i++) {
1743  if (equipment[i].buffer_handle) {
1744  /* check if buffer already flushed */
1745  buffer_done = FALSE;
1746  for (j = 0; j < i; j++)
1747  if (equipment[i].buffer_handle == equipment[j].buffer_handle) {
1748  buffer_done = TRUE;
1749  break;
1750  }
1751 
1752  if (!buffer_done) {
1753  rpc_set_option(-1, RPC_OTRANSPORT, RPC_FTCP);
1754  rpc_flush_event();
1755  err = bm_flush_cache(equipment[i].buffer_handle, ASYNC);
1756  if (err != BM_SUCCESS) {
1757  cm_msg(MERROR, "scheduler", "bm_flush_cache(ASYNC) error %d",
1758  err);
1759  return err;
1760  }
1761  rpc_set_option(-1, RPC_OTRANSPORT, RPC_TCP);
1762  }
1763  }
1764  }
1766  }
1767  }
1768 
1769  /*---- check for auto restart --------------------------------*/
1770  if (auto_restart > 0 && ss_time() > auto_restart) {
1771  /* check if really stopped */
1772  size = sizeof(state);
1773  status = db_get_value(hDB, 0, "Runinfo/State", &state, &size, TID_INT, TRUE);
1774  if (status != DB_SUCCESS)
1775  cm_msg(MERROR, "scheduler", "cannot get Runinfo/State in database");
1776 
1777  if (state == STATE_STOPPED) {
1778  auto_restart = 0;
1779  size = sizeof(run_number);
1780  status =
1781  db_get_value(hDB, 0, "/Runinfo/Run number", &run_number, &size, TID_INT,
1782  TRUE);
1783  assert(status == SUCCESS);
1784 
1785  if (run_number <= 0) {
1786  cm_msg(MERROR, "main", "aborting on attempt to use invalid run number %d",
1787  run_number);
1788  abort();
1789  }
1790 
1791  cm_msg(MTALK, "main", "starting new run");
1792  status = cm_transition(TR_START, run_number + 1, NULL, 0, SYNC, FALSE);
1793  if (status != CM_SUCCESS)
1794  cm_msg(MERROR, "main", "cannot restart run");
1795  }
1796  }
1797 
1798  /*---- check network messages ----------------------------------*/
1799  if (run_state == STATE_RUNNING && interrupt_eq == NULL) {
1800  /* only call yield once every 100ms when running */
1801  if (actual_millitime - last_time_network > 100) {
1802  status = cm_yield(0);
1803  last_time_network = actual_millitime;
1804  } else
1805  status = RPC_SUCCESS;
1806  } else
1807  /* when run is stopped or interrupts used,
1808  call yield with 100ms timeout */
1809  status = cm_yield(100);
1810 
1811  /* exit for VxWorks */
1812  if (fe_stop)
1813  status = RPC_SHUTDOWN;
1814 
1815  } while (status != RPC_SHUTDOWN && status != SS_ABORT);
1816 
1817  net_error:
1818 
1819  return status;
1820 }
1821 
1822 /*------------------------------------------------------------------*/
1823 
1824 #ifdef HAVE_CAMAC
1825 
1826 INT cnaf_callback(INT index, void *prpc_param[])
1827 {
1828  DWORD cmd, b, c, n, a, f, *pdword, *size, *x, *q, dtemp;
1829  WORD *pword, *pdata, temp;
1830  INT i, count;
1831 
1832  /* Decode parameters */
1833  cmd = CDWORD(0);
1834  b = CDWORD(1);
1835  c = CDWORD(2);
1836  n = CDWORD(3);
1837  a = CDWORD(4);
1838  f = CDWORD(5);
1839  pdword = CPDWORD(6);
1840  pword = CPWORD(6);
1841  pdata = CPWORD(6);
1842  size = CPDWORD(7);
1843  x = CPDWORD(8);
1844  q = CPDWORD(9);
1845 
1846  /* determine repeat count */
1847  if (index == RPC_CNAF16)
1848  count = *size / sizeof(WORD); /* 16 bit */
1849  else
1850  count = *size / sizeof(DWORD); /* 24 bit */
1851 
1852  switch (cmd) {
1853  /*---- special commands ----*/
1854 
1855  case CNAF_INHIBIT_SET:
1856  cam_inhibit_set(c);
1857  break;
1858  case CNAF_INHIBIT_CLEAR:
1859  cam_inhibit_clear(c);
1860  break;
1861  case CNAF_CRATE_CLEAR:
1862  cam_crate_clear(c);
1863  break;
1864  case CNAF_CRATE_ZINIT:
1865  cam_crate_zinit(c);
1866  break;
1867 
1868  case CNAF_TEST:
1869  break;
1870 
1871  case CNAF:
1872  if (index == RPC_CNAF16) {
1873  for (i = 0; i < count; i++)
1874  if (f < 16)
1875  cam16i_q(c, n, a, f, pword++, (int *) x, (int *) q);
1876  else if (f < 24)
1877  cam16o_q(c, n, a, f, pword[i], (int *) x, (int *) q);
1878  else
1879  cam16i_q(c, n, a, f, &temp, (int *) x, (int *) q);
1880  } else {
1881  for (i = 0; i < count; i++)
1882  if (f < 16)
1883  cam24i_q(c, n, a, f, pdword++, (int *) x, (int *) q);
1884  else if (f < 24)
1885  cam24o_q(c, n, a, f, pdword[i], (int *) x, (int *) q);
1886  else
1887  cam24i_q(c, n, a, f, &dtemp, (int *) x, (int *) q);
1888  }
1889 
1890  break;
1891 
1892  case CNAF_nQ:
1893  if (index == RPC_CNAF16) {
1894  if (f < 16)
1895  cam16i_rq(c, n, a, f, (WORD **) & pdword, count);
1896  } else {
1897  if (f < 16)
1898  cam24i_rq(c, n, a, f, &pdword, count);
1899  }
1900 
1901  /* return reduced return size */
1902  *size = (int) pdword - (int) pdata;
1903  break;
1904 
1905  default:
1906  printf("cnaf: Unknown command 0x%X\n", (unsigned int) cmd);
1907  }
1908 
1909  if (debug) {
1910  if (index == RPC_CNAF16)
1911  printf("cmd=%d r=%d c=%d n=%d a=%d f=%d d=%X x=%d q=%d\n",
1912  (int) cmd, (int) count, (int) c, (int) n, (int) a, (int) f,
1913  (int) pword[0], (int) *x, (int) *q);
1914  else if (index == RPC_CNAF24)
1915  printf("cmd=%d r=%d c=%d n=%d a=%d f=%d d=%X x=%d q=%d\n",
1916  (int) cmd, (int) count, (int) c, (int) n, (int) a, (int) f,
1917  (int) pdword[0], (int) *x, (int) *q);
1918  }
1919 
1920  return RPC_SUCCESS;
1921 }
1922 
1923 #endif /* HAVE_CAMAC */
1924 
1925 
1926 /*------------------------------------------------------------------*/
1927 
1929 {
1930  return frontend_index;
1931 }
1932 
1933 /*------------------------------------------------------------------*/
1934 
1935 #ifdef OS_VXWORKS
1936 int mfe(char *ahost_name, char *aexp_name, BOOL adebug)
1937 #else
1938 int main(int argc, char *argv[])
1939 #endif
1940 {
1941  INT status, i, dm_size;
1942  INT daemon;
1943 
1944  host_name[0] = 0;
1945  exp_name[0] = 0;
1946  debug = FALSE;
1947  daemon = 0;
1948 
1949  setbuf(stdout, 0);
1950  setbuf(stderr, 0);
1951 
1952 #ifdef SIGPIPE
1953  signal(SIGPIPE, SIG_IGN);
1954 #endif
1955 
1956 #ifdef OS_VXWORKS
1957  if (ahost_name)
1958  strcpy(host_name, ahost_name);
1959  if (aexp_name)
1960  strcpy(exp_name, aexp_name);
1961  debug = adebug;
1962 #else
1963 
1964  /* get default from environment */
1966 
1967  /* parse command line parameters */
1968  for (i = 1; i < argc; i++) {
1969  if (argv[i][0] == '-' && argv[i][1] == 'd')
1970  debug = TRUE;
1971  else if (argv[i][0] == '-' && argv[i][1] == 'D')
1972  daemon = 1;
1973  else if (argv[i][0] == '-' && argv[i][1] == 'O')
1974  daemon = 2;
1975  else if (argv[i][0] == '-') {
1976  if (i + 1 >= argc || argv[i + 1][0] == '-')
1977  goto usage;
1978  if (argv[i][1] == 'e')
1979  strcpy(exp_name, argv[++i]);
1980  else if (argv[i][1] == 'h')
1981  strcpy(host_name, argv[++i]);
1982  else if (argv[i][1] == 'i')
1983  frontend_index = atoi(argv[++i]);
1984  else {
1985  usage:
1986  printf("usage: frontend [-h Hostname] [-e Experiment] [-d] [-D] [-O] [-i n]\n");
1987  printf(" [-d] Used to debug the frontend\n");
1988  printf(" [-D] Become a daemon\n");
1989  printf(" [-O] Become a daemon but keep stdout\n");
1990  printf(" [-i n] Set frontend index (used for event building)\n");
1991  return 0;
1992  }
1993  }
1994  }
1995 #endif
1996 
1997 #ifdef PART_OF_MUCAP
1999 #endif
2000 
2001  /* check event and buffer sizes */
2002  if (event_buffer_size < 2 * max_event_size) {
2003  printf("event_buffer_size too small for max. event size\n");
2004  ss_sleep(5000);
2005  return 1;
2006  }
2007 
2008  if (max_event_size > MAX_EVENT_SIZE) {
2009  printf("Requested max_event_size (%d) exceeds max. system event size (%d)",
2010  max_event_size, MAX_EVENT_SIZE);
2011  ss_sleep(5000);
2012  return 1;
2013  }
2014 
2015  dm_size = event_buffer_size;
2016 
2017 #ifdef OS_VXWORKS
2018  /* override dm_size in case of VxWorks
2019  take remaining free memory and use 20% of it for dm_ */
2020  dm_size = 2 * 10 * (max_event_size + sizeof(EVENT_HEADER) + sizeof(INT));
2021  if (dm_size > memFindMax()) {
2022  cm_msg(MERROR, "mainFE", "Not enough mem space for event size");
2023  return 0;
2024  }
2025  /* takes overall 20% of the available memory resource for dm_() */
2026  dm_size = 0.2 * memFindMax();
2027 
2028  /* there are two buffers */
2029  dm_size /= 2;
2030 #endif
2031 
2032  /* reduce memory size for MS-DOS */
2033 #ifdef OS_MSDOS
2034  if (dm_size > 0x4000)
2035  dm_size = 0x4000; /* 16k */
2036 #endif
2037 
2038  /* add frontend index to frontend name if present */
2040  if (frontend_index >= 0)
2042 
2043  /* inform user of settings */
2044  printf("Frontend name : %s\n", full_frontend_name);
2045  printf("Event buffer size : %d\n", event_buffer_size);
2046  printf("Buffer allocation : 2 x %d\n", dm_size);
2047  printf("System max event size : %d\n", MAX_EVENT_SIZE);
2048  printf("User max event size : %d\n", max_event_size);
2049  if (max_event_size_frag > 0)
2050  printf("User max frag. size : %d\n", max_event_size_frag);
2051  printf("# of events per buffer : %d\n\n", dm_size / max_event_size);
2052 
2053  if (daemon) {
2054  printf("\nBecoming a daemon...\n");
2055  ss_daemon_init(daemon == 2);
2056  }
2057 
2058  /* now connect to server */
2059  if (display_period) {
2060  if (host_name[0])
2061  printf("Connect to experiment %s on host %s...", exp_name, host_name);
2062  else
2063  printf("Connect to experiment %s...", exp_name);
2064  }
2065 
2066  status = cm_connect_experiment1(host_name, exp_name, full_frontend_name,
2067  NULL, DEFAULT_ODB_SIZE, DEFAULT_FE_TIMEOUT);
2068  if (status != CM_SUCCESS) {
2069  /* let user read message before window might close */
2070  ss_sleep(5000);
2071  return 1;
2072  }
2073 
2074  if (display_period)
2075  printf("OK\n");
2076 
2077  /* book buffer space */
2078  status = dm_buffer_create(dm_size, max_event_size);
2079  if (status != CM_SUCCESS) {
2080  printf("dm_buffer_create: Not enough memory or event too big\n");
2081  return 1;
2082  }
2083 
2084  /* remomve any dead frontend */
2085  cm_cleanup(full_frontend_name, FALSE);
2086 
2087  /* shutdown previous frontend */
2088  status = cm_shutdown(full_frontend_name, FALSE);
2089  if (status == CM_SUCCESS && display_period) {
2090  printf("Previous frontend stopped\n");
2091 
2092  /* let user read message */
2093  ss_sleep(3000);
2094  }
2095 
2096  /* register transition callbacks */
2097  if (cm_register_transition(TR_START, tr_prestart, 400+crate_number) != CM_SUCCESS ||
2098  cm_register_transition(TR_START, tr_start, 500+crate_number) != CM_SUCCESS ||
2099  cm_register_transition(TR_STOP, tr_stop, 500+crate_number) != CM_SUCCESS ||
2100  cm_register_transition(TR_PAUSE, tr_pause, 500+crate_number) != CM_SUCCESS ||
2101  cm_register_transition(TR_RESUME, tr_resume, 500+crate_number) != CM_SUCCESS) {
2102  printf("Failed to start local RPC server");
2103  cm_disconnect_experiment();
2104  dm_buffer_release();
2105 
2106  /* let user read message before window might close */
2107  ss_sleep(5000);
2108  return 1;
2109  }
2110 #ifdef HAVE_CAMAC
2111 
2112  /* register CNAF callback */
2113  cm_register_function(RPC_CNAF16, cnaf_callback);
2114  cm_register_function(RPC_CNAF24, cnaf_callback);
2115 
2116 #endif
2117 
2118  cm_get_experiment_database(&hDB, &status);
2119 
2120  /* set time from server */
2121 #ifdef OS_VXWORKS
2122  cm_synchronize(NULL);
2123 #endif
2124 
2125  /* turn off watchdog if in debug mode */
2126  if (debug)
2127  cm_set_watchdog_params(TRUE, 0);
2128 
2129  /* increase RPC timeout to 2min for logger with exabyte or blocked disk */
2130  rpc_set_option(-1, RPC_OTIMEOUT, 120000);
2131 
2132  /* set own message print function */
2133  if (display_period)
2134  cm_set_msg_print(MT_ALL, MT_ALL, message_print);
2135 
2136  /* call user init function */
2137  if (display_period)
2138  printf("Init hardware...");
2139  if (frontend_init() != SUCCESS) {
2140  if (display_period)
2141  printf("\n");
2142  cm_disconnect_experiment();
2143  dm_buffer_release();
2144 
2145  /* let user read message before window might close */
2146  ss_sleep(5000);
2147  return 1;
2148  }
2149 
2150  /* reqister equipment in ODB */
2151  if (register_equipment() != SUCCESS) {
2152  if (display_period)
2153  printf("\n");
2154  cm_disconnect_experiment();
2155  dm_buffer_release();
2156 
2157  /* let user read message before window might close */
2158  ss_sleep(5000);
2159  return 1;
2160  }
2161 
2162  if (display_period)
2163  printf("OK\n");
2164 
2165  /* initialize screen display */
2166  if (display_period) {
2167  ss_sleep(1000);
2168  display(TRUE);
2169  }
2170 
2171  /* switch on interrupts if running */
2172  if (interrupt_eq && run_state == STATE_RUNNING)
2174 
2175  /* initialize ss_getchar */
2176  ss_getchar(0);
2177 
2178  /* call main scheduler loop */
2179  status = scheduler();
2180 
2181  /* reset terminal */
2182  ss_getchar(TRUE);
2183 
2184  /* switch off interrupts */
2185  if (interrupt_eq) {
2186  interrupt_configure(CMD_INTERRUPT_DISABLE, 0, 0);
2187  interrupt_configure(CMD_INTERRUPT_DETACH, 0, 0);
2189  free(interrupt_odb_buffer);
2190  }
2191 
2192  /* detach interrupts */
2193  if (interrupt_eq != NULL)
2194  interrupt_configure(CMD_INTERRUPT_DETACH, interrupt_eq->info.source, 0);
2195 
2196  /* call user exit function */
2197  frontend_exit();
2198 
2199  /* close slow control drivers */
2200  for (i = 0; equipment[i].name[0]; i++)
2201  if ((equipment[i].info.eq_type & EQ_SLOW) && equipment[i].status == FE_SUCCESS)
2202  equipment[i].cd(CMD_EXIT, &equipment[i]);
2203 
2204  /* close network connection to server */
2205  cm_disconnect_experiment();
2206 
2207  if (display_period) {
2208  if (status == RPC_SHUTDOWN) {
2209  ss_clear_screen();
2210  ss_printf(0, 0, "Frontend shut down.");
2211  ss_printf(0, 1, "");
2212  }
2213  }
2214 
2215  if (status != RPC_SHUTDOWN)
2216  printf("Network connection aborted.\n");
2217 
2218  dm_buffer_release();
2219 
2220  return 0;
2221 }