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