mfe.c

Go to the documentation of this file.
00001 /********************************************************************\
00002 
00003   Name:         mfe.c
00004   Created by:   Stefan Ritt
00005 
00006   Contents:     The system part of the MIDAS frontend. Has to be
00007                 linked with user code to form a complete frontend
00008 
00009   $Log: mfe.c,v $
00010   Revision 1.61  2003/11/24 08:22:46  midas
00011   Changed timeouts from INT to DWORD, added ignore_timeout to cm_cleanup, adde '-f' flag to ODBEdit 'cleanup'
00012 
00013   Revision 1.60  2003/11/20 11:29:44  midas
00014   Implemented db_check_record and use it in most places instead of db_create_record
00015 
00016   Revision 1.59  2003/11/01 00:48:14  olchansk
00017   abort if cannot read /runinfo/run number
00018   abort if run number resets to zero
00019 
00020   Revision 1.58  2003/10/29 15:33:48  midas
00021   Properly display message about stopped previous frontend
00022 
00023   Revision 1.57  2003/09/30 19:47:57  midas
00024   Removed tabs
00025 
00026   Revision 1.56  2003/09/30 18:30:07  midas
00027   Put CNAF functionality under #ifdef HAVE_CAMAC
00028 
00029   Revision 1.55  2003/05/09 07:40:04  midas
00030   Added extra parameter to cm_get_environment
00031 
00032   Revision 1.54  2003/05/07 10:57:10  midas
00033   Removed tabs
00034 
00035   Revision 1.53  2003/04/25 10:41:42  midas
00036   Removed FTCP mode in update_odb()
00037 
00038   Revision 1.52  2003/04/25 07:45:03  midas
00039   Write first event to ODB only if logger uses ROOT format
00040 
00041   Revision 1.51  2003/04/14 12:40:23  midas
00042   Create ODB entries for structured banks derived from BANK_LIST in frontend.c
00043 
00044   Revision 1.50  2003/04/14 05:12:54  pierre
00045   fix send_event for handle=0
00046 
00047   Revision 1.49  2003/04/01 19:22:44  pierre
00048   fix update_odb for hKeyl copy
00049 
00050   Revision 1.48  2003/03/31 08:27:34  midas
00051   Fixed alignment bug for strings
00052 
00053   Revision 1.47  2003/03/28 09:13:05  midas
00054   Added warning for uncreated structured banks
00055 
00056   Revision 1.46  2003/03/28 08:55:11  midas
00057   Added code for structured banks
00058 
00059   Revision 1.45  2002/10/15 18:44:23  olchansk
00060   fix printf() and cm_msg() format mismatches
00061 
00062   Revision 1.44  2002/10/15 18:15:25  olchansk
00063   disable dtsout, stderr buffering,
00064   catch-ignore SIGPIPE
00065 
00066   Revision 1.43  2002/10/15 18:13:59  olchansk
00067   always recreate the statistics record.
00068 
00069   Revision 1.42  2002/10/15 18:09:59  olchansk
00070   catch bm_xxx() errors and bail out from schedule(). This fixes infinite looping after rpc timeouts.
00071 
00072   Revision 1.41  2002/09/13 07:32:47  midas
00073   Added client name to cm_cleanup()
00074 
00075   Revision 1.40  2002/06/03 06:07:15  midas
00076   Added extra parameter to ss_daemon_init to keep stdout
00077 
00078   Revision 1.39  2002/05/15 23:43:56  midas
00079   Added event fragmentation
00080 
00081   Revision 1.38  2002/05/10 01:41:19  midas
00082   Added optional debug output to cm_transition
00083 
00084   Revision 1.37  2002/05/08 19:54:40  midas
00085   Added extra parameter to function db_get_value()
00086 
00087   Revision 1.36  2001/11/21 08:37:32  midas
00088   Took out db_delete_key for statistics again (not needed)
00089 
00090   Revision 1.35  2001/11/20 19:22:07  pierre
00091   - Add rpc_flush_event in case no periodic eqp
00092   - Force rpc_flush_event for low trigger rate
00093   - Patch /Statistics in case it exists but size=0
00094 
00095   Revision 1.34  2001/06/27 12:34:49  midas
00096   Added -D flag to become a daemon
00097 
00098   Revision 1.33  2001/04/06 04:13:40  midas
00099   Put cm_cleanup() in init code
00100 
00101   Revision 1.32  2001/01/29 09:50:53  midas
00102   Changed send_event() parameter from event_id to equipment index
00103 
00104   Revision 1.31  2000/11/14 08:30:03  midas
00105   SLOW events are not any more sent to the ODB when the history is on
00106 
00107   Revision 1.30  2000/11/06 10:10:23  midas
00108   Flush events for set-ups with only non-periodic events
00109 
00110   Revision 1.29  2000/10/23 14:19:06  midas
00111   Added idle period for slow control equipment
00112 
00113   Revision 1.28  2000/09/28 13:16:02  midas
00114   Fixed bug that MANUAL_TRIG only events are not read out during transitions
00115 
00116   Revision 1.27  2000/09/28 13:02:03  midas
00117   Added manual triggered events
00118 
00119   Revision 1.26  2000/08/21 11:01:11  midas
00120   Changed comments
00121 
00122   Revision 1.25  2000/08/21 10:44:58  midas
00123   Removed reconnect functionality, it's better to restart the frontend via
00124   /programs/frontend/auto restart.
00125 
00126   Revision 1.24  2000/08/21 10:36:41  midas
00127   Reworked event and event buffer sizes:
00128   - Both max_event_size and event_buffer_size must be defined in user code
00129   - While max_event_size is used for frontend buffers, MAX_EVENT_SIZE is the
00130     system limit which must be larger than max_event_size
00131   - Event size returned from user readout routine is now checked against event
00132     size limits
00133   - Buffer settings are now always displayed, not only under VxWorks
00134 
00135   Revision 1.23  2000/08/09 12:02:43  midas
00136   Evaluate return status in tr_xxx functions properly
00137 
00138   Revision 1.22  2000/08/09 11:37:56  midas
00139   Rearranged serial number increments
00140 
00141   Revision 1.21  2000/07/11 16:43:40  pierre
00142   - Fix serial number for POLL super event.
00143 
00144   Revision 1.20  2000/04/03 12:27:43  midas
00145   Changed auto restart to 20 seconds in main loop
00146 
00147   Revision 1.19  2000/03/22 14:42:48  midas
00148   Fixed bug with invalid pointer
00149 
00150   Revision 1.18  2000/03/17 13:00:05  midas
00151   Frontends use default timeout fo 60 sec.
00152 
00153   Revision 1.17  2000/03/01 23:29:20  midas
00154   Fixed bug with wrong event header data size in super eventsvents mfe.c
00155 
00156   Revision 1.16  2000/02/29 21:59:45  midas
00157   Added auto restart
00158 
00159   Revision 1.15  2000/02/26 01:25:54  midas
00160   Fixed bug that number of sent events was not cleared at start
00161 
00162   Revision 1.14  2000/02/25 20:22:49  midas
00163   Added super-event scheme
00164 
00165   Revision 1.13  2000/02/24 22:38:19  midas
00166   Outcommented USE_EVENT_CHANNEL
00167 
00168   Revision 1.12  2000/02/24 22:29:24  midas
00169   Added deferred transitions
00170 
00171   Revision 1.11  1999/12/08 00:50:29  pierre
00172   - fix EVID (ybos: strncpy to strncmp)
00173 
00174   Revision 1.10  1999/11/24 00:49:59  pierre
00175   - YBOS reject EVID bank in udpate_odb with eb_functions
00176 
00177   Revision 1.9  1999/11/23 18:25:25  pierre
00178   - YBOS reject EVID bank in udpate_odb
00179 
00180   Revision 1.8  1999/10/18 14:41:51  midas
00181   Use /programs/<name>/Watchdog timeout in all programs as timeout value. The
00182   default value can be submitted by calling cm_connect_experiment1(..., timeout)
00183 
00184   Revision 1.7  1999/10/15 12:17:52  midas
00185   Increased timeout
00186 
00187   Revision 1.6  1999/09/27 13:49:04  midas
00188   Added bUnique parameter to cm_shutdown
00189 
00190   Revision 1.5  1999/09/23 12:45:48  midas
00191   Added 32 bit banks
00192 
00193   Revision 1.4  1999/06/23 09:38:51  midas
00194   - Added D8_BKTYPE
00195   - Fixed CAMAC server F24 bug
00196   - cm_synchronize only called for VxWorks
00197 
00198   Revision 1.3  1998/12/10 12:50:47  midas
00199   Program abort with "!" now works without a return under UNIX
00200 
00201   Revision 1.2  1998/10/12 12:19:01  midas
00202   Added Log tag in header
00203 
00204 
00205 \********************************************************************/  
00206     
00207 #include <stdio.h>
00208 #include <assert.h>
00209 #include "midas.h"
00210 #include "msystem.h"
00211 #include "mcstd.h"
00212     
00213 #ifdef YBOS_SUPPORT
00214 #include "ybos.h"
00215 #endif                          /* 
00216  */
00217     
00218 /*------------------------------------------------------------------*/ 
00219     
00220 /* items defined in frontend.c */ 
00221 
00222 extern char *frontend_name;
00223 
00224 extern char *frontend_file_name;
00225 
00226 extern BOOL frontend_call_loop;
00227 
00228 extern INT max_event_size;
00229 
00230 extern INT max_event_size_frag;
00231 
00232 extern INT event_buffer_size;
00233 
00234 extern INT display_period;
00235 
00236 extern INT frontend_init(void);
00237 
00238 extern INT frontend_exit(void);
00239 
00240 extern INT frontend_loop(void);
00241 
00242 extern INT begin_of_run(INT run_number, char *error);
00243 
00244 extern INT end_of_run(INT run_number, char *error);
00245 
00246 extern INT pause_run(INT run_number, char *error);
00247 
00248 extern INT resume_run(INT run_number, char *error);
00249 
00250 extern INT poll_event(INT source, INT count, BOOL test);
00251 
00252 extern INT interrupt_configure(INT cmd, INT source, PTYPE adr);
00253 
00254 
00255 /*------------------------------------------------------------------*/ 
00256     
00257 /* globals */ 
00258     
00259 #undef USE_EVENT_CHANNEL
00260     
00261 #define SERVER_CACHE_SIZE  100000 /* event cache before buffer */
00262     
00263 #define ODB_UPDATE_TIME      1000 /* 1 seconds for ODB update */
00264     
00265 #define DEFAULT_FE_TIMEOUT  60000 /* 60 seconds for watchdog timeout */
00266     
00267 INT run_state;             /* STATE_RUNNING, STATE_STOPPED, STATE_PAUSED */
00268 
00269 INT run_number;
00270 
00271 DWORD actual_time;             /* current time in seconds since 1970 */
00272 
00273 DWORD actual_millitime;        /* current time in milliseconds */
00274 
00275 
00276 char host_name[HOST_NAME_LENGTH];
00277 
00278 char exp_name[NAME_LENGTH];
00279 
00280 
00281 INT max_bytes_per_sec;
00282 
00283 INT optimize = 0;              /* set this to one to opimize TCP buffer size */
00284 
00285 INT fe_stop = 0;               /* stop switch for VxWorks */
00286 
00287 BOOL debug;                    /* disable watchdog messages from server */
00288 
00289 DWORD auto_restart = 0;        /* restart run after event limit reached stop */
00290 
00291 
00292 HNDLE hDB;
00293 
00294 
00295 #ifdef YBOS_SUPPORT
00296     struct {
00297   
00298 DWORD ybos_type;
00299   
00300 DWORD odb_type;
00301   
00302 INT tsize;
00303 
00304 } id_map[] = {
00305   
00306  {
00307   A1_BKTYPE, TID_CHAR, 1}, 
00308  {
00309   I1_BKTYPE, TID_BYTE, 1}, 
00310  {
00311   I2_BKTYPE, TID_WORD, 2}, 
00312  {
00313   I4_BKTYPE, TID_DWORD, 4}, 
00314  {
00315   F4_BKTYPE, TID_FLOAT, 4}, 
00316  {
00317   D8_BKTYPE, TID_DOUBLE, 8}, 
00318  {
00319 0, 0} 
00320 };
00321 
00322 
00323 #endif                          /* 
00324  */
00325 
00326 extern EQUIPMENT equipment[];
00327 
00328 
00329 EQUIPMENT * interrupt_eq = NULL;
00330 
00331 EVENT_HEADER * interrupt_odb_buffer;
00332 
00333 BOOL interrupt_odb_buffer_valid;
00334 
00335 
00336 int send_event(INT index);
00337 
00338 void send_all_periodic_events(INT transition);
00339 
00340 void interrupt_routine(void);
00341 
00342 void interrupt_enable(BOOL flag);
00343 
00344 void display(BOOL bInit);
00345 
00346 
00347 /*---- ODB records -------------------------------------------------*/ 
00348     
00349 #define EQUIPMENT_COMMON_STR "\
00350 Event ID = WORD: 0 \ n \ 
00351 Trigger mask = WORD: 0 \ n \ 
00352 Buffer = STRING: [32] SYSTEM \ n \ 
00353 Type = INT: 0 \ n \ 
00354 Source = INT: 0 \ n \ 
00355 Format = STRING: [8] FIXED \ n \ 
00356 Enabled = BOOL: 0 \ n \ 
00357 Read on = INT: 0 \ n \ 
00358 Period = INT: 0 \ n \ 
00359 Event limit = DOUBLE: 0 \ n \ 
00360 Num subevents = DWORD: 0 \ n \ 
00361 Log history = INT: 0 \ n \ 
00362 Frontend host = STRING: [32] \ n \ 
00363 Frontend name = STRING: [32] \ n \ 
00364 Frontend file name = STRING: [256] \ n \ 
00365 "
00366 
00367 #define EQUIPMENT_STATISTICS_STR " \ 
00368 Events sent = DOUBLE: 0 \ n \ 
00369 Events per sec. = DOUBLE: 0 \ n \ 
00370 kBytes per sec. = DOUBLE:0 \ n \ 
00371 "
00372 
00373 /*-- transition callbacks ------------------------------------------*/
00374 
00375 /*-- start ---------------------------------------------------------*/
00376 
00377 INT tr_start(INT rn, char *error)
00378 {
00379 INT i, status;
00380 
00381   /* reset serial numbers */
00382   for (i=0 ; equipment[i].name[0] ; i++)
00383     {
00384     equipment[i].serial_number = 1;
00385     equipment[i].subevent_number = 0;
00386     equipment[i].stats.events_sent = 0;
00387     equipment[i].odb_in = equipment[i].odb_out = 0;
00388     }
00389 
00390   status = begin_of_run(rn, error);
00391 
00392   if (status == CM_SUCCESS)
00393     {
00394     run_state = STATE_RUNNING;
00395     run_number = rn;
00396 
00397     send_all_periodic_events(TR_START);
00398 
00399     if (display_period)
00400       {
00401       ss_printf(14, 2, " Running ");
00402       ss_printf(36, 2, " % d ", rn);
00403       }
00404 
00405     /* enable interrupts */
00406     interrupt_enable(TRUE);
00407     }
00408     
00409   return status;
00410 }
00411 
00412 /*-- prestop -------------------------------------------------------*/
00413 
00414 INT tr_prestop(INT rn, char *error)
00415 {
00416 INT status, i;
00417 
00418   /* disable interrupts */
00419   interrupt_enable(FALSE);
00420 
00421   status = end_of_run(rn, error);
00422 
00423   if (status == CM_SUCCESS)
00424     {
00425     /* don't send events if already stopped */
00426     if (run_state != STATE_STOPPED)
00427       send_all_periodic_events(TR_STOP);
00428 
00429     run_state = STATE_STOPPED;
00430     run_number = rn;
00431 
00432     if (display_period)
00433       ss_printf(14, 2, " Stopped ");
00434     }
00435   else
00436     interrupt_enable(TRUE);
00437 
00438   /* flush remaining buffered events */
00439   rpc_flush_event();
00440   for (i=0 ; equipment[i].name[0] ; i++)
00441     if (equipment[i].buffer_handle)
00442       {
00443     INT err = bm_flush_cache(equipment[i].buffer_handle, SYNC);
00444     if (err != BM_SUCCESS)
00445       {
00446         cm_msg(MERROR," tr_prestop "," bm_flush_cache(SYNC) error % d ",err);
00447         return err;
00448       }
00449       }
00450 
00451   return status;
00452 }
00453 
00454 /*-- pause ---------------------------------------------------------*/
00455 
00456 INT tr_prepause(INT rn, char *error)
00457 {
00458 INT status;
00459 
00460   /* disable interrupts */
00461   interrupt_enable(FALSE);
00462 
00463   status = pause_run(rn, error);
00464 
00465   if (status == CM_SUCCESS)
00466     {
00467     run_state = STATE_PAUSED;
00468     run_number = rn;
00469 
00470     send_all_periodic_events(TR_PAUSE);
00471 
00472     if (display_period)
00473       ss_printf(14, 2, " Paused ");
00474     }
00475   else
00476     interrupt_enable(TRUE);
00477 
00478   return status;
00479 }
00480 
00481 /*-- resume --------------------------------------------------------*/
00482 
00483 INT tr_resume(INT rn, char *error)
00484 {
00485 INT status;
00486 
00487   status = resume_run(rn, error);
00488 
00489   if (status == CM_SUCCESS)
00490     {
00491     run_state = STATE_RUNNING;
00492     run_number = rn;
00493 
00494     send_all_periodic_events(TR_RESUME);
00495 
00496     if (display_period)
00497       ss_printf(14, 2, " Running ");
00498 
00499     /* enable interrupts */
00500     interrupt_enable(TRUE);
00501     }
00502 
00503   return status;
00504 }
00505 
00506 /*------------------------------------------------------------------*/
00507 
00508 INT manual_trigger(INT index, void *prpc_param[])
00509 {
00510 WORD event_id, i;
00511 
00512   event_id = CWORD(0);
00513 
00514   for (i=0 ; equipment[i].name[0] ; i++)
00515     if (equipment[i].info.event_id == event_id)
00516       send_event(i);
00517 
00518   if (display_period)
00519     display(FALSE);
00520 
00521   return SUCCESS;
00522 }
00523 
00524 /*------------------------------------------------------------------*/
00525 
00526 INT register_equipment(void)
00527 {
00528 INT    index, count, size, status, i, j, k, n;
00529 char   str[256];
00530 EQUIPMENT_INFO *eq_info;
00531 EQUIPMENT_STATS *eq_stats;
00532 DWORD  start_time, delta_time;
00533 HNDLE  hKey;
00534 BOOL   manual_trig_flag = FALSE;
00535 BANK_LIST *bank_list;
00536 DWORD  dummy;
00537 
00538   /* get current ODB run state */
00539   size = sizeof(run_state);
00540   run_state = STATE_STOPPED;
00541   db_get_value(hDB, 0, " / Runinfo / State ", &run_state, &size, TID_INT, TRUE);
00542   size = sizeof(run_number);
00543   run_number = 1;
00544   status = db_get_value(hDB, 0, " / Runinfo /
00545     Run number ", &run_number, &size, TID_INT, TRUE);
00546   assert(status == SUCCESS);
00547 
00548   /* scan EQUIPMENT table from FRONTEND.C */
00549   for (index=0 ; equipment[index].name[0] ; index++)
00550     {
00551     eq_info = &equipment[index].info;
00552     eq_stats = &equipment[index].stats;
00553 
00554     if (eq_info->event_id == 0)
00555       {
00556       printf(" Event ID 0 for %s
00557   not allowed \ n ", equipment[index].name);
00558       ss_sleep(5000);
00559       }
00560 
00561     /* init status */
00562     equipment[index].status = FE_SUCCESS;
00563 
00564     sprintf(str, " / Equipment / %s / Common ", equipment[index].name);
00565     
00566     /* get last event limit from ODB */
00567     if (eq_info->eq_type != EQ_SLOW)
00568       {
00569       db_find_key(hDB, 0, str, &hKey);
00570       size = sizeof(double);
00571       if (hKey)
00572         db_get_value(hDB, hKey, " Event limit ", &eq_info->event_limit, &size, TID_DOUBLE, TRUE);
00573       }
00574     
00575     /* Create common subtree */
00576     status = db_check_record(hDB, 0, str, EQUIPMENT_COMMON_STR, TRUE);
00577     if (status != DB_SUCCESS)
00578       {
00579       printf(" Cannot check equipment record, status = %d \ n ", status);
00580       ss_sleep(3000);
00581       }
00582     db_find_key(hDB, 0, str, &hKey);
00583 
00584     if (equal_ustring(eq_info->format, " YBOS "))
00585       equipment[index].format = FORMAT_YBOS;
00586     else if (equal_ustring(eq_info->format, " FIXED "))
00587       equipment[index].format = FORMAT_FIXED;
00588     else /* default format is MIDAS */
00589       equipment[index].format = FORMAT_MIDAS;
00590 
00591     gethostname(eq_info->frontend_host, sizeof(eq_info->frontend_host));
00592     strcpy(eq_info->frontend_name, frontend_name);
00593     strcpy(eq_info->frontend_file_name, frontend_file_name);
00594 
00595     /* set record from equipment[] table in frontend.c */
00596     db_set_record(hDB, hKey, eq_info, sizeof(EQUIPMENT_INFO), 0);
00597 
00598     /* open hot link to equipment info */
00599     db_open_record(hDB, hKey, eq_info, sizeof(EQUIPMENT_INFO), MODE_READ, NULL, NULL);
00600 
00601     /*---- Create variables record ---------------------------------*/
00602     sprintf(str, " / Equipment / %s / Variables ", equipment[index].name);
00603     if (equipment[index].event_descrip)
00604       {
00605       if (equipment[index].format == FORMAT_FIXED)
00606         db_check_record(hDB, 0, str, (char *)equipment[index].event_descrip, TRUE);
00607       else
00608         {
00609         /* create bank descriptions */
00610         bank_list = (BANK_LIST *)equipment[index].event_descrip;
00611 
00612         for (; bank_list->name[0] ; bank_list++)
00613           {
00614           /* mabye needed later...
00615           if (bank_list->output_flag == 0)
00616             continue;
00617           */
00618 
00619           if (bank_list->type == TID_STRUCT)
00620             {
00621             sprintf(str, " / Equipment / %s / Variables / %s ", equipment[index].name, bank_list->name);
00622             status = db_check_record(hDB, 0, str, strcomb(bank_list->init_str), TRUE);
00623             if (status != DB_SUCCESS)
00624               {
00625               printf(" Cannot check / create record \ "%s\", status = %d\n", str, status);
00626 
00627 ss_sleep(3000);
00628 
00629 }
00630 
00631 }
00632 
00633 
00634 else
00635 
00636 {
00637   
00638 sprintf(str, "/Equipment/%s/Variables/%s", equipment[index].name,
00639            bank_list->name);
00640   
00641 dummy = 0;
00642   
00643 db_set_value(hDB, 0, str, &dummy, rpc_tid_size(bank_list->type), 1,
00644                 bank_list->type);
00645 
00646 }
00647 
00648 }
00649 
00650 }
00651 
00652 }
00653 
00654 
00655 else
00656 
00657 db_create_key(hDB, 0, str, TID_KEY);
00658 
00659 
00660 sprintf(str, "/Equipment/%s/Variables", equipment[index].name);
00661 
00662 db_find_key(hDB, 0, str, &hKey);
00663 
00664 equipment[index].hkey_variables = hKey;
00665 
00666 
00667     /*---- Create and initialize statistics tree -------------------*/ 
00668     sprintf(str, "/Equipment/%s/Statistics", equipment[index].name);
00669 
00670 
00671 status = db_check_record(hDB, 0, str, EQUIPMENT_STATISTICS_STR, TRUE);
00672 
00673 if (status != DB_SUCCESS)
00674   
00675  {
00676   
00677 printf("Cannot create/check statistics record, error %d\n", status);
00678   
00679 ss_sleep(3000);
00680   
00681 }
00682 
00683 
00684 status = db_find_key(hDB, 0, str, &hKey);
00685 
00686 if (status != DB_SUCCESS)
00687   
00688  {
00689   
00690 printf("Cannot find statistics record, error %d\n", status);
00691   
00692 ss_sleep(3000);
00693   
00694 }
00695 
00696 
00697 eq_stats->events_sent = 0;
00698 
00699 eq_stats->events_per_sec = 0;
00700 
00701 eq_stats->kbytes_per_sec = 0;
00702 
00703 
00704     /* open hot link to statistics tree */ 
00705     status =
00706     db_open_record(hDB, hKey, eq_stats, sizeof(EQUIPMENT_STATS),
00707                    MODE_WRITE, NULL, NULL);
00708 
00709 if (status != DB_SUCCESS)
00710   
00711  {
00712   
00713 printf
00714       ("Cannot open statistics record, error %d. Probably other FE is using it\n",
00715        status);
00716   
00717 ss_sleep(3000);
00718   
00719 }
00720 
00721 
00722     /*---- open event buffer ---------------------------------------*/ 
00723     if (eq_info->buffer[0])
00724   
00725  {
00726   
00727 status =
00728       bm_open_buffer(eq_info->buffer, EVENT_BUFFER_SIZE,
00729                      &equipment[index].buffer_handle);
00730   
00731 if (status != BM_SUCCESS && status != BM_CREATED)
00732     
00733  {
00734     
00735 cm_msg(MERROR, "register_equipment",
00736             
00737 "Cannot open event buffer. Try to reduce EVENT_BUFFER_SIZE in midas.h \
00738 and rebuild the system.");
00739     
00740 return 0;
00741     
00742 }
00743   
00744 
00745       /* set the default buffer cache size */ 
00746       bm_set_cache_size(equipment[index].buffer_handle, 0,
00747                         SERVER_CACHE_SIZE);
00748   
00749 }
00750 
00751 else
00752   
00753 equipment[index].buffer_handle = 0;
00754 
00755 
00756     /*---- evaluate polling count ----------------------------------*/ 
00757     if (eq_info->eq_type & EQ_POLLED)
00758   
00759  {
00760   
00761 if (display_period)
00762     
00763 printf("\nCalibrating");
00764   
00765 
00766 count = 1;
00767   
00768   do
00769     
00770  {
00771     
00772 if (display_period)
00773       
00774 printf(".");
00775     
00776 
00777 start_time = ss_millitime();
00778     
00779 
00780 poll_event(equipment[index].info.source, count, TRUE);
00781     
00782 
00783 delta_time = ss_millitime() - start_time;
00784     
00785 
00786 if (delta_time > 0)
00787       
00788 count = (INT) ((double) count * 100 / delta_time);
00789     
00790     else
00791       
00792 count *= 100;
00793   
00794 } while (delta_time > 120 || delta_time < 80);
00795   
00796 
00797 equipment[index].poll_count =
00798       (INT) ((double) eq_info->period / 100 * count);
00799   
00800 
00801 if (display_period)
00802     
00803 printf("OK\n");
00804   
00805 }
00806 
00807 
00808     /*---- initialize interrupt events -----------------------------*/ 
00809     if (eq_info->eq_type & EQ_INTERRUPT)
00810   
00811  {
00812   
00813       /* install interrupt for interrupt events */ 
00814       
00815 for (i = 0; equipment[i].name[0]; i++)
00816     
00817 if (equipment[i].info.eq_type & EQ_POLLED)
00818       
00819  {
00820       
00821 equipment[index].status = FE_ERR_DISABLED;
00822       
00823 cm_msg(MINFO, "register_equipment",
00824               
00825 "Interrupt readout cannot be combined with polled readout");
00826       
00827 }
00828   
00829 
00830 if (equipment[index].status != FE_ERR_DISABLED)
00831     
00832  {
00833     
00834 if (eq_info->enabled)
00835       
00836  {
00837       
00838 if (interrupt_eq)
00839         
00840  {
00841         
00842 equipment[index].status = FE_ERR_DISABLED;
00843         
00844 cm_msg(MINFO, "register_equipment",
00845                 
00846 "Defined more than one equipment with interrupt readout");
00847         
00848 }
00849       
00850       else
00851         
00852  {
00853         
00854 interrupt_configure(CMD_INTERRUPT_ATTACH,
00855                              eq_info->source, (PTYPE) interrupt_routine);
00856         
00857 interrupt_eq = &equipment[index];
00858         
00859 interrupt_odb_buffer =
00860             (EVENT_HEADER *) malloc(MAX_EVENT_SIZE + sizeof(EVENT_HEADER));
00861         
00862 }
00863       
00864 }
00865     
00866     else
00867       
00868  {
00869       
00870 equipment[index].status = FE_ERR_DISABLED;
00871       
00872 cm_msg(MINFO, "register_equipment",
00873               "Equipment %s disabled in file \"frontend.c\"",
00874               
00875 equipment[index].name);
00876       
00877 }
00878     
00879 }
00880   
00881 }
00882 
00883 
00884     /*---- initialize slow control equipment -----------------------*/ 
00885     if (eq_info->eq_type & EQ_SLOW)
00886   
00887  {
00888   
00889       /* resolve duplicate device names */ 
00890       for (i = 0; equipment[index].driver[i].name[0]; i++)
00891     
00892 for (j = i + 1; equipment[index].driver[j].name[0]; j++)
00893       
00894 if (equal_ustring
00895            (equipment[index].driver[i].name,
00896             
00897 equipment[index].driver[j].name))
00898         
00899  {
00900         
00901 strcpy(str, equipment[index].driver[i].name);
00902         
00903 for (k = 0, n = 0; equipment[index].driver[k].name[0]; k++)
00904           
00905 if (equal_ustring(str, equipment[index].driver[k].name))
00906             
00907 sprintf(equipment[index].driver[k].name, "%s_%d", str, n++);
00908         
00909 
00910 break;
00911         
00912 }
00913   
00914 
00915       /* loop over equipment list and call class driver's init method */ 
00916       if (eq_info->enabled)
00917     
00918 equipment[index].status =
00919         equipment[index].cd(CMD_INIT, &equipment[index]);
00920   
00921   else
00922     
00923  {
00924     
00925 equipment[index].status = FE_ERR_DISABLED;
00926     
00927 cm_msg(MINFO, "register_equipment",
00928             "Equipment %s disabled in file \"frontend.c\"",
00929             
00930 equipment[index].name);
00931     
00932 }
00933   
00934 
00935       /* let user read error messages */ 
00936       if (equipment[index].status != FE_SUCCESS)
00937     
00938 ss_sleep(3000);
00939   
00940 }
00941 
00942 
00943     /*---- register callback for manual triggered events -----------*/ 
00944     if (eq_info->eq_type & EQ_MANUAL_TRIG)
00945   
00946  {
00947   
00948 if (!manual_trig_flag)
00949     
00950 cm_register_function(RPC_MANUAL_TRIG, manual_trigger);
00951   
00952 
00953 manual_trig_flag = TRUE;
00954   
00955 }
00956 
00957 }
00958 
00959 
00960 
00961 return SUCCESS;
00962 
00963 }
00964 
00965 
00966 
00967 /*------------------------------------------------------------------*/ 
00968 
00969 void update_odb(EVENT_HEADER * pevent, HNDLE hKey, INT format) 
00970  {
00971   
00972 INT size, i, ni4, tsize, status, n_data;
00973   
00974 void *pdata;
00975   
00976 char name[5];
00977   
00978 BANK_HEADER * pbh;
00979   
00980 BANK * pbk;
00981   
00982 BANK32 * pbk32;
00983   
00984 void *pydata;
00985   
00986 DWORD odb_type;
00987   
00988 DWORD * pyevt, bkname;
00989   
00990 WORD bktype;
00991   
00992 HNDLE hKeyRoot, hKeyl;
00993   
00994 KEY key;
00995   
00996 
00997       /* outcommented sind db_find_key does not work in FTCP mode, SR 25.4.03
00998          rpc_set_option(-1, RPC_OTRANSPORT, RPC_FTCP); */ 
00999       
01000 if (format == FORMAT_FIXED)
01001     
01002  {
01003     
01004 if (db_set_record
01005          (hDB, hKey, (char *) (pevent + 1), 
01006 pevent->data_size,
01007           0) != DB_SUCCESS)
01008       
01009 cm_msg(MERROR, "update_odb", "event #%d size mismatch",
01010               pevent->event_id);
01011     
01012 }
01013   
01014   else if (format == FORMAT_MIDAS)
01015     
01016  {
01017     
01018 pbh = (BANK_HEADER *) (pevent + 1);
01019     
01020 pbk = NULL;
01021     
01022 pbk32 = NULL;
01023     
01024     do
01025       
01026  {
01027       
01028           /* scan all banks */ 
01029           if (bk_is32(pbh))
01030         
01031  {
01032         
01033 size = bk_iterate32(pbh, &pbk32, &pdata);
01034         
01035 if (pbk32 == NULL)
01036           
01037 break;
01038         
01039 bkname = *((DWORD *) pbk32->name);
01040         
01041 bktype = (WORD) pbk32->type;
01042         
01043 }
01044       
01045       else
01046         
01047  {
01048         
01049 size = bk_iterate(pbh, &pbk, &pdata);
01050         
01051 if (pbk == NULL)
01052           
01053 break;
01054         
01055 bkname = *((DWORD *) pbk->name);
01056         
01057 bktype = (WORD) pbk->type;
01058         
01059 }
01060       
01061 
01062 n_data = size;
01063       
01064 if (rpc_tid_size(bktype & 0xFF))
01065         
01066 n_data /= rpc_tid_size(bktype & 0xFF);
01067       
01068 
01069           /* get bank key */ 
01070           *((DWORD *) name) = bkname;
01071       
01072 name[4] = 0;
01073       
01074 
01075 if (bktype == TID_STRUCT)
01076         
01077  {
01078         
01079 status = db_find_key(hDB, hKey, name, &hKeyRoot);
01080         
01081 if (status != DB_SUCCESS)
01082           
01083  {
01084           
01085 cm_msg(MERROR, "update_odb",
01086                   "please define bank %s in BANK_LIST in frontend.c",
01087                   name);
01088           
01089 continue;
01090           
01091 }
01092         
01093 
01094             /* write structured bank */ 
01095             for (i = 0;; i++)
01096           
01097  {
01098           
01099 char *temp;
01100           
01101 status = db_enum_key(hDB, hKeyRoot, i, &hKeyl);
01102           
01103 if (status == DB_NO_MORE_SUBKEYS)
01104             
01105 break;
01106           
01107 
01108 db_get_key(hDB, hKeyl, &key);
01109           
01110 
01111               /* adjust for alignment */ 
01112               if (key.type != TID_STRING && key.type != TID_LINK)
01113             
01114 pdata =
01115                 (void *) VALIGN(pdata,
01116                                 min(ss_get_struct_align(), key.item_size));
01117           
01118 
01119 status =
01120               db_set_data(hDB, hKeyl, pdata,
01121                           key.item_size * key.num_values,
01122                           
01123 key.num_values, key.type);
01124           
01125 if (status != DB_SUCCESS)
01126             
01127  {
01128             
01129 cm_msg(MERROR, "update_odb", "cannot write %s to ODB", name);
01130             
01131 continue;
01132             
01133 }
01134           
01135 
01136               /* shift data pointer to next item */ 
01137 //          (char *) pdata += key.item_size*key.num_values;
01138               temp = (char *) pdata;    //JPM
01139           temp += key.item_size * key.num_values;
01140           
01141 pdata = (void *) temp;
01142         
01143 } 
01144 }
01145       
01146       else
01147         
01148  {
01149         
01150             /* write variable length bank  */ 
01151             if (n_data > 0)
01152           
01153 db_set_value(hDB, hKey, name, pdata, size,
01154                         n_data, bktype & 0xFF);
01155         
01156 }
01157     
01158 
01159 } while (1);
01160     
01161 }
01162   
01163   else if (format == FORMAT_YBOS)
01164     
01165  {
01166     
01167 #ifdef YBOS_SUPPORT
01168         YBOS_BANK_HEADER * pybkh;
01169     
01170 
01171         /* skip the lrl (4 bytes per event) */ 
01172         pyevt = (DWORD *) (pevent + 1);
01173     
01174 pybkh = NULL;
01175     
01176     do
01177       
01178  {
01179       
01180           /* scan all banks */ 
01181           ni4 = ybk_iterate(pyevt, &pybkh, &pydata);
01182       
01183 if (pybkh == NULL || ni4 == 0)
01184         
01185 break;
01186       
01187 
01188           /* find the corresponding odb type */ 
01189           tsize = odb_type = 0;
01190       
01191 for (i = 0; id_map[0].ybos_type > 0; i++)
01192         
01193  {
01194         
01195 if (pybkh->type == id_map[i].ybos_type)
01196           
01197  {
01198           
01199 odb_type = id_map[i].odb_type;
01200           
01201 tsize = id_map[i].tsize;
01202           
01203 break;
01204           
01205 }
01206         
01207 }
01208       
01209 
01210           /* extract bank name (key name) */ 
01211           *((DWORD *) name) = pybkh->name;
01212       
01213 name[4] = 0;
01214       
01215 
01216           /* reject EVID bank */ 
01217           if (strncmp(name, "EVID", 4) == 0)
01218         
01219 continue;
01220       
01221 
01222           /* correct YBS number of entries */ 
01223           if (pybkh->type == D8_BKTYPE)
01224         
01225 ni4 /= 2;
01226       
01227 if (pybkh->type == I2_BKTYPE)
01228         
01229 ni4 *= 2;
01230       
01231 if (pybkh->type == I1_BKTYPE || pybkh->type == A1_BKTYPE)
01232         
01233 ni4 *= 4;
01234       
01235 
01236           /* write bank to ODB, ni4 always in I*4 */ 
01237           size = ni4 * tsize;
01238       
01239 if ((status =
01240             db_set_value(hDB, hKey, name, pydata, size, ni4,
01241                          odb_type & 0xFF)) != DB_SUCCESS)
01242         
01243  {
01244         
01245 float *ftemp;
01246         
01247 printf
01248             ("status:%i odb_type:%li name:%s ni4:%i size:%i tsize:%i\n",
01249              
01250 status, odb_type, name, ni4, size, tsize);
01251         
01252 ftemp = (float *) pydata;      //JPM
01253         for (i = 0; i < 6; i++)
01254           
01255 printf("data: %f\n", *ftemp++);
01256         
01257 }
01258     
01259 } while (1);
01260     
01261 #endif  /* YBOS_SUPPORT */
01262     }
01263   
01264 
01265 rpc_set_option(-1, RPC_OTRANSPORT, RPC_TCP);
01266 
01267 }
01268 
01269 
01270 
01271 /*------------------------------------------------------------------*/ 
01272 
01273 int send_event(INT index) 
01274  {
01275   
01276 EQUIPMENT_INFO * eq_info;
01277   
01278 EVENT_HEADER * pevent, *pfragment;
01279   
01280 char *pdata;
01281   
01282 unsigned char *pd;
01283   
01284 INT i, status;
01285   
01286 DWORD sent, size;
01287   
01288 static void *frag_buffer = NULL;
01289   
01290 
01291 eq_info = &equipment[index].info;
01292   
01293 
01294       /* check for fragmented event */ 
01295       if (eq_info->eq_type & EQ_FRAGMENTED)
01296     
01297  {
01298     
01299 if (frag_buffer == NULL)
01300       
01301 frag_buffer = malloc(max_event_size_frag);
01302     
01303 
01304 if (frag_buffer == NULL)
01305       
01306  {
01307       
01308 cm_msg(MERROR, "send_event",
01309               "Not enough memory to allocate buffer for fragmented events");
01310       
01311 return SS_NO_MEMORY;
01312       
01313 }
01314     
01315 
01316 pevent = (EVENT_HEADER *) frag_buffer;
01317     
01318 }
01319   
01320   else
01321     
01322  {
01323     
01324         /* return value should be valid pointer. if NULL BIG error ==> abort  */ 
01325         pevent = dm_pointer_get();
01326     
01327 if (pevent == NULL)
01328       
01329  {
01330       
01331 cm_msg(MERROR, "send_event",
01332               "dm_pointer_get not returning valid pointer");
01333       
01334 return SS_NO_MEMORY;
01335       
01336 }
01337     
01338 }
01339   
01340 
01341       /* compose MIDAS event header */ 
01342       pevent->event_id = eq_info->event_id;
01343   
01344 pevent->trigger_mask = eq_info->trigger_mask;
01345   
01346 pevent->data_size = 0;
01347   
01348 pevent->time_stamp = ss_time();
01349   
01350 pevent->serial_number = equipment[index].serial_number++;
01351   
01352 
01353 equipment[index].last_called = ss_millitime();
01354   
01355 
01356       /* call user readout routine */ 
01357       *((EQUIPMENT **) (pevent + 1)) = &equipment[index];
01358   
01359 pevent->data_size = equipment[index].readout((char *) (pevent + 1), 0);
01360   
01361 
01362       /* send event */ 
01363       if (pevent->data_size)
01364     
01365  {
01366     
01367 if (eq_info->eq_type & EQ_FRAGMENTED)
01368       
01369  {
01370       
01371           /* fragment event */ 
01372           if (pevent->data_size + sizeof(EVENT_HEADER) >
01373               (DWORD) max_event_size_frag)
01374         
01375  {
01376         
01377 cm_msg(MERROR, "send_event",
01378                 "Event size %ld larger than maximum size %d for frag. ev.",
01379                 
01380 (long) (pevent->data_size +
01381                          sizeof(EVENT_HEADER)), max_event_size_frag);
01382         
01383 return SS_NO_MEMORY;
01384         
01385 }
01386       
01387 
01388           /* compose fragments */ 
01389           pfragment = dm_pointer_get();
01390       
01391 if (pfragment == NULL)
01392         
01393  {
01394         
01395 cm_msg(MERROR, "send_event",
01396                 "dm_pointer_get not returning valid pointer");
01397         
01398 return SS_NO_MEMORY;
01399         
01400 }
01401       
01402 
01403           /* compose MIDAS event header */ 
01404           memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
01405       
01406 pfragment->event_id |= EVENTID_FRAG1;
01407       
01408 
01409           /* store total event size */ 
01410           pd = (unsigned char *) (pfragment + 1);       //JPM
01411       size = pevent->data_size;
01412       
01413 for (i = 0; i < 4; i++)
01414         
01415  {
01416         
01417 pd[i] = (unsigned char) (size & 0xFF); /* little endian, please! */
01418         
01419 size >>= 8;
01420         
01421 } 
01422 
01423 pfragment->data_size = sizeof(DWORD);
01424       
01425 
01426 pdata = (char *) (pevent + 1);
01427       
01428 
01429 for (i = 0, sent = 0; sent < pevent->data_size; i++)
01430         
01431  {
01432         
01433 if (i > 0)
01434           
01435  {
01436           
01437 pfragment = dm_pointer_get();
01438           
01439 
01440               /* compose MIDAS event header */ 
01441               memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
01442           
01443 pfragment->event_id |= EVENTID_FRAG;
01444           
01445 
01446               /* copy portion of event */ 
01447               size = pevent->data_size - sent;
01448           
01449 if (size > max_event_size - sizeof(EVENT_HEADER))
01450             
01451 size = max_event_size - sizeof(EVENT_HEADER);
01452           
01453 
01454 memcpy(pfragment + 1, pdata, size);
01455           
01456 pfragment->data_size = size;
01457           
01458 sent += size;
01459           
01460 pdata += size;
01461           
01462 }
01463         
01464 
01465             /* send event to buffer */ 
01466             if (equipment[index].buffer_handle)
01467           
01468  {
01469           
01470 #ifdef USE_EVENT_CHANNEL
01471               dm_pointer_increment(equipment[index].
01472                                    buffer_handle,
01473                                    
01474 pfragment->
01475                                    data_size + sizeof(EVENT_HEADER));
01476           
01477 #else                           /* 
01478  */
01479               rpc_flush_event();
01480           
01481 status =
01482               bm_send_event(equipment[index].
01483                             buffer_handle, pfragment,
01484                             
01485 pfragment->data_size +
01486                             sizeof(EVENT_HEADER), SYNC);
01487           
01488 if (status != BM_SUCCESS)
01489             
01490  {
01491             
01492 cm_msg(MERROR, "send_event",
01493                     "bm_send_event(SYNC) error %d", status);
01494             
01495 return status;
01496             
01497 }
01498           
01499 #endif                          /* 
01500  */
01501           }
01502         
01503 }
01504       
01505 
01506 if (equipment[index].buffer_handle) {
01507         
01508 #ifndef USE_EVENT_CHANNEL
01509             status = bm_flush_cache(equipment[index].buffer_handle, SYNC);
01510         
01511 if (status != BM_SUCCESS)
01512           
01513  {
01514           
01515 cm_msg(MERROR, "send_event",
01516                   "bm_flush_cache(SYNC) error %d", status);
01517           
01518 return status;
01519           
01520 }
01521         
01522 #endif                          /* 
01523  */
01524       }
01525       
01526 }
01527     
01528     else
01529       
01530  {
01531       
01532           /* send unfragmented event */ 
01533           
01534 if (pevent->data_size + sizeof(EVENT_HEADER) >
01535                (DWORD) max_event_size)
01536         
01537  {
01538         
01539 cm_msg(MERROR, "send_event",
01540                 "Event size %ld larger than maximum size %d",
01541                 
01542 (long) (pevent->data_size +
01543                          sizeof(EVENT_HEADER)), max_event_size);
01544         
01545 return SS_NO_MEMORY;
01546         
01547 }
01548       
01549 
01550           /* send event to buffer */ 
01551           if (equipment[index].buffer_handle)
01552         
01553  {
01554         
01555 #ifdef USE_EVENT_CHANNEL
01556             dm_pointer_increment(equipment[index].
01557                                  buffer_handle,
01558                                  
01559 pevent->data_size +
01560                                  sizeof(EVENT_HEADER));
01561         
01562 #else                           /* 
01563  */
01564             rpc_flush_event();
01565         
01566 status =
01567             bm_send_event(equipment[index].buffer_handle,
01568                           pevent,
01569                           
01570 pevent->data_size + sizeof(EVENT_HEADER), SYNC);
01571         
01572 if (status != BM_SUCCESS)
01573           
01574  {
01575           
01576 cm_msg(MERROR, "send_event",
01577                   "bm_send_event(SYNC) error %d", status);
01578           
01579 return status;
01580           
01581 }
01582         
01583 status = bm_flush_cache(equipment[index].buffer_handle, SYNC);
01584         
01585 if (status != BM_SUCCESS)
01586           
01587  {
01588           
01589 cm_msg(MERROR, "send_event",
01590                   "bm_flush_cache(SYNC) error %d", status);
01591           
01592 return status;
01593           
01594 }
01595         
01596 #endif                          /* 
01597  */
01598         }
01599       
01600 
01601           /* send event to ODB if RO_ODB flag is set or history is on. Do not
01602              send SLOW events since the class driver does that */ 
01603           if ((eq_info->read_on & RO_ODB) || 
01604               (eq_info->history > 0 && (eq_info->eq_type & ~EQ_SLOW)))
01605         
01606  {
01607         
01608 update_odb(pevent,
01609                     equipment[index].hkey_variables,
01610                     equipment[index].format);
01611         
01612 equipment[index].odb_out++;
01613         
01614 }
01615       
01616 }
01617     
01618 
01619 equipment[index].bytes_sent +=
01620         pevent->data_size + sizeof(EVENT_HEADER);
01621     
01622 equipment[index].events_sent++;
01623     
01624 
01625 equipment[index].stats.events_sent += equipment[index].events_sent;
01626     
01627 equipment[index].events_sent = 0;
01628     
01629 }
01630   
01631   else
01632     
01633 equipment[index].serial_number--;
01634   
01635 
01636       /* emtpy event buffer */ 
01637 #ifdef USE_EVENT_CHANNEL
01638       if ((status = dm_area_flush()) != CM_SUCCESS)
01639     
01640 cm_msg(MERROR, "send_event", "dm_area_flush: %i", status);
01641   
01642 #endif                          /* 
01643  */
01644       
01645 for (i = 0; equipment[i].name[0]; i++)
01646     
01647 if (equipment[i].buffer_handle)
01648       
01649  {
01650       
01651 status = bm_flush_cache(equipment[i].buffer_handle, SYNC);
01652       
01653 if (status != BM_SUCCESS)
01654         
01655  {
01656         
01657 cm_msg(MERROR, "send_event",
01658                 "bm_flush_cache(SYNC) error %d", status);
01659         
01660 return status;
01661         
01662 }
01663       
01664 }
01665   
01666 
01667 return CM_SUCCESS;
01668 
01669 }
01670 
01671 
01672 
01673 /*------------------------------------------------------------------*/ 
01674 
01675 void send_all_periodic_events(INT transition) 
01676  {
01677   
01678 EQUIPMENT_INFO * eq_info;
01679   
01680 INT i;
01681   
01682 
01683 for (i = 0; equipment[i].name[0]; i++)
01684     
01685  {
01686     
01687 eq_info = &equipment[i].info;
01688     
01689 
01690 if (!eq_info->enabled || equipment[i].status != FE_SUCCESS)
01691       
01692 continue;
01693     
01694 
01695 if (transition == TR_START && (eq_info->read_on & RO_BOR) == 0)
01696       
01697 continue;
01698     
01699 if (transition == TR_STOP && (eq_info->read_on & RO_EOR) == 0)
01700       
01701 continue;
01702     
01703 if (transition == TR_PAUSE && (eq_info->read_on & RO_PAUSE) == 0)
01704       
01705 continue;
01706     
01707 if (transition == TR_RESUME && (eq_info->read_on & RO_RESUME) == 0)
01708       
01709 continue;
01710     
01711 
01712 send_event(i);
01713     
01714 }
01715 
01716 }
01717 
01718 
01719 
01720 /*------------------------------------------------------------------*/ 
01721     
01722 BOOL interrupt_enabled;
01723 
01724 
01725 void interrupt_enable(BOOL flag) 
01726  {
01727   
01728 interrupt_enabled = flag;
01729   
01730 
01731 if (interrupt_eq)
01732     
01733  {
01734     
01735 if (interrupt_enabled)
01736       
01737 interrupt_configure(CMD_INTERRUPT_ENABLE, 0, 0);
01738     
01739     else
01740       
01741 interrupt_configure(CMD_INTERRUPT_DISABLE, 0, 0);
01742     
01743 }
01744 
01745 }
01746 
01747 
01748 
01749 /*------------------------------------------------------------------*/ 
01750 
01751 void interrupt_routine(void) 
01752  {
01753   
01754 EVENT_HEADER * pevent;
01755   
01756 
01757       /* get pointer for upcoming event.
01758          This is a blocking call if no space available */ 
01759   if ((pevent = dm_pointer_get()) == NULL)
01760     
01761 cm_msg(MERROR, "interrupt_routine",
01762             "interrupt, dm_pointer_get returned NULL");
01763   
01764 
01765       /* compose MIDAS event header */ 
01766   pevent->event_id = interrupt_eq->info.event_id;
01767   
01768 pevent->trigger_mask = interrupt_eq->info.trigger_mask;
01769   
01770 pevent->data_size = 0;
01771   
01772 pevent->time_stamp = actual_time;
01773   
01774 pevent->serial_number = interrupt_eq->serial_number++;
01775   
01776 
01777       /* call user readout routine */ 
01778   pevent->data_size = interrupt_eq->readout((char *) (pevent + 1), 0);
01779   
01780 
01781       /* send event */ 
01782   if (pevent->data_size)
01783     
01784  {
01785     
01786 interrupt_eq->bytes_sent += pevent->data_size + sizeof(EVENT_HEADER);
01787     
01788 interrupt_eq->events_sent++;
01789     
01790 
01791 if (interrupt_eq->buffer_handle)
01792       
01793  {
01794       
01795 #ifdef USE_EVENT_CHANNEL
01796           dm_pointer_increment(interrupt_eq->buffer_handle,
01797                                
01798 pevent->data_size + sizeof(EVENT_HEADER));
01799       
01800 #else                           /* 
01801  */
01802           rpc_send_event(interrupt_eq->buffer_handle, pevent,
01803                          
01804 pevent->data_size + sizeof(EVENT_HEADER), SYNC);
01805       
01806 #endif                          /* 
01807  */
01808       }
01809     
01810 
01811         /* send event to ODB */ 
01812     if (interrupt_eq->info.read_on & RO_ODB || 
01813 interrupt_eq->info.history)
01814       
01815  {
01816       
01817 if (actual_millitime - interrupt_eq->last_called > ODB_UPDATE_TIME)
01818         
01819  {
01820         
01821 interrupt_eq->last_called = actual_millitime;
01822         
01823 memcpy(interrupt_odb_buffer, pevent,
01824                 pevent->data_size + sizeof(EVENT_HEADER));
01825         
01826 interrupt_odb_buffer_valid = TRUE;
01827         
01828 interrupt_eq->odb_out++;
01829         
01830 }
01831       
01832 }
01833     
01834 }
01835   
01836   else
01837     
01838 interrupt_eq->serial_number--;
01839 
01840 
01841 }
01842 
01843 
01844 
01845 /*------------------------------------------------------------------*/ 
01846 
01847 int message_print(const char *msg) 
01848  {
01849   
01850 char str[160];
01851   
01852 
01853 memset(str, ' ', 159);
01854   
01855 str[159] = 0;
01856   
01857 
01858 if (msg[0] == '[')
01859     
01860 msg = strchr(msg, ']') + 2;
01861   
01862 
01863 memcpy(str, msg, strlen(msg));
01864   
01865 ss_printf(0, 20, str);
01866   
01867 
01868 return 0;
01869 
01870 } 
01871 
01872 /*------------------------------------------------------------------*/ 
01873 
01874 void display(BOOL bInit) 
01875  {
01876   
01877 INT i, status;
01878   
01879 time_t full_time;
01880   
01881 char str[30];
01882   
01883 
01884 if (bInit)
01885     
01886  {
01887     
01888 ss_clear_screen();
01889     
01890 
01891 if (host_name[0])
01892       
01893 strcpy(str, host_name);
01894     
01895     else
01896       
01897 strcpy(str, "<local>");
01898     
01899 
01900 ss_printf(0, 0, "%s connected to %s. Press \"!\" to exit",
01901                 frontend_name, str);
01902     
01903 ss_printf(0, 1,
01904                "================================================================================");
01905     
01906 ss_printf(0, 2, "Run status:   %s",
01907                run_state ==
01908                STATE_STOPPED ? "Stopped" : 
01909 run_state ==
01910                STATE_RUNNING ? "Running" : 
01911 "Paused");
01912     
01913 ss_printf(25, 2, "Run number %d   ", run_number);
01914     
01915 ss_printf(0, 3,
01916                "================================================================================");
01917     
01918 ss_printf(0, 4,
01919                "Equipment     Status     Events     Events/sec Rate[kB/s] ODB->FE    FE->ODB");
01920     
01921 ss_printf(0, 5,
01922                "--------------------------------------------------------------------------------");
01923     
01924 for (i = 0; equipment[i].name[0]; i++)
01925       
01926 ss_printf(0, i + 6, "%s", equipment[i].name);
01927     
01928 }
01929   
01930 
01931       /* display time */ 
01932       time(&full_time);
01933   
01934 strcpy(str, ctime(&full_time) + 11);
01935   
01936 str[8] = 0;
01937   
01938 ss_printf(72, 0, "%s", str);
01939   
01940 
01941 for (i = 0; equipment[i].name[0]; i++)
01942     
01943  {
01944     
01945 status = equipment[i].status;
01946     
01947 
01948 if ((status == 0 || status == FE_SUCCESS)
01949           && 
01950 equipment[i].info.enabled)
01951       
01952 ss_printf(14, i + 6, "OK       ");
01953     
01954     else if (!equipment[i].info.enabled)
01955       
01956 ss_printf(14, i + 6, "Disabled ");
01957     
01958     else if (status == FE_ERR_ODB)
01959       
01960 ss_printf(14, i + 6, "ODB Error");
01961     
01962     else if (status == FE_ERR_HW)
01963       
01964 ss_printf(14, i + 6, "HW Error ");
01965     
01966     else if (status == FE_ERR_DISABLED)
01967       
01968 ss_printf(14, i + 6, "Disabled ");
01969     
01970     else
01971       
01972 ss_printf(14, i + 6, "Unknown  ");
01973     
01974 
01975 if (equipment[i].stats.events_sent > 1E9)
01976       
01977 ss_printf(25, i + 6, "%1.3lfG     ",
01978                  equipment[i].stats.events_sent / 1E9);
01979     
01980     else if (equipment[i].stats.events_sent > 1E6)
01981       
01982 ss_printf(25, i + 6, "%1.3lfM     ",
01983                  equipment[i].stats.events_sent / 1E6);
01984     
01985     else
01986       
01987 ss_printf(25, i + 6, "%1.0lf      ",
01988                  equipment[i].stats.events_sent);
01989     
01990 ss_printf(36, i + 6, "%1.1lf      ",
01991                equipment[i].stats.events_per_sec);
01992     
01993 ss_printf(47, i + 6, "%1.1lf      ",
01994                equipment[i].stats.kbytes_per_sec);
01995     
01996 ss_printf(58, i + 6, "%ld       ", equipment[i].odb_in);
01997     
01998 ss_printf(69, i + 6, "%ld       ", equipment[i].odb_out);
01999     
02000 }
02001   
02002 
02003       /* go to next line */ 
02004       ss_printf(0, i + 6, "");
02005 
02006 }
02007 
02008 
02009 
02010 /*------------------------------------------------------------------*/ 
02011     
02012 BOOL logger_root() 
02013 /* check if logger uses ROOT format */ 
02014 {
02015   
02016 int size, i, status;
02017   
02018 char str[80];
02019   
02020 HNDLE hKeyRoot, hKey;
02021   
02022 
02023 if (db_find_key(hDB, 0, "/Logger/Channels", &hKeyRoot) == DB_SUCCESS)
02024     
02025  {
02026     
02027 for (i = 0;; i++)
02028       
02029  {
02030       
02031 status = db_enum_key(hDB, hKeyRoot, i, &hKey);
02032       
02033 if (status == DB_NO_MORE_SUBKEYS)
02034         
02035 break;
02036       
02037 
02038 strcpy(str, "MIDAS");
02039       
02040 size = sizeof(str);
02041       
02042 db_get_value(hDB, hKey, "Settings/Format", str, &size,
02043                     TID_STRING, TRUE);
02044       
02045 
02046 if (equal_ustring(str, "ROOT"))
02047         
02048 return TRUE;
02049       
02050 }
02051     
02052 }
02053   
02054 
02055 return FALSE;
02056 
02057 }
02058 
02059 
02060 
02061 /*------------------------------------------------------------------*/ 
02062     
02063 INT scheduler(void) 
02064  {
02065   
02066 EQUIPMENT_INFO * eq_info;
02067   
02068 EQUIPMENT * eq;
02069   
02070 EVENT_HEADER * pevent;
02071   
02072 DWORD last_time_network = 0, last_time_display =
02073       0, 
02074 last_time_flush = 0, readout_start;
02075   
02076 INT i, j, index, status, ch, source, size, state;
02077   
02078 char str[80];
02079   
02080 BOOL buffer_done, flag, force_update = FALSE;
02081   
02082 
02083 INT opt_max = 0, opt_index = 0, opt_tcp_size = 128, opt_cnt = 0;
02084   
02085 INT err;
02086   
02087 
02088 #ifdef OS_VXWORKS
02089       rpc_set_opt_tcp_size(1024);
02090   
02091 #ifdef PPCxxx
02092       rpc_set_opt_tcp_size(NET_TCP_SIZE);
02093   
02094 #endif                          /* 
02095  */
02096 #endif                          /* 
02097  */
02098       
02099   /*----------------- MAIN equipment loop ------------------------------*/ 
02100       
02101   do
02102     
02103  {
02104     
02105 actual_millitime = ss_millitime();
02106     
02107 actual_time = ss_time();
02108     
02109 
02110     /*---- loop over equipment table -------------------------------*/ 
02111         for (index = 0;; index++)
02112       
02113  {
02114       
02115 eq = &equipment[index];
02116       
02117 eq_info = &eq->info;
02118       
02119 
02120           /* check if end of equipment list */ 
02121           if (!eq->name[0])
02122         
02123 break;
02124       
02125 
02126 if (!eq_info->enabled)
02127         
02128 continue;
02129       
02130 
02131 if (eq->status != FE_SUCCESS)
02132         
02133 continue;
02134       
02135 
02136       /*---- call idle routine for slow control equipment ----*/ 
02137           if ((eq_info->eq_type & EQ_SLOW)
02138               && 
02139 eq->status == FE_SUCCESS)
02140         
02141  {
02142         
02143 if (eq_info->event_limit > 0 && run_state == STATE_RUNNING)
02144           
02145  {
02146           
02147 if (actual_time - eq->last_idle >= (DWORD) eq_info->event_limit)
02148             
02149  {
02150             
02151 eq->cd(CMD_IDLE, eq);
02152             
02153 eq->last_idle = actual_time;
02154             
02155 }
02156           
02157 }
02158         
02159         else
02160           
02161 eq->cd(CMD_IDLE, eq);
02162         
02163 }
02164       
02165 
02166 if (run_state == STATE_STOPPED
02167             && (eq_info->read_on & RO_STOPPED) == 0)
02168         
02169 continue;
02170       
02171 if (run_state == STATE_PAUSED
02172            && (eq_info->read_on & RO_PAUSED) == 0)
02173         
02174 continue;
02175       
02176 if (run_state == STATE_RUNNING
02177            && (eq_info->read_on & RO_RUNNING) == 0)
02178         
02179 continue;
02180       
02181 
02182       /*---- check periodic events ----*/ 
02183           if ((eq_info->eq_type & EQ_PERIODIC)
02184               || (eq_info->eq_type & EQ_SLOW))
02185         
02186  {
02187         
02188 if (eq_info->period == 0)
02189           
02190 continue;
02191         
02192 
02193             /* check if period over */ 
02194             if (actual_millitime - eq->last_called >=
02195                 (DWORD) eq_info->period)
02196           
02197  {
02198           
02199               /* disable interrupts during readout */ 
02200               interrupt_enable(FALSE);
02201           
02202 
02203               /* readout and send event */ 
02204               status = send_event(index);
02205           
02206 
02207 if (status != CM_SUCCESS)
02208             
02209  {
02210             
02211 cm_msg(MERROR, "scheduler", "send_event error %d", status);
02212             
02213 goto net_error;
02214             
02215 }
02216           
02217 
02218               /* re-enable the interrupt after periodic */ 
02219               interrupt_enable(TRUE);
02220           
02221 }
02222         
02223 }                      /* end of periodic equipments */
02224       
02225 
02226       /*---- check polled events ----*/ 
02227           if (eq_info->eq_type & EQ_POLLED)
02228         
02229  {
02230         
02231 readout_start = actual_millitime;
02232         
02233 pevent = NULL;
02234         
02235 
02236 while ((source =
02237                   poll_event(eq_info->source, eq->poll_count, FALSE)) > 0)
02238           
02239  {
02240           
02241 pevent = dm_pointer_get();
02242           
02243 if (pevent == NULL)
02244             
02245  {
02246             
02247 cm_msg(MERROR, "scheduler",
02248                     "polled, dm_pointer_get not returning valid pointer");
02249             
02250 status = SS_NO_MEMORY;
02251             
02252 goto net_error;
02253             
02254 }
02255           
02256 
02257               /* compose MIDAS event header */ 
02258               pevent->event_id = eq_info->event_id;
02259           
02260 pevent->trigger_mask = eq_info->trigger_mask;
02261           
02262 pevent->data_size = 0;
02263           
02264 pevent->time_stamp = actual_time;
02265           
02266 pevent->serial_number = eq->serial_number;
02267           
02268 
02269               /* put source at beginning of event, will be overwritten by 
02270                  user readout code, just a special feature used by some 
02271                  multi-source applications */ 
02272               *(INT *) (pevent + 1) = source;
02273           
02274 
02275 if (eq->info.num_subevents)
02276             
02277  {
02278             
02279 eq->subevent_number = 0;
02280             
02281             do
02282               
02283  {
02284               
02285 *(INT *) ((char *) (pevent + 1)
02286                          + pevent->data_size) = source;
02287               
02288 
02289                   /* call user readout routine for subevent indicating offset */ 
02290                   size =
02291                   eq->readout((char *) (pevent + 1), pevent->data_size);
02292               
02293 pevent->data_size += size;
02294               
02295 if (size > 0)
02296                 
02297  {
02298                 
02299 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD)
02300                      max_event_size)
02301                   
02302  {
02303                   
02304 cm_msg(MERROR,
02305                           "scheduler",
02306                           "Event size %ld larger than maximum size %d",
02307                           
02308 (long)
02309                           (pevent->
02310                            data_size +
02311                            sizeof(EVENT_HEADER)), max_event_size);
02312                   
02313 }
02314                 
02315 
02316 eq->subevent_number++;
02317                 
02318 eq->serial_number++;
02319                 
02320 }
02321               
02322 
02323                   /* wait for next event */ 
02324                   do
02325                 
02326  {
02327                 
02328 source =
02329                     poll_event(eq_info->source, eq->poll_count, FALSE);
02330                 
02331 
02332 if (source == FALSE)
02333                   
02334  {
02335                   
02336 actual_millitime = ss_millitime();
02337                   
02338 
02339                       /* repeat no more than period */ 
02340                       if (actual_millitime - readout_start > (DWORD)
02341                           eq_info->period)
02342                     
02343 break;
02344                   
02345 }
02346               
02347 } while (source == FALSE);
02348             
02349 
02350 } while (eq->subevent_number <
02351                          eq->info.num_subevents && source);
02352             
02353 
02354                 /* notify readout routine about end of super-event */ 
02355                 pevent->data_size = eq->readout((char *) (pevent + 1), -1);
02356             
02357 }
02358           
02359           else
02360             
02361  {
02362             
02363                 /* call user readout routine indicating event source */ 
02364                 pevent->data_size = eq->readout((char *) (pevent + 1), 0);
02365             
02366 
02367                 /* check event size */ 
02368                 if (pevent->data_size +
02369                     sizeof(EVENT_HEADER) > (DWORD) max_event_size)
02370               
02371  {
02372               
02373 cm_msg(MERROR, "scheduler",
02374                       "Event size %ld larger than maximum size %d",
02375                       
02376 (long) (pevent->
02377                                data_size +
02378                                sizeof(EVENT_HEADER)), max_event_size);
02379               
02380 }
02381             
02382 
02383                 /* increment serial number if event read out sucessfully */ 
02384                 if (pevent->data_size)
02385               
02386 eq->serial_number++;
02387             
02388 }
02389           
02390 
02391               /* send event */ 
02392               if (pevent->data_size)
02393             
02394  {
02395             
02396 if (eq->buffer_handle)
02397               
02398  {
02399               
02400                   /* send first event to ODB if logger writes in root format */ 
02401                   if (pevent->serial_number == 1)
02402                 
02403 if (logger_root())
02404                   
02405 update_odb(pevent, eq->hkey_variables, eq->format);
02406               
02407 
02408 #ifdef USE_EVENT_CHANNEL
02409                   dm_pointer_increment(eq->
02410                                        buffer_handle,
02411                                        
02412 pevent->
02413                                        data_size + sizeof(EVENT_HEADER));
02414               
02415 #else                           /* 
02416  */
02417                   status =
02418                   rpc_send_event(eq->
02419                                  buffer_handle,
02420                                  pevent,
02421                                  
02422 pevent->
02423                                  data_size + sizeof(EVENT_HEADER), SYNC);
02424               
02425 
02426 if (status != SUCCESS)
02427                 
02428  {
02429                 
02430 cm_msg(MERROR,
02431                         "scheduler", "rpc_send_event error %d", status);
02432                 
02433 goto net_error;
02434                 
02435 }
02436               
02437 #endif                          /* 
02438  */
02439                   
02440 eq->bytes_sent +=
02441                   pevent->data_size + sizeof(EVENT_HEADER);
02442               
02443 
02444 if (eq->info.num_subevents)
02445                 
02446 eq->events_sent += eq->subevent_number;
02447               
02448               else
02449                 
02450 eq->events_sent++;
02451               
02452 }
02453             
02454 }
02455           
02456 
02457 actual_millitime = ss_millitime();
02458           
02459 
02460               /* repeat no more than period */ 
02461               if (actual_millitime - readout_start >
02462                   (DWORD) eq_info->period)
02463             
02464 break;
02465           
02466 
02467               /* quit if event limit is reached */ 
02468               if (eq_info->event_limit > 0
02469                   && 
02470 eq->stats.events_sent +
02471                   eq->events_sent >= eq_info->event_limit)
02472             
02473 break;
02474           
02475 }
02476         
02477 
02478             /* send event to ODB */ 
02479             if (pevent && (eq_info->read_on & RO_ODB || eq_info->history))
02480           
02481  {
02482           
02483 if (actual_millitime - eq->last_called >
02484                ODB_UPDATE_TIME && pevent != NULL)
02485             
02486  {
02487             
02488 eq->last_called = actual_millitime;
02489             
02490 update_odb(pevent, eq->hkey_variables, eq->format);
02491             
02492 eq->odb_out++;
02493             
02494 }
02495           
02496 }
02497         
02498 }
02499       
02500 
02501       /*---- send interrupt events ----*/ 
02502           if (eq_info->eq_type & EQ_INTERRUPT)
02503         
02504  {
02505         
02506             /* not much to do as work being done independently in interrupt_routine() */ 
02507             
02508             /* update ODB */ 
02509             if (interrupt_odb_buffer_valid)
02510           
02511  {
02512           
02513 update_odb(interrupt_odb_buffer,
02514                       interrupt_eq->hkey_variables, 
02515 interrupt_eq->format);
02516           
02517 interrupt_odb_buffer_valid = FALSE;
02518           
02519 }
02520         
02521 
02522 }
02523       
02524 
02525       /*---- check if event limit is reached ----*/ 
02526           if (eq_info->eq_type != EQ_SLOW
02527               && 
02528 eq_info->event_limit > 0
02529               && 
02530 eq->stats.events_sent + eq->events_sent >=
02531               eq_info->event_limit && 
02532 run_state == STATE_RUNNING)
02533         
02534  {
02535         
02536             /* stop run */ 
02537             if (cm_transition
02538                 (TR_STOP, 0, str, sizeof(str), SYNC, FALSE) != CM_SUCCESS)
02539           
02540 cm_msg(MERROR, "scheduler", "cannot stop run: %s", str);
02541         
02542 
02543             /* check if autorestart, main loop will take care of it */ 
02544             size = sizeof(BOOL);
02545         
02546 flag = FALSE;
02547         
02548 db_get_value(hDB, 0, "/Logger/Auto restart",
02549                       &flag, &size, TID_BOOL, TRUE);
02550         
02551 
02552 if (flag)
02553           
02554 auto_restart = ss_time() + 20;       /* restart in 20 sec. */
02555         
02556 
02557             /* update event display correctly */ 
02558             force_update = TRUE;
02559         
02560 }
02561       
02562 }
02563     
02564 
02565     /*---- call frontend_loop periodically -------------------------*/ 
02566         if (frontend_call_loop)
02567       
02568  {
02569       
02570 status = frontend_loop();
02571       
02572 if (status != CM_SUCCESS)
02573         
02574 status = RPC_SHUTDOWN;
02575       
02576 }
02577     
02578 
02579     /*---- check for deferred transitions --------------------------*/ 
02580         cm_check_deferred_transition();
02581     
02582 
02583     /*---- calculate rates and update status page periodically -----*/ 
02584         if (force_update || 
02585             (display_period
02586              && actual_millitime - last_time_display >
02587              (DWORD) display_period) || 
02588 (!display_period
02589                                           && actual_millitime -
02590                                           last_time_display > 3000))
02591       
02592  {
02593       
02594 force_update = FALSE;
02595       
02596 
02597           /* calculate rates */ 
02598           if (actual_millitime != last_time_display)
02599         
02600  {
02601         
02602 max_bytes_per_sec = 0;
02603         
02604 for (i = 0; equipment[i].name[0]; i++)
02605           
02606  {
02607           
02608 eq = &equipment[i];
02609           
02610 eq->stats.events_sent += eq->events_sent;
02611           
02612 eq->stats.events_per_sec =
02613               
02614 eq->events_sent /
02615               ((actual_millitime - last_time_display) / 1000.0);
02616           
02617 eq->stats.kbytes_per_sec =
02618               
02619 eq->bytes_sent / 1024.0 /
02620               ((actual_millitime - last_time_display) / 1000.0);
02621           
02622 
02623 if ((INT) eq->bytes_sent > max_bytes_per_sec)
02624             
02625 max_bytes_per_sec = eq->bytes_sent;
02626           
02627 
02628 eq->bytes_sent = 0;
02629           
02630 eq->events_sent = 0;
02631           
02632 }
02633         
02634 
02635 max_bytes_per_sec = (DWORD) 
02636             ((double) max_bytes_per_sec /
02637              ((actual_millitime - last_time_display) / 1000.0));
02638         
02639 
02640             /* tcp buffer size evaluation */ 
02641             if (optimize)
02642           
02643  {
02644           
02645 opt_max = max(opt_max, (INT) max_bytes_per_sec);
02646           
02647 ss_printf(0, opt_index,
02648                      "%6d : %5.1lf %5.1lf",
02649                      opt_tcp_size, opt_max / 1024.0,
02650                      
02651 max_bytes_per_sec / 1024.0);
02652           
02653 if (++opt_cnt == 10)
02654             
02655  {
02656             
02657 opt_cnt = 0;
02658             
02659 opt_max = 0;
02660             
02661 opt_index++;
02662             
02663 opt_tcp_size = 1 << (opt_index + 7);
02664             
02665 rpc_set_opt_tcp_size(opt_tcp_size);
02666             
02667 if (1 << (opt_index + 7) > 0x8000)
02668               
02669  {
02670               
02671 opt_index = 0;
02672               
02673 opt_tcp_size = 1 << 7;
02674               
02675 rpc_set_opt_tcp_size(opt_tcp_size);
02676               
02677 }
02678             
02679 }
02680           
02681 }
02682         
02683 
02684 }
02685       
02686 
02687           /* propagate changes in equipment to ODB */ 
02688           rpc_set_option(-1, RPC_OTRANSPORT, RPC_FTCP);
02689       
02690 db_send_changed_records();
02691       
02692 rpc_set_option(-1, RPC_OTRANSPORT, RPC_TCP);
02693       
02694 
02695 if (display_period)
02696         
02697  {
02698         
02699 display(FALSE);
02700         
02701 
02702             /* check keyboard */ 
02703             ch = 0;
02704         
02705 status = 0;
02706         
02707 while (ss_kbhit())
02708           
02709  {
02710           
02711 ch = ss_getchar(0);
02712           
02713 if (ch == -1)
02714             
02715 ch = getchar();
02716           
02717 
02718 if (ch == '!')
02719             
02720 status = RPC_SHUTDOWN;
02721           
02722 }
02723         
02724 
02725 if (ch > 0)
02726           
02727 display(TRUE);
02728         
02729 if (status == RPC_SHUTDOWN)
02730           
02731 break;
02732         
02733 }
02734       
02735 
02736 last_time_display = actual_millitime;
02737       
02738 }
02739     
02740 
02741     /*---- check to flush cache ------------------------------------*/ 
02742         if (actual_millitime - last_time_flush > 1000)
02743       
02744  {
02745       
02746 last_time_flush = actual_millitime;
02747       
02748 
02749           /* if cache on server is not filled in one second at current
02750              data rate, flush it now to make events available to consumers */ 
02751           
02752 if (max_bytes_per_sec < SERVER_CACHE_SIZE)
02753         
02754  {
02755         
02756 interrupt_enable(FALSE);
02757         
02758 
02759 #ifdef USE_EVENT_CHANNEL
02760             if ((status = dm_area_flush()) != CM_SUCCESS)
02761           
02762 cm_msg(MERROR, "scheduler", "dm_area_flush: %i", status);
02763         
02764 #endif                          /* 
02765  */
02766             
02767 for (i = 0; equipment[i].name[0]; i++)
02768           
02769  {
02770           
02771 if (equipment[i].buffer_handle)
02772             
02773  {
02774             
02775                 /* check if buffer already flushed */ 
02776                 buffer_done = FALSE;
02777             
02778 for (j = 0; j < i; j++)
02779               
02780 if (equipment[i].
02781                    buffer_handle == equipment[j].buffer_handle)
02782                 
02783  {
02784                 
02785 buffer_done = TRUE;
02786                 
02787 break;
02788                 
02789 }
02790             
02791 
02792 if (!buffer_done)
02793               
02794  {
02795               
02796 rpc_set_option(-1, RPC_OTRANSPORT, RPC_FTCP);
02797               
02798 rpc_flush_event();
02799               
02800 err = bm_flush_cache(equipment[i].buffer_handle, ASYNC);
02801               
02802 if (err != BM_SUCCESS)
02803                 
02804  {
02805                 
02806 cm_msg(MERROR,
02807                         "scheduler",
02808                         "bm_flush_cache(ASYNC) error %d", err);
02809                 
02810 return err;
02811                 
02812 }
02813               
02814 rpc_set_option(-1, RPC_OTRANSPORT, RPC_TCP);
02815               
02816 }
02817             
02818 }
02819           
02820 }
02821         
02822 interrupt_enable(TRUE);
02823         
02824 }
02825       
02826 }
02827     
02828 
02829       /*---- check for auto restart --------------------------------*/ 
02830         if (auto_restart > 0 && ss_time() > auto_restart)
02831       
02832  {
02833       
02834           /* check if really stopped */ 
02835           size = sizeof(state);
02836       
02837 status =
02838           db_get_value(hDB, 0, "Runinfo/State", &state, &size,
02839                        TID_INT, TRUE);
02840       
02841 if (status != DB_SUCCESS)
02842         
02843 cm_msg(MERROR, "scheduler",
02844                 "cannot get Runinfo/State in database");
02845       
02846 
02847 if (state == STATE_STOPPED)
02848         
02849  {
02850         
02851 auto_restart = 0;
02852         
02853 size = sizeof(run_number);
02854         
02855 status =
02856             db_get_value(hDB, 0, "/Runinfo/Run number",
02857                          &run_number, &size, TID_INT, TRUE);
02858         
02859 assert(status == SUCCESS);
02860         
02861 
02862 if (run_number <= 0)
02863           
02864  {
02865           
02866 cm_msg(MERROR, "main",
02867                   "aborting on attempt to use invalid run number %d",
02868                   run_number);
02869           
02870 abort();
02871           
02872 }
02873         
02874 
02875 cm_msg(MTALK, "main", "starting new run");
02876         
02877 status =
02878             cm_transition(TR_START, run_number + 1, NULL, 0, SYNC, FALSE);
02879         
02880 if (status != CM_SUCCESS)
02881           
02882 cm_msg(MERROR, "main", "cannot restart run");
02883         
02884 }
02885       
02886 }
02887     
02888 
02889     /*---- check network messages ----------------------------------*/ 
02890         if (run_state == STATE_RUNNING && interrupt_eq == NULL)
02891       
02892  {
02893       
02894           /* only call yield once every 500ms when running */ 
02895           if (actual_millitime - last_time_network > 500)
02896         
02897  {
02898         
02899 status = cm_yield(0);
02900         
02901 last_time_network = actual_millitime;
02902         
02903 }
02904       
02905       else
02906         
02907 status = RPC_SUCCESS;
02908       
02909 }
02910     
02911     else
02912       
02913           /* when run is stopped or interrupts used, 
02914              call yield with 100ms timeout */ 
02915           status = cm_yield(100);
02916     
02917 
02918         /* exit for VxWorks */ 
02919         if (fe_stop)
02920       
02921 status = RPC_SHUTDOWN;
02922   
02923 
02924 } while (status != RPC_SHUTDOWN && status != SS_ABORT);
02925 
02926 
02927 net_error:
02928 
02929 return status;
02930 
02931 }
02932 
02933 
02934 
02935 /*------------------------------------------------------------------*/ 
02936     
02937 #ifdef HAVE_CAMAC
02938     
02939 INT cnaf_callback(INT index, void *prpc_param[]) 
02940  {
02941   
02942 DWORD cmd, b, c, n, a, f, *pdword, *size, *x, *q, dtemp;
02943   
02944 WORD * pword, *pdata, temp;
02945   
02946 INT i, count;
02947   
02948 
02949       /* Decode parameters */ 
02950       cmd = CDWORD(0);
02951   
02952 b = CDWORD(1);
02953   
02954 c = CDWORD(2);
02955   
02956 n = CDWORD(3);
02957   
02958 a = CDWORD(4);
02959   
02960 f = CDWORD(5);
02961   
02962 pdword = CPDWORD(6);
02963   
02964 pword = CPWORD(6);
02965   
02966 pdata = CPWORD(6);
02967   
02968 size = CPDWORD(7);
02969   
02970 x = CPDWORD(8);
02971   
02972 q = CPDWORD(9);
02973   
02974 
02975       /* determine repeat count */ 
02976       if (index == RPC_CNAF16)
02977     
02978 count = *size / sizeof(WORD);      /* 16 bit */
02979   
02980   else
02981     
02982 count = *size / sizeof(DWORD);     /* 24 bit */
02983   
02984 
02985 switch (cmd)
02986     
02987  {
02988     
02989     /*---- special commands ----*/ 
02990   
02991 case CNAF_INHIBIT_SET:
02992     
02993 cam_inhibit_set(c);
02994     
02995 break;
02996   
02997 case CNAF_INHIBIT_CLEAR:
02998     
02999 cam_inhibit_clear(c);
03000     
03001 break;
03002   
03003 case CNAF_CRATE_CLEAR:
03004     
03005 cam_crate_clear(c);
03006     
03007 break;
03008   
03009 case CNAF_CRATE_ZINIT:
03010     
03011 cam_crate_zinit(c);
03012     
03013 break;
03014   
03015 
03016 case CNAF_TEST:
03017     
03018 break;
03019   
03020 
03021 case CNAF:
03022     
03023 if (index == RPC_CNAF16)
03024       
03025  {
03026       
03027 for (i = 0; i < count; i++)
03028         
03029 if (f < 16)
03030           
03031 cam16i_q(c, n, a, f, pword++, (int *) x, (int *) q);
03032       
03033         else if (f < 24)
03034           
03035 cam16o_q(c, n, a, f, pword[i], (int *) x, (int *) q);
03036       
03037         else
03038           
03039 cam16i_q(c, n, a, f, &temp, (int *) x, (int *) q);
03040       
03041 }
03042     
03043     else
03044       
03045  {
03046       
03047 for (i = 0; i < count; i++)
03048         
03049 if (f < 16)
03050           
03051 cam24i_q(c, n, a, f, pdword++, (int *) x, (int *) q);
03052       
03053         else if (f < 24)
03054           
03055 cam24o_q(c, n, a, f, pdword[i], (int *) x, (int *) q);
03056       
03057         else
03058           
03059 cam24i_q(c, n, a, f, &dtemp, (int *) x, (int *) q);
03060       
03061 } 
03062 
03063 break;
03064   
03065 
03066 case CNAF_nQ:
03067     
03068 if (index == RPC_CNAF16)
03069       
03070  {
03071       
03072 if (f < 16)
03073         
03074 cam16i_rq(c, n, a, f, (WORD **) & pdword, count);
03075       
03076 }
03077     
03078     else
03079       
03080  {
03081       
03082 if (f < 16)
03083         
03084 cam24i_rq(c, n, a, f, &pdword, count);
03085       
03086 }
03087     
03088 
03089         /* return reduced return size */ 
03090         *size = (int) pdword - (int) pdata;
03091     
03092 break;
03093   
03094 
03095 default:
03096     
03097 printf("cnaf: Unknown command 0x%X\n", (unsigned int) cmd);
03098   
03099 } 
03100 
03101 if (debug)
03102     
03103  {
03104     
03105 if (index == RPC_CNAF16)
03106       
03107 printf
03108           ("cmd=%d r=%d c=%d n=%d a=%d f=%d d=%X x=%d q=%d\n",
03109            
03110 (int) cmd, (int) count, (int) c, (int) n, (int) a,
03111            (int) f, (int) pword[0], (int) *x, (int) *q);
03112     
03113     else if (index == RPC_CNAF24)
03114       
03115 printf
03116           ("cmd=%d r=%d c=%d n=%d a=%d f=%d d=%X x=%d q=%d\n",
03117            
03118 (int) cmd, (int) count, (int) c, (int) n, (int) a,
03119            (int) f, (int) pdword[0], (int) *x, (int) *q);
03120     
03121 }
03122   
03123 
03124 return RPC_SUCCESS;
03125 
03126 }
03127 
03128 
03129 
03130 #endif  /* HAVE_CAMAC */
03131     
03132 /*------------------------------------------------------------------*/ 
03133     
03134 #ifdef OS_VXWORKS
03135 int mfe(char *ahost_name, char *aexp_name, BOOL adebug) 
03136 #else                           /* 
03137  */
03138 int main(int argc, char *argv[]) 
03139 #endif                          /* 
03140  */
03141 {
03142   
03143 INT status, i, dm_size;
03144   
03145 INT daemon;
03146   
03147 
03148 host_name[0] = 0;
03149   
03150 exp_name[0] = 0;
03151   
03152 debug = FALSE;
03153   
03154 daemon = 0;
03155   
03156 
03157 setbuf(stdout, 0);
03158   
03159 setbuf(stderr, 0);
03160   
03161 
03162 #ifdef SIGPIPE
03163   signal(SIGPIPE, SIG_IGN);
03164   
03165 #endif                          /* 
03166  */
03167       
03168 #ifdef OS_VXWORKS
03169   if (ahost_name)
03170     
03171 strcpy(host_name, ahost_name);
03172   
03173 if (aexp_name)
03174     
03175 strcpy(exp_name, aexp_name);
03176   
03177 debug = adebug;
03178   
03179 #else                           /* 
03180  */
03181       
03182       /* get default from environment */ 
03183   cm_get_environment(host_name, sizeof(host_name), exp_name,
03184                      sizeof(exp_name));
03185   
03186 
03187       /* parse command line parameters */ 
03188   for (i = 1; i < argc; i++)
03189     
03190  {
03191     
03192 if (argv[i][0] == '-' && argv[i][1] == 'd')
03193       
03194 debug = TRUE;
03195     
03196     else if (argv[i][0] == '-' && argv[i][1] == 'D')
03197       
03198 daemon = 1;
03199     
03200     else if (argv[i][0] == '-' && argv[i][1] == 'O')
03201       
03202 daemon = 2;
03203     
03204     else if (argv[i][0] == '-')
03205       
03206  {
03207       
03208 if (i + 1 >= argc || argv[i + 1][0] == '-')
03209         
03210 goto usage;
03211       
03212 if (argv[i][1] == 'e')
03213         
03214 strcpy(exp_name, argv[++i]);
03215       
03216       else if (argv[i][1] == 'h')
03217         
03218 strcpy(host_name, argv[++i]);
03219       
03220       else
03221         
03222  {
03223       
03224 usage:
03225 printf
03226             ("usage: frontend [-h Hostname] [-e Experiment] [-d] [-D] [-O]\n");
03227         
03228 printf("         [-d]     Used to debug the frontend\n");
03229         
03230 printf("         [-D]     Become a daemon\n");
03231         
03232 printf("         [-O]     Become a daemon but keep stdout\n");
03233         
03234 return 0;
03235       
03236 } 
03237 }
03238     
03239 } 
03240 #endif                          /* 
03241  */
03242       
03243       /* check event and buffer sizes */ 
03244   if (event_buffer_size < 2 * max_event_size)
03245     
03246  {
03247     
03248 printf("event_buffer_size too small for max. event size\n");
03249     
03250 ss_sleep(5000);
03251     
03252 return 1;
03253     
03254 }
03255   
03256 
03257 if (max_event_size > MAX_EVENT_SIZE)
03258     
03259  {
03260     
03261 printf
03262         ("Requested max_event_size (%d) exceeds max. system event size (%d)",
03263          
03264 max_event_size, MAX_EVENT_SIZE);
03265     
03266 ss_sleep(5000);
03267     
03268 return 1;
03269     
03270 }
03271   
03272 
03273 dm_size = event_buffer_size;
03274   
03275 
03276 #ifdef OS_VXWORKS
03277       /* override dm_size in case of VxWorks
03278          take remaining free memory and use 20% of it for dm_ */ 
03279       dm_size =
03280       2 * 10 * (max_event_size + sizeof(EVENT_HEADER) + sizeof(INT));
03281   
03282 if (dm_size > memFindMax())
03283     
03284  {
03285     
03286 cm_msg(MERROR, "mainFE", "Not enough mem space for event size");
03287     
03288 return 0;
03289     
03290 }
03291   
03292       /* takes overall 20% of the available memory resource for dm_() */ 
03293       dm_size = 0.2 * memFindMax();
03294   
03295 
03296       /* there are two buffers */ 
03297       dm_size /= 2;
03298   
03299 #endif                          /* 
03300  */
03301       
03302       /* reduce memory size for MS-DOS */ 
03303 #ifdef OS_MSDOS
03304       if (dm_size > 0x4000)
03305     
03306 dm_size = 0x4000;          /* 16k */
03307   
03308 #endif                          /* 
03309  */
03310       
03311       /* inform user of settings */ 
03312       printf("Event buffer size      :     %d\n", event_buffer_size);
03313   
03314 printf("Buffer allocation      : 2 x %d\n", dm_size);
03315   
03316 printf("System max event size  :     %d\n", MAX_EVENT_SIZE);
03317   
03318 printf("User max event size    :     %d\n", max_event_size);
03319   
03320 if (max_event_size_frag > 0)
03321     
03322 printf("User max frag. size    :     %d\n", max_event_size_frag);
03323   
03324 printf("# of events per buffer :     %d\n\n", dm_size / max_event_size);
03325   
03326 
03327 if (daemon)
03328     
03329  {
03330     
03331 printf("\nBecoming a daemon...\n");
03332     
03333 ss_daemon_init(daemon == 2);
03334     
03335 }
03336   
03337 
03338       /* now connect to server */ 
03339       if (display_period)
03340     
03341  {
03342     
03343 if (host_name[0])
03344       
03345 printf("Connect to experiment %s on host %s...",
03346               exp_name, host_name);
03347     
03348     else
03349       
03350 printf("Connect to experiment %s...", exp_name);
03351     
03352 }
03353   
03354 
03355 status =
03356       cm_connect_experiment1(host_name, exp_name, frontend_name, 
03357 NULL,
03358                              DEFAULT_ODB_SIZE, DEFAULT_FE_TIMEOUT);
03359   
03360 if (status != CM_SUCCESS)
03361     
03362  {
03363     
03364         /* let user read message before window might close */ 
03365         ss_sleep(5000);
03366     
03367 return 1;
03368     
03369 }
03370   
03371 
03372 if (display_period)
03373     
03374 printf("OK\n");
03375   
03376 
03377       /* book buffer space */ 
03378       status = dm_buffer_create(dm_size, max_event_size);
03379   
03380 if (status != CM_SUCCESS)
03381     
03382  {
03383     
03384 printf("dm_buffer_create: Not enough memory or event too big\n");
03385     
03386 return 1;
03387     
03388 }
03389   
03390 
03391       /* remomve any dead frontend */ 
03392       cm_cleanup(frontend_name, FALSE);
03393   
03394 
03395       /* shutdown previous frontend */ 
03396       status = cm_shutdown(frontend_name, FALSE);
03397   
03398 if (status == CM_SUCCESS && display_period)
03399     
03400  {
03401     
03402 printf("Previous frontend stopped\n");
03403     
03404 
03405         /* let user read message */ 
03406         ss_sleep(3000);
03407     
03408 }
03409   
03410 
03411       /* register transition callbacks */ 
03412       if (cm_register_transition(TR_START, tr_start) != CM_SUCCESS
03413           || 
03414 cm_register_transition(TR_PRESTOP,
03415                                      tr_prestop) != CM_SUCCESS
03416           || 
03417 cm_register_transition(TR_PREPAUSE,
03418                                      tr_prepause) != CM_SUCCESS
03419           || 
03420 cm_register_transition(TR_RESUME, tr_resume) != CM_SUCCESS)
03421     
03422  {
03423     
03424 printf("Failed to start local RPC server");
03425     
03426 cm_disconnect_experiment();
03427     
03428 dm_buffer_release();
03429     
03430 
03431         /* let user read message before window might close */ 
03432         ss_sleep(5000);
03433     
03434 return 1;
03435     
03436 }
03437   
03438 
03439 #ifdef HAVE_CAMAC
03440       
03441       /* register CNAF callback */ 
03442       cm_register_function(RPC_CNAF16, cnaf_callback);
03443   
03444 cm_register_function(RPC_CNAF24, cnaf_callback);
03445   
03446 
03447 #endif                          /* 
03448  */
03449       
03450 cm_get_experiment_database(&hDB, &status);
03451   
03452 
03453       /* set time from server */ 
03454 #ifdef OS_VXWORKS
03455       cm_synchronize(NULL);
03456   
03457 #endif                          /* 
03458  */
03459       
03460       /* turn off watchdog if in debug mode */ 
03461       if (debug)
03462     
03463 cm_set_watchdog_params(TRUE, 0);
03464   
03465 
03466       /* increase RPC timeout to 2min for logger with exabyte or blocked disk */ 
03467       rpc_set_option(-1, RPC_OTIMEOUT, 120000);
03468   
03469 
03470       /* set own message print function */ 
03471       if (display_period)
03472     
03473 cm_set_msg_print(MT_ALL, MT_ALL, message_print);
03474   
03475 
03476       /* call user init function */ 
03477       if (display_period)
03478     
03479 printf("Init hardware...");
03480   
03481 if (frontend_init() != SUCCESS)
03482     
03483  {
03484     
03485 if (display_period)
03486       
03487 printf("\n");
03488     
03489 cm_disconnect_experiment();
03490     
03491 dm_buffer_release();
03492     
03493 
03494         /* let user read message before window might close */ 
03495         ss_sleep(5000);
03496     
03497 return 1;
03498     
03499 }
03500   
03501 
03502       /* reqister equipment in ODB */ 
03503       if (register_equipment() != SUCCESS)
03504     
03505  {
03506     
03507 if (display_period)
03508       
03509 printf("\n");
03510     
03511 cm_disconnect_experiment();
03512     
03513 dm_buffer_release();
03514     
03515 
03516         /* let user read message before window might close */ 
03517         ss_sleep(5000);
03518     
03519 return 1;
03520     
03521 }
03522   
03523 
03524 if (display_period)
03525     
03526 printf("OK\n");
03527   
03528 
03529       /* initialize screen display */ 
03530       if (display_period)
03531     
03532  {
03533     
03534 ss_sleep(1000);
03535     
03536 display(TRUE);
03537     
03538 }
03539   
03540 
03541       /* switch on interrupts if running */ 
03542       if (interrupt_eq && run_state == STATE_RUNNING)
03543     
03544 interrupt_enable(TRUE);
03545   
03546 
03547       /* initialize ss_getchar */ 
03548       ss_getchar(0);
03549   
03550 
03551       /* call main scheduler loop */ 
03552       status = scheduler();
03553   
03554 
03555       /* reset terminal */ 
03556       ss_getchar(TRUE);
03557   
03558 
03559       /* switch off interrupts */ 
03560       if (interrupt_eq)
03561     
03562  {
03563     
03564 interrupt_configure(CMD_INTERRUPT_DISABLE, 0, 0);
03565     
03566 interrupt_configure(CMD_INTERRUPT_DETACH, 0, 0);
03567     
03568 if (interrupt_odb_buffer)
03569       
03570 free(interrupt_odb_buffer);
03571     
03572 }
03573   
03574 
03575       /* detach interrupts */ 
03576       if (interrupt_eq != NULL)
03577     
03578 interrupt_configure(CMD_INTERRUPT_DETACH,
03579                          interrupt_eq->info.source, 0);
03580   
03581 
03582       /* call user exit function */ 
03583       frontend_exit();
03584   
03585 
03586       /* close slow control drivers */ 
03587       for (i = 0; equipment[i].name[0]; i++)
03588     
03589 if ((equipment[i].info.eq_type & EQ_SLOW)
03590          && 
03591 equipment[i].status == FE_SUCCESS)
03592       
03593 equipment[i].cd(CMD_EXIT, &equipment[i]);
03594   
03595 
03596       /* close network connection to server */ 
03597       cm_disconnect_experiment();
03598   
03599 
03600 if (display_period)
03601     
03602  {
03603     
03604 if (status == RPC_SHUTDOWN)
03605       
03606  {
03607       
03608 ss_clear_screen();
03609       
03610 ss_printf(0, 0, "Frontend shut down.");
03611       
03612 ss_printf(0, 1, "");
03613       
03614 }
03615     
03616 }
03617   
03618 
03619 if (status != RPC_SHUTDOWN)
03620     
03621 printf("Network connection aborted.\n");
03622   
03623 
03624 dm_buffer_release();
03625   
03626 
03627 return 0;
03628 
03629 }
03630 
03631 

Midas DOC Version 1.9.3 ---- PSI Stefan Ritt ----
Contributions: Pierre-Andre Amaudruz - Suzannah Daviel - Doxygen - Peter Green - Greg Hackman - Gertjan Hofman - Paul Knowles - Rudi Meier - Glenn Moloney - Dave Morris - Konstantin Olchanski - Renee Poutissou - Andreas Suter - Piotr Adam Zolnierczuk