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.64  2004/03/26 09:31:56  midas
00011   Converted pritnf() to cm_msg() for statistics record error
00012 
00013   Revision 1.63  2004/03/19 09:31:43  midas
00014   Re-formatted comments
00015 
00016   Revision 1.62  2004/01/08 08:40:10  midas
00017   Implemented standard indentation
00018 
00019   Revision 1.61  2003/11/24 08:22:46  midas
00020   Changed timeouts from INT to DWORD, added ignore_timeout to cm_cleanup, adde '-f' flag to ODBEdit 'cleanup'
00021 
00022   Revision 1.60  2003/11/20 11:29:44  midas
00023   Implemented db_check_record and use it in most places instead of db_create_record
00024 
00025   Revision 1.59  2003/11/01 00:48:14  olchansk
00026   abort if cannot read /runinfo/run number
00027   abort if run number resets to zero
00028 
00029   Revision 1.58  2003/10/29 15:33:48  midas
00030   Properly display message about stopped previous frontend
00031 
00032   Revision 1.57  2003/09/30 19:47:57  midas
00033   Removed tabs
00034 
00035   Revision 1.56  2003/09/30 18:30:07  midas
00036   Put CNAF functionality under #ifdef HAVE_CAMAC
00037 
00038   Revision 1.55  2003/05/09 07:40:04  midas
00039   Added extra parameter to cm_get_environment
00040 
00041   Revision 1.54  2003/05/07 10:57:10  midas
00042   Removed tabs
00043 
00044   Revision 1.53  2003/04/25 10:41:42  midas
00045   Removed FTCP mode in update_odb()
00046 
00047   Revision 1.52  2003/04/25 07:45:03  midas
00048   Write first event to ODB only if logger uses ROOT format
00049 
00050   Revision 1.51  2003/04/14 12:40:23  midas
00051   Create ODB entries for structured banks derived from BANK_LIST in frontend.c
00052 
00053   Revision 1.50  2003/04/14 05:12:54  pierre
00054   fix send_event for handle=0
00055 
00056   Revision 1.49  2003/04/01 19:22:44  pierre
00057   fix update_odb for hKeyl copy
00058 
00059   Revision 1.48  2003/03/31 08:27:34  midas
00060   Fixed alignment bug for strings
00061 
00062   Revision 1.47  2003/03/28 09:13:05  midas
00063   Added warning for uncreated structured banks
00064 
00065   Revision 1.46  2003/03/28 08:55:11  midas
00066   Added code for structured banks
00067 
00068   Revision 1.45  2002/10/15 18:44:23  olchansk
00069   fix printf() and cm_msg() format mismatches
00070 
00071   Revision 1.44  2002/10/15 18:15:25  olchansk
00072   disable dtsout, stderr buffering,
00073   catch-ignore SIGPIPE
00074 
00075   Revision 1.43  2002/10/15 18:13:59  olchansk
00076   always recreate the statistics record.
00077 
00078   Revision 1.42  2002/10/15 18:09:59  olchansk
00079   catch bm_xxx() errors and bail out from schedule(). This fixes infinite looping after rpc timeouts.
00080 
00081   Revision 1.41  2002/09/13 07:32:47  midas
00082   Added client name to cm_cleanup()
00083 
00084   Revision 1.40  2002/06/03 06:07:15  midas
00085   Added extra parameter to ss_daemon_init to keep stdout
00086 
00087   Revision 1.39  2002/05/15 23:43:56  midas
00088   Added event fragmentation
00089 
00090   Revision 1.38  2002/05/10 01:41:19  midas
00091   Added optional debug output to cm_transition
00092 
00093   Revision 1.37  2002/05/08 19:54:40  midas
00094   Added extra parameter to function db_get_value()
00095 
00096   Revision 1.36  2001/11/21 08:37:32  midas
00097   Took out db_delete_key for statistics again (not needed)
00098 
00099   Revision 1.35  2001/11/20 19:22:07  pierre
00100   - Add rpc_flush_event in case no periodic eqp
00101   - Force rpc_flush_event for low trigger rate
00102   - Patch /Statistics in case it exists but size=0
00103 
00104   Revision 1.34  2001/06/27 12:34:49  midas
00105   Added -D flag to become a daemon
00106 
00107   Revision 1.33  2001/04/06 04:13:40  midas
00108   Put cm_cleanup() in init code
00109 
00110   Revision 1.32  2001/01/29 09:50:53  midas
00111   Changed send_event() parameter from event_id to equipment index
00112 
00113   Revision 1.31  2000/11/14 08:30:03  midas
00114   SLOW events are not any more sent to the ODB when the history is on
00115 
00116   Revision 1.30  2000/11/06 10:10:23  midas
00117   Flush events for set-ups with only non-periodic events
00118 
00119   Revision 1.29  2000/10/23 14:19:06  midas
00120   Added idle period for slow control equipment
00121 
00122   Revision 1.28  2000/09/28 13:16:02  midas
00123   Fixed bug that MANUAL_TRIG only events are not read out during transitions
00124 
00125   Revision 1.27  2000/09/28 13:02:03  midas
00126   Added manual triggered events
00127 
00128   Revision 1.26  2000/08/21 11:01:11  midas
00129   Changed comments
00130 
00131   Revision 1.25  2000/08/21 10:44:58  midas
00132   Removed reconnect functionality, it's better to restart the frontend via
00133   /programs/frontend/auto restart.
00134 
00135   Revision 1.24  2000/08/21 10:36:41  midas
00136   Reworked event and event buffer sizes:
00137   - Both max_event_size and event_buffer_size must be defined in user code
00138   - While max_event_size is used for frontend buffers, MAX_EVENT_SIZE is the
00139     system limit which must be larger than max_event_size
00140   - Event size returned from user readout routine is now checked against event
00141     size limits
00142   - Buffer settings are now always displayed, not only under VxWorks
00143 
00144   Revision 1.23  2000/08/09 12:02:43  midas
00145   Evaluate return status in tr_xxx functions properly
00146 
00147   Revision 1.22  2000/08/09 11:37:56  midas
00148   Rearranged serial number increments
00149 
00150   Revision 1.21  2000/07/11 16:43:40  pierre
00151   - Fix serial number for POLL super event.
00152 
00153   Revision 1.20  2000/04/03 12:27:43  midas
00154   Changed auto restart to 20 seconds in main loop
00155 
00156   Revision 1.19  2000/03/22 14:42:48  midas
00157   Fixed bug with invalid pointer
00158 
00159   Revision 1.18  2000/03/17 13:00:05  midas
00160   Frontends use default timeout fo 60 sec.
00161 
00162   Revision 1.17  2000/03/01 23:29:20  midas
00163   Fixed bug with wrong event header data size in super eventsvents mfe.c
00164 
00165   Revision 1.16  2000/02/29 21:59:45  midas
00166   Added auto restart
00167 
00168   Revision 1.15  2000/02/26 01:25:54  midas
00169   Fixed bug that number of sent events was not cleared at start
00170 
00171   Revision 1.14  2000/02/25 20:22:49  midas
00172   Added super-event scheme
00173 
00174   Revision 1.13  2000/02/24 22:38:19  midas
00175   Outcommented USE_EVENT_CHANNEL
00176 
00177   Revision 1.12  2000/02/24 22:29:24  midas
00178   Added deferred transitions
00179 
00180   Revision 1.11  1999/12/08 00:50:29  pierre
00181   - fix EVID (ybos: strncpy to strncmp)
00182 
00183   Revision 1.10  1999/11/24 00:49:59  pierre
00184   - YBOS reject EVID bank in udpate_odb with eb_functions
00185 
00186   Revision 1.9  1999/11/23 18:25:25  pierre
00187   - YBOS reject EVID bank in udpate_odb
00188 
00189   Revision 1.8  1999/10/18 14:41:51  midas
00190   Use /programs/<name>/Watchdog timeout in all programs as timeout value. The
00191   default value can be submitted by calling cm_connect_experiment1(..., timeout)
00192 
00193   Revision 1.7  1999/10/15 12:17:52  midas
00194   Increased timeout
00195 
00196   Revision 1.6  1999/09/27 13:49:04  midas
00197   Added bUnique parameter to cm_shutdown
00198 
00199   Revision 1.5  1999/09/23 12:45:48  midas
00200   Added 32 bit banks
00201 
00202   Revision 1.4  1999/06/23 09:38:51  midas
00203   - Added D8_BKTYPE
00204   - Fixed CAMAC server F24 bug
00205   - cm_synchronize only called for VxWorks
00206 
00207   Revision 1.3  1998/12/10 12:50:47  midas
00208   Program abort with "!" now works without a return under UNIX
00209 
00210   Revision 1.2  1998/10/12 12:19:01  midas
00211   Added Log tag in header
00212 
00213 
00214 \********************************************************************/
00215 
00216 #include <stdio.h>
00217 #include <assert.h>
00218 #include "midas.h"
00219 #include "msystem.h"
00220 #include "mcstd.h"
00221 
00222 #ifdef YBOS_SUPPORT
00223 #include "ybos.h"
00224 #endif
00225 
00226 /*------------------------------------------------------------------*/
00227 
00228 /* items defined in frontend.c */
00229 
00230 extern char *frontend_name;
00231 extern char *frontend_file_name;
00232 extern BOOL frontend_call_loop;
00233 extern INT max_event_size;
00234 extern INT max_event_size_frag;
00235 extern INT event_buffer_size;
00236 extern INT display_period;
00237 extern INT frontend_init(void);
00238 extern INT frontend_exit(void);
00239 extern INT frontend_loop(void);
00240 extern INT begin_of_run(INT run_number, char *error);
00241 extern INT end_of_run(INT run_number, char *error);
00242 extern INT pause_run(INT run_number, char *error);
00243 extern INT resume_run(INT run_number, char *error);
00244 extern INT poll_event(INT source, INT count, BOOL test);
00245 extern INT interrupt_configure(INT cmd, INT source, PTYPE adr);
00246 
00247 /*------------------------------------------------------------------*/
00248 
00249 /* globals */
00250 
00251 #undef USE_EVENT_CHANNEL
00252 
00253 #define SERVER_CACHE_SIZE  100000       /* event cache before buffer */
00254 
00255 #define ODB_UPDATE_TIME      1000       /* 1 seconds for ODB update */
00256 
00257 #define DEFAULT_FE_TIMEOUT  60000       /* 60 seconds for watchdog timeout */
00258 
00259 INT run_state;                  /* STATE_RUNNING, STATE_STOPPED, STATE_PAUSED */
00260 INT run_number;
00261 DWORD actual_time;              /* current time in seconds since 1970 */
00262 DWORD actual_millitime;         /* current time in milliseconds */
00263 
00264 char host_name[HOST_NAME_LENGTH];
00265 char exp_name[NAME_LENGTH];
00266 
00267 INT max_bytes_per_sec;
00268 INT optimize = 0;               /* set this to one to opimize TCP buffer size */
00269 INT fe_stop = 0;                /* stop switch for VxWorks */
00270 BOOL debug;                     /* disable watchdog messages from server */
00271 DWORD auto_restart = 0;         /* restart run after event limit reached stop */
00272 
00273 HNDLE hDB;
00274 
00275 #ifdef YBOS_SUPPORT
00276 struct {
00277    DWORD ybos_type;
00278    DWORD odb_type;
00279    INT tsize;
00280 } id_map[] = {
00281    {
00282    A1_BKTYPE, TID_CHAR, 1}, {
00283    I1_BKTYPE, TID_BYTE, 1}, {
00284    I2_BKTYPE, TID_WORD, 2}, {
00285    I4_BKTYPE, TID_DWORD, 4}, {
00286    F4_BKTYPE, TID_FLOAT, 4}, {
00287    D8_BKTYPE, TID_DOUBLE, 8}, {
00288    0, 0}
00289 };
00290 #endif
00291 
00292 extern EQUIPMENT equipment[];
00293 
00294 EQUIPMENT *interrupt_eq = NULL;
00295 EVENT_HEADER *interrupt_odb_buffer;
00296 BOOL interrupt_odb_buffer_valid;
00297 
00298 int send_event(INT index);
00299 void send_all_periodic_events(INT transition);
00300 void interrupt_routine(void);
00301 void interrupt_enable(BOOL flag);
00302 void display(BOOL bInit);
00303 
00304 /*---- ODB records -------------------------------------------------*/
00305 
00306 #define EQUIPMENT_COMMON_STR "\
00307 Event ID = WORD : 0\n\
00308 Trigger mask = WORD : 0\n\
00309 Buffer = STRING : [32] SYSTEM\n\
00310 Type = INT : 0\n\
00311 Source = INT : 0\n\
00312 Format = STRING : [8] FIXED\n\
00313 Enabled = BOOL : 0\n\
00314 Read on = INT : 0\n\
00315 Period = INT : 0\n\
00316 Event limit = DOUBLE : 0\n\
00317 Num subevents = DWORD : 0\n\
00318 Log history = INT : 0\n\
00319 Frontend host = STRING : [32] \n\
00320 Frontend name = STRING : [32] \n\
00321 Frontend file name = STRING : [256] \n\
00322 "
00323 
00324 #define EQUIPMENT_STATISTICS_STR "\
00325 Events sent = DOUBLE : 0\n\
00326 Events per sec. = DOUBLE : 0\n\
00327 kBytes per sec. = DOUBLE : 0\n\
00328 "
00329 
00330 /*-- transition callbacks ------------------------------------------*/
00331 
00332 /*-- start ---------------------------------------------------------*/
00333 
00334 INT tr_start(INT rn, char *error)
00335 {
00336    INT i, status;
00337 
00338    /* reset serial numbers */
00339    for (i = 0; equipment[i].name[0]; i++) {
00340       equipment[i].serial_number = 1;
00341       equipment[i].subevent_number = 0;
00342       equipment[i].stats.events_sent = 0;
00343       equipment[i].odb_in = equipment[i].odb_out = 0;
00344    }
00345 
00346    status = begin_of_run(rn, error);
00347 
00348    if (status == CM_SUCCESS) {
00349       run_state = STATE_RUNNING;
00350       run_number = rn;
00351 
00352       send_all_periodic_events(TR_START);
00353 
00354       if (display_period) {
00355          ss_printf(14, 2, "Running ");
00356          ss_printf(36, 2, "%d", rn);
00357       }
00358 
00359       /* enable interrupts */
00360       interrupt_enable(TRUE);
00361    }
00362 
00363    return status;
00364 }
00365 
00366 /*-- prestop -------------------------------------------------------*/
00367 
00368 INT tr_prestop(INT rn, char *error)
00369 {
00370    INT status, i;
00371 
00372    /* disable interrupts */
00373    interrupt_enable(FALSE);
00374 
00375    status = end_of_run(rn, error);
00376 
00377    if (status == CM_SUCCESS) {
00378       /* don't send events if already stopped */
00379       if (run_state != STATE_STOPPED)
00380          send_all_periodic_events(TR_STOP);
00381 
00382       run_state = STATE_STOPPED;
00383       run_number = rn;
00384 
00385       if (display_period)
00386          ss_printf(14, 2, "Stopped ");
00387    } else
00388       interrupt_enable(TRUE);
00389 
00390    /* flush remaining buffered events */
00391    rpc_flush_event();
00392    for (i = 0; equipment[i].name[0]; i++)
00393       if (equipment[i].buffer_handle) {
00394          INT err = bm_flush_cache(equipment[i].buffer_handle, SYNC);
00395          if (err != BM_SUCCESS) {
00396             cm_msg(MERROR, "tr_prestop", "bm_flush_cache(SYNC) error %d", err);
00397             return err;
00398          }
00399       }
00400 
00401    return status;
00402 }
00403 
00404 /*-- pause ---------------------------------------------------------*/
00405 
00406 INT tr_prepause(INT rn, char *error)
00407 {
00408    INT status;
00409 
00410    /* disable interrupts */
00411    interrupt_enable(FALSE);
00412 
00413    status = pause_run(rn, error);
00414 
00415    if (status == CM_SUCCESS) {
00416       run_state = STATE_PAUSED;
00417       run_number = rn;
00418 
00419       send_all_periodic_events(TR_PAUSE);
00420 
00421       if (display_period)
00422          ss_printf(14, 2, "Paused  ");
00423    } else
00424       interrupt_enable(TRUE);
00425 
00426    return status;
00427 }
00428 
00429 /*-- resume --------------------------------------------------------*/
00430 
00431 INT tr_resume(INT rn, char *error)
00432 {
00433    INT status;
00434 
00435    status = resume_run(rn, error);
00436 
00437    if (status == CM_SUCCESS) {
00438       run_state = STATE_RUNNING;
00439       run_number = rn;
00440 
00441       send_all_periodic_events(TR_RESUME);
00442 
00443       if (display_period)
00444          ss_printf(14, 2, "Running ");
00445 
00446       /* enable interrupts */
00447       interrupt_enable(TRUE);
00448    }
00449 
00450    return status;
00451 }
00452 
00453 /*------------------------------------------------------------------*/
00454 
00455 INT manual_trigger(INT index, void *prpc_param[])
00456 {
00457    WORD event_id, i;
00458 
00459    event_id = CWORD(0);
00460 
00461    for (i = 0; equipment[i].name[0]; i++)
00462       if (equipment[i].info.event_id == event_id)
00463          send_event(i);
00464 
00465    if (display_period)
00466       display(FALSE);
00467 
00468    return SUCCESS;
00469 }
00470 
00471 /*------------------------------------------------------------------*/
00472 
00473 INT register_equipment(void)
00474 {
00475    INT index, count, size, status, i, j, k, n;
00476    char str[256];
00477    EQUIPMENT_INFO *eq_info;
00478    EQUIPMENT_STATS *eq_stats;
00479    DWORD start_time, delta_time;
00480    HNDLE hKey;
00481    BOOL manual_trig_flag = FALSE;
00482    BANK_LIST *bank_list;
00483    DWORD dummy;
00484 
00485    /* get current ODB run state */
00486    size = sizeof(run_state);
00487    run_state = STATE_STOPPED;
00488    db_get_value(hDB, 0, "/Runinfo/State", &run_state, &size, TID_INT, TRUE);
00489    size = sizeof(run_number);
00490    run_number = 1;
00491    status =
00492        db_get_value(hDB, 0, "/Runinfo/Run number", &run_number, &size, TID_INT, TRUE);
00493    assert(status == SUCCESS);
00494 
00495    /* scan EQUIPMENT table from FRONTEND.C */
00496    for (index = 0; equipment[index].name[0]; index++) {
00497       eq_info = &equipment[index].info;
00498       eq_stats = &equipment[index].stats;
00499 
00500       if (eq_info->event_id == 0) {
00501          printf("Event ID 0 for %s not allowed\n", equipment[index].name);
00502          ss_sleep(5000);
00503       }
00504 
00505       /* init status */
00506       equipment[index].status = FE_SUCCESS;
00507 
00508       sprintf(str, "/Equipment/%s/Common", equipment[index].name);
00509 
00510       /* get last event limit from ODB */
00511       if (eq_info->eq_type != EQ_SLOW) {
00512          db_find_key(hDB, 0, str, &hKey);
00513          size = sizeof(double);
00514          if (hKey)
00515             db_get_value(hDB, hKey, "Event limit", &eq_info->event_limit, &size,
00516                          TID_DOUBLE, TRUE);
00517       }
00518 
00519       /* Create common subtree */
00520       status = db_check_record(hDB, 0, str, EQUIPMENT_COMMON_STR, TRUE);
00521       if (status != DB_SUCCESS) {
00522          printf("Cannot check equipment record, status = %d\n", status);
00523          ss_sleep(3000);
00524       }
00525       db_find_key(hDB, 0, str, &hKey);
00526 
00527       if (equal_ustring(eq_info->format, "YBOS"))
00528          equipment[index].format = FORMAT_YBOS;
00529       else if (equal_ustring(eq_info->format, "FIXED"))
00530          equipment[index].format = FORMAT_FIXED;
00531       else                      /* default format is MIDAS */
00532          equipment[index].format = FORMAT_MIDAS;
00533 
00534       gethostname(eq_info->frontend_host, sizeof(eq_info->frontend_host));
00535       strcpy(eq_info->frontend_name, frontend_name);
00536       strcpy(eq_info->frontend_file_name, frontend_file_name);
00537 
00538       /* set record from equipment[] table in frontend.c */
00539       db_set_record(hDB, hKey, eq_info, sizeof(EQUIPMENT_INFO), 0);
00540 
00541       /* open hot link to equipment info */
00542       db_open_record(hDB, hKey, eq_info, sizeof(EQUIPMENT_INFO), MODE_READ, NULL, NULL);
00543 
00544     /*---- Create variables record ---------------------------------*/
00545       sprintf(str, "/Equipment/%s/Variables", equipment[index].name);
00546       if (equipment[index].event_descrip) {
00547          if (equipment[index].format == FORMAT_FIXED)
00548             db_check_record(hDB, 0, str, (char *) equipment[index].event_descrip, TRUE);
00549          else {
00550             /* create bank descriptions */
00551             bank_list = (BANK_LIST *) equipment[index].event_descrip;
00552 
00553             for (; bank_list->name[0]; bank_list++) {
00554                /* mabye needed later...
00555                   if (bank_list->output_flag == 0)
00556                   continue;
00557                 */
00558 
00559                if (bank_list->type == TID_STRUCT) {
00560                   sprintf(str, "/Equipment/%s/Variables/%s", equipment[index].name,
00561                           bank_list->name);
00562                   status =
00563                       db_check_record(hDB, 0, str, strcomb(bank_list->init_str), TRUE);
00564                   if (status != DB_SUCCESS) {
00565                      printf("Cannot check/create record \"%s\", status = %d\n", str,
00566                             status);
00567                      ss_sleep(3000);
00568                   }
00569                } else {
00570                   sprintf(str, "/Equipment/%s/Variables/%s", equipment[index].name,
00571                           bank_list->name);
00572                   dummy = 0;
00573                   db_set_value(hDB, 0, str, &dummy, rpc_tid_size(bank_list->type), 1,
00574                                bank_list->type);
00575                }
00576             }
00577          }
00578       } else
00579          db_create_key(hDB, 0, str, TID_KEY);
00580 
00581       sprintf(str, "/Equipment/%s/Variables", equipment[index].name);
00582       db_find_key(hDB, 0, str, &hKey);
00583       equipment[index].hkey_variables = hKey;
00584 
00585     /*---- Create and initialize statistics tree -------------------*/
00586       sprintf(str, "/Equipment/%s/Statistics", equipment[index].name);
00587 
00588       status = db_check_record(hDB, 0, str, EQUIPMENT_STATISTICS_STR, TRUE);
00589       if (status != DB_SUCCESS) {
00590          printf("Cannot create/check statistics record, error %d\n", status);
00591          ss_sleep(3000);
00592       }
00593 
00594       status = db_find_key(hDB, 0, str, &hKey);
00595       if (status != DB_SUCCESS) {
00596          printf("Cannot find statistics record, error %d\n", status);
00597          ss_sleep(3000);
00598       }
00599 
00600       eq_stats->events_sent = 0;
00601       eq_stats->events_per_sec = 0;
00602       eq_stats->kbytes_per_sec = 0;
00603 
00604       /* open hot link to statistics tree */
00605       status =
00606           db_open_record(hDB, hKey, eq_stats, sizeof(EQUIPMENT_STATS), MODE_WRITE, NULL,
00607                          NULL);
00608       if (status != DB_SUCCESS) {
00609          cm_msg(MERROR, "register_equipment", 
00610              "Cannot open statistics record, error %d. Probably other FE is using it",
00611               status);
00612          ss_sleep(3000);
00613       }
00614 
00615     /*---- open event buffer ---------------------------------------*/
00616       if (eq_info->buffer[0]) {
00617          status =
00618              bm_open_buffer(eq_info->buffer, EVENT_BUFFER_SIZE,
00619                             &equipment[index].buffer_handle);
00620          if (status != BM_SUCCESS && status != BM_CREATED) {
00621             cm_msg(MERROR, "register_equipment",
00622                    "Cannot open event buffer. Try to reduce EVENT_BUFFER_SIZE in midas.h \
00623 and rebuild the system.");
00624             return 0;
00625          }
00626 
00627          /* set the default buffer cache size */
00628          bm_set_cache_size(equipment[index].buffer_handle, 0, SERVER_CACHE_SIZE);
00629       } else
00630          equipment[index].buffer_handle = 0;
00631 
00632     /*---- evaluate polling count ----------------------------------*/
00633       if (eq_info->eq_type & EQ_POLLED) {
00634          if (display_period)
00635             printf("\nCalibrating");
00636 
00637          count = 1;
00638          do {
00639             if (display_period)
00640                printf(".");
00641 
00642             start_time = ss_millitime();
00643 
00644             poll_event(equipment[index].info.source, count, TRUE);
00645 
00646             delta_time = ss_millitime() - start_time;
00647 
00648             if (delta_time > 0)
00649                count = (INT) ((double) count * 100 / delta_time);
00650             else
00651                count *= 100;
00652          } while (delta_time > 120 || delta_time < 80);
00653 
00654          equipment[index].poll_count = (INT) ((double) eq_info->period / 100 * count);
00655 
00656          if (display_period)
00657             printf("OK\n");
00658       }
00659 
00660     /*---- initialize interrupt events -----------------------------*/
00661       if (eq_info->eq_type & EQ_INTERRUPT) {
00662          /* install interrupt for interrupt events */
00663 
00664          for (i = 0; equipment[i].name[0]; i++)
00665             if (equipment[i].info.eq_type & EQ_POLLED) {
00666                equipment[index].status = FE_ERR_DISABLED;
00667                cm_msg(MINFO, "register_equipment",
00668                       "Interrupt readout cannot be combined with polled readout");
00669             }
00670 
00671          if (equipment[index].status != FE_ERR_DISABLED) {
00672             if (eq_info->enabled) {
00673                if (interrupt_eq) {
00674                   equipment[index].status = FE_ERR_DISABLED;
00675                   cm_msg(MINFO, "register_equipment",
00676                          "Defined more than one equipment with interrupt readout");
00677                } else {
00678                   interrupt_configure(CMD_INTERRUPT_ATTACH, eq_info->source,
00679                                       (PTYPE) interrupt_routine);
00680                   interrupt_eq = &equipment[index];
00681                   interrupt_odb_buffer = malloc(MAX_EVENT_SIZE + sizeof(EVENT_HEADER));
00682                }
00683             } else {
00684                equipment[index].status = FE_ERR_DISABLED;
00685                cm_msg(MINFO, "register_equipment",
00686                       "Equipment %s disabled in file \"frontend.c\"",
00687                       equipment[index].name);
00688             }
00689          }
00690       }
00691 
00692     /*---- initialize slow control equipment -----------------------*/
00693       if (eq_info->eq_type & EQ_SLOW) {
00694          /* resolve duplicate device names */
00695          for (i = 0; equipment[index].driver[i].name[0]; i++)
00696             for (j = i + 1; equipment[index].driver[j].name[0]; j++)
00697                if (equal_ustring(equipment[index].driver[i].name,
00698                                  equipment[index].driver[j].name)) {
00699                   strcpy(str, equipment[index].driver[i].name);
00700                   for (k = 0, n = 0; equipment[index].driver[k].name[0]; k++)
00701                      if (equal_ustring(str, equipment[index].driver[k].name))
00702                         sprintf(equipment[index].driver[k].name, "%s_%d", str, n++);
00703 
00704                   break;
00705                }
00706 
00707          /* loop over equipment list and call class driver's init method */
00708          if (eq_info->enabled)
00709             equipment[index].status = equipment[index].cd(CMD_INIT, &equipment[index]);
00710          else {
00711             equipment[index].status = FE_ERR_DISABLED;
00712             cm_msg(MINFO, "register_equipment",
00713                    "Equipment %s disabled in file \"frontend.c\"", equipment[index].name);
00714          }
00715 
00716          /* let user read error messages */
00717          if (equipment[index].status != FE_SUCCESS)
00718             ss_sleep(3000);
00719       }
00720 
00721     /*---- register callback for manual triggered events -----------*/
00722       if (eq_info->eq_type & EQ_MANUAL_TRIG) {
00723          if (!manual_trig_flag)
00724             cm_register_function(RPC_MANUAL_TRIG, manual_trigger);
00725 
00726          manual_trig_flag = TRUE;
00727       }
00728    }
00729 
00730    return SUCCESS;
00731 }
00732 
00733 /*------------------------------------------------------------------*/
00734 
00735 void update_odb(EVENT_HEADER * pevent, HNDLE hKey, INT format)
00736 {
00737    INT size, i, ni4, tsize, status, n_data;
00738    void *pdata;
00739    char name[5];
00740    BANK_HEADER *pbh;
00741    BANK *pbk;
00742    BANK32 *pbk32;
00743    void *pydata;
00744    DWORD odb_type;
00745    DWORD *pyevt, bkname;
00746    WORD bktype;
00747    HNDLE hKeyRoot, hKeyl;
00748    KEY key;
00749 
00750    /* outcommented sind db_find_key does not work in FTCP mode, SR 25.4.03
00751       rpc_set_option(-1, RPC_OTRANSPORT, RPC_FTCP); */
00752 
00753    if (format == FORMAT_FIXED) {
00754       if (db_set_record(hDB, hKey, (char *) (pevent + 1),
00755                         pevent->data_size, 0) != DB_SUCCESS)
00756          cm_msg(MERROR, "update_odb", "event #%d size mismatch", pevent->event_id);
00757    } else if (format == FORMAT_MIDAS) {
00758       pbh = (BANK_HEADER *) (pevent + 1);
00759       pbk = NULL;
00760       pbk32 = NULL;
00761       do {
00762          /* scan all banks */
00763          if (bk_is32(pbh)) {
00764             size = bk_iterate32(pbh, &pbk32, &pdata);
00765             if (pbk32 == NULL)
00766                break;
00767             bkname = *((DWORD *) pbk32->name);
00768             bktype = (WORD) pbk32->type;
00769          } else {
00770             size = bk_iterate(pbh, &pbk, &pdata);
00771             if (pbk == NULL)
00772                break;
00773             bkname = *((DWORD *) pbk->name);
00774             bktype = (WORD) pbk->type;
00775          }
00776 
00777          n_data = size;
00778          if (rpc_tid_size(bktype & 0xFF))
00779             n_data /= rpc_tid_size(bktype & 0xFF);
00780 
00781          /* get bank key */
00782          *((DWORD *) name) = bkname;
00783          name[4] = 0;
00784 
00785          if (bktype == TID_STRUCT) {
00786             status = db_find_key(hDB, hKey, name, &hKeyRoot);
00787             if (status != DB_SUCCESS) {
00788                cm_msg(MERROR, "update_odb",
00789                       "please define bank %s in BANK_LIST in frontend.c", name);
00790                continue;
00791             }
00792 
00793             /* write structured bank */
00794             for (i = 0;; i++) {
00795                status = db_enum_key(hDB, hKeyRoot, i, &hKeyl);
00796                if (status == DB_NO_MORE_SUBKEYS)
00797                   break;
00798 
00799                db_get_key(hDB, hKeyl, &key);
00800 
00801                /* adjust for alignment */
00802                if (key.type != TID_STRING && key.type != TID_LINK)
00803                   pdata =
00804                       (void *) VALIGN(pdata, min(ss_get_struct_align(), key.item_size));
00805 
00806                status = db_set_data(hDB, hKeyl, pdata, key.item_size * key.num_values,
00807                                     key.num_values, key.type);
00808                if (status != DB_SUCCESS) {
00809                   cm_msg(MERROR, "update_odb", "cannot write %s to ODB", name);
00810                   continue;
00811                }
00812 
00813                /* shift data pointer to next item */
00814                (char *) pdata += key.item_size * key.num_values;
00815             }
00816          } else {
00817             /* write variable length bank  */
00818             if (n_data > 0)
00819                db_set_value(hDB, hKey, name, pdata, size, n_data, bktype & 0xFF);
00820          }
00821 
00822       } while (1);
00823    } else if (format == FORMAT_YBOS) {
00824 #ifdef YBOS_SUPPORT
00825       YBOS_BANK_HEADER *pybkh;
00826 
00827       /* skip the lrl (4 bytes per event) */
00828       pyevt = (DWORD *) (pevent + 1);
00829       pybkh = NULL;
00830       do {
00831          /* scan all banks */
00832          ni4 = ybk_iterate(pyevt, &pybkh, &pydata);
00833          if (pybkh == NULL || ni4 == 0)
00834             break;
00835 
00836          /* find the corresponding odb type */
00837          tsize = odb_type = 0;
00838          for (i = 0; id_map[0].ybos_type > 0; i++) {
00839             if (pybkh->type == id_map[i].ybos_type) {
00840                odb_type = id_map[i].odb_type;
00841                tsize = id_map[i].tsize;
00842                break;
00843             }
00844          }
00845 
00846          /* extract bank name (key name) */
00847          *((DWORD *) name) = pybkh->name;
00848          name[4] = 0;
00849 
00850          /* reject EVID bank */
00851          if (strncmp(name, "EVID", 4) == 0)
00852             continue;
00853 
00854          /* correct YBS number of entries */
00855          if (pybkh->type == D8_BKTYPE)
00856             ni4 /= 2;
00857          if (pybkh->type == I2_BKTYPE)
00858             ni4 *= 2;
00859          if (pybkh->type == I1_BKTYPE || pybkh->type == A1_BKTYPE)
00860             ni4 *= 4;
00861 
00862          /* write bank to ODB, ni4 always in I*4 */
00863          size = ni4 * tsize;
00864          if ((status =
00865               db_set_value(hDB, hKey, name, pydata, size, ni4,
00866                            odb_type & 0xFF)) != DB_SUCCESS) {
00867             printf("status:%i odb_type:%li name:%s ni4:%i size:%i tsize:%i\n", status,
00868                    odb_type, name, ni4, size, tsize);
00869             for (i = 0; i < 6; i++)
00870                printf("data: %f\n", *((float *) (pydata))++);
00871          }
00872       } while (1);
00873 #endif                          /* YBOS_SUPPORT */
00874    }
00875 
00876    rpc_set_option(-1, RPC_OTRANSPORT, RPC_TCP);
00877 }
00878 
00879 /*------------------------------------------------------------------*/
00880 
00881 int send_event(INT index)
00882 {
00883    EQUIPMENT_INFO *eq_info;
00884    EVENT_HEADER *pevent, *pfragment;
00885    char *pdata;
00886    unsigned char *pd;
00887    INT i, status;
00888    DWORD sent, size;
00889    static void *frag_buffer = NULL;
00890 
00891    eq_info = &equipment[index].info;
00892 
00893    /* check for fragmented event */
00894    if (eq_info->eq_type & EQ_FRAGMENTED) {
00895       if (frag_buffer == NULL)
00896          frag_buffer = malloc(max_event_size_frag);
00897 
00898       if (frag_buffer == NULL) {
00899          cm_msg(MERROR, "send_event",
00900                 "Not enough memory to allocate buffer for fragmented events");
00901          return SS_NO_MEMORY;
00902       }
00903 
00904       pevent = frag_buffer;
00905    } else {
00906       /* return value should be valid pointer. if NULL BIG error ==> abort  */
00907       pevent = dm_pointer_get();
00908       if (pevent == NULL) {
00909          cm_msg(MERROR, "send_event", "dm_pointer_get not returning valid pointer");
00910          return SS_NO_MEMORY;
00911       }
00912    }
00913 
00914    /* compose MIDAS event header */
00915    pevent->event_id = eq_info->event_id;
00916    pevent->trigger_mask = eq_info->trigger_mask;
00917    pevent->data_size = 0;
00918    pevent->time_stamp = ss_time();
00919    pevent->serial_number = equipment[index].serial_number++;
00920 
00921    equipment[index].last_called = ss_millitime();
00922 
00923    /* call user readout routine */
00924    *((EQUIPMENT **) (pevent + 1)) = &equipment[index];
00925    pevent->data_size = equipment[index].readout((char *) (pevent + 1), 0);
00926 
00927    /* send event */
00928    if (pevent->data_size) {
00929       if (eq_info->eq_type & EQ_FRAGMENTED) {
00930          /* fragment event */
00931          if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size_frag) {
00932             cm_msg(MERROR, "send_event",
00933                    "Event size %ld larger than maximum size %d for frag. ev.",
00934                    (long) (pevent->data_size + sizeof(EVENT_HEADER)),
00935                    max_event_size_frag);
00936             return SS_NO_MEMORY;
00937          }
00938 
00939          /* compose fragments */
00940          pfragment = dm_pointer_get();
00941          if (pfragment == NULL) {
00942             cm_msg(MERROR, "send_event", "dm_pointer_get not returning valid pointer");
00943             return SS_NO_MEMORY;
00944          }
00945 
00946          /* compose MIDAS event header */
00947          memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
00948          pfragment->event_id |= EVENTID_FRAG1;
00949 
00950          /* store total event size */
00951          pd = (char *) (pfragment + 1);
00952          size = pevent->data_size;
00953          for (i = 0; i < 4; i++) {
00954             pd[i] = (unsigned char) (size & 0xFF);      /* little endian, please! */
00955             size >>= 8;
00956          }
00957 
00958          pfragment->data_size = sizeof(DWORD);
00959 
00960          pdata = (char *) (pevent + 1);
00961 
00962          for (i = 0, sent = 0; sent < pevent->data_size; i++) {
00963             if (i > 0) {
00964                pfragment = dm_pointer_get();
00965 
00966                /* compose MIDAS event header */
00967                memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
00968                pfragment->event_id |= EVENTID_FRAG;
00969 
00970                /* copy portion of event */
00971                size = pevent->data_size - sent;
00972                if (size > max_event_size - sizeof(EVENT_HEADER))
00973                   size = max_event_size - sizeof(EVENT_HEADER);
00974 
00975                memcpy(pfragment + 1, pdata, size);
00976                pfragment->data_size = size;
00977                sent += size;
00978                pdata += size;
00979             }
00980 
00981             /* send event to buffer */
00982             if (equipment[index].buffer_handle) {
00983 #ifdef USE_EVENT_CHANNEL
00984                dm_pointer_increment(equipment[index].buffer_handle,
00985                                     pfragment->data_size + sizeof(EVENT_HEADER));
00986 #else
00987                rpc_flush_event();
00988                status = bm_send_event(equipment[index].buffer_handle, pfragment,
00989                                       pfragment->data_size + sizeof(EVENT_HEADER), SYNC);
00990                if (status != BM_SUCCESS) {
00991                   cm_msg(MERROR, "send_event", "bm_send_event(SYNC) error %d", status);
00992                   return status;
00993                }
00994 #endif
00995             }
00996          }
00997 
00998          if (equipment[index].buffer_handle) {
00999 #ifndef USE_EVENT_CHANNEL
01000             status = bm_flush_cache(equipment[index].buffer_handle, SYNC);
01001             if (status != BM_SUCCESS) {
01002                cm_msg(MERROR, "send_event", "bm_flush_cache(SYNC) error %d", status);
01003                return status;
01004             }
01005 #endif
01006          }
01007       } else {
01008          /* send unfragmented event */
01009 
01010          if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
01011             cm_msg(MERROR, "send_event", "Event size %ld larger than maximum size %d",
01012                    (long) (pevent->data_size + sizeof(EVENT_HEADER)), max_event_size);
01013             return SS_NO_MEMORY;
01014          }
01015 
01016          /* send event to buffer */
01017          if (equipment[index].buffer_handle) {
01018 #ifdef USE_EVENT_CHANNEL
01019             dm_pointer_increment(equipment[index].buffer_handle,
01020                                  pevent->data_size + sizeof(EVENT_HEADER));
01021 #else
01022             rpc_flush_event();
01023             status = bm_send_event(equipment[index].buffer_handle, pevent,
01024                                    pevent->data_size + sizeof(EVENT_HEADER), SYNC);
01025             if (status != BM_SUCCESS) {
01026                cm_msg(MERROR, "send_event", "bm_send_event(SYNC) error %d", status);
01027                return status;
01028             }
01029             status = bm_flush_cache(equipment[index].buffer_handle, SYNC);
01030             if (status != BM_SUCCESS) {
01031                cm_msg(MERROR, "send_event", "bm_flush_cache(SYNC) error %d", status);
01032                return status;
01033             }
01034 #endif
01035          }
01036 
01037          /* send event to ODB if RO_ODB flag is set or history is on. Do not
01038             send SLOW events since the class driver does that */
01039          if ((eq_info->read_on & RO_ODB) ||
01040              (eq_info->history > 0 && (eq_info->eq_type & ~EQ_SLOW))) {
01041             update_odb(pevent, equipment[index].hkey_variables, equipment[index].format);
01042             equipment[index].odb_out++;
01043          }
01044       }
01045 
01046       equipment[index].bytes_sent += pevent->data_size + sizeof(EVENT_HEADER);
01047       equipment[index].events_sent++;
01048 
01049       equipment[index].stats.events_sent += equipment[index].events_sent;
01050       equipment[index].events_sent = 0;
01051    } else
01052       equipment[index].serial_number--;
01053 
01054    /* emtpy event buffer */
01055 #ifdef USE_EVENT_CHANNEL
01056    if ((status = dm_area_flush()) != CM_SUCCESS)
01057       cm_msg(MERROR, "send_event", "dm_area_flush: %i", status);
01058 #endif
01059 
01060    for (i = 0; equipment[i].name[0]; i++)
01061       if (equipment[i].buffer_handle) {
01062          status = bm_flush_cache(equipment[i].buffer_handle, SYNC);
01063          if (status != BM_SUCCESS) {
01064             cm_msg(MERROR, "send_event", "bm_flush_cache(SYNC) error %d", status);
01065             return status;
01066          }
01067       }
01068 
01069    return CM_SUCCESS;
01070 }
01071 
01072 /*------------------------------------------------------------------*/
01073 
01074 void send_all_periodic_events(INT transition)
01075 {
01076    EQUIPMENT_INFO *eq_info;
01077    INT i;
01078 
01079    for (i = 0; equipment[i].name[0]; i++) {
01080       eq_info = &equipment[i].info;
01081 
01082       if (!eq_info->enabled || equipment[i].status != FE_SUCCESS)
01083          continue;
01084 
01085       if (transition == TR_START && (eq_info->read_on & RO_BOR) == 0)
01086          continue;
01087       if (transition == TR_STOP && (eq_info->read_on & RO_EOR) == 0)
01088          continue;
01089       if (transition == TR_PAUSE && (eq_info->read_on & RO_PAUSE) == 0)
01090          continue;
01091       if (transition == TR_RESUME && (eq_info->read_on & RO_RESUME) == 0)
01092          continue;
01093 
01094       send_event(i);
01095    }
01096 }
01097 
01098 /*------------------------------------------------------------------*/
01099 
01100 BOOL interrupt_enabled;
01101 
01102 void interrupt_enable(BOOL flag)
01103 {
01104    interrupt_enabled = flag;
01105 
01106    if (interrupt_eq) {
01107       if (interrupt_enabled)
01108          interrupt_configure(CMD_INTERRUPT_ENABLE, 0, 0);
01109       else
01110          interrupt_configure(CMD_INTERRUPT_DISABLE, 0, 0);
01111    }
01112 }
01113 
01114 /*------------------------------------------------------------------*/
01115 
01116 void interrupt_routine(void)
01117 {
01118    EVENT_HEADER *pevent;
01119 
01120    /* get pointer for upcoming event.
01121       This is a blocking call if no space available */
01122    if ((pevent = dm_pointer_get()) == NULL)
01123       cm_msg(MERROR, "interrupt_routine", "interrupt, dm_pointer_get returned NULL");
01124 
01125    /* compose MIDAS event header */
01126    pevent->event_id = interrupt_eq->info.event_id;
01127    pevent->trigger_mask = interrupt_eq->info.trigger_mask;
01128    pevent->data_size = 0;
01129    pevent->time_stamp = actual_time;
01130    pevent->serial_number = interrupt_eq->serial_number++;
01131 
01132    /* call user readout routine */
01133    pevent->data_size = interrupt_eq->readout((char *) (pevent + 1), 0);
01134 
01135    /* send event */
01136    if (pevent->data_size) {
01137       interrupt_eq->bytes_sent += pevent->data_size + sizeof(EVENT_HEADER);
01138       interrupt_eq->events_sent++;
01139 
01140       if (interrupt_eq->buffer_handle) {
01141 #ifdef USE_EVENT_CHANNEL
01142          dm_pointer_increment(interrupt_eq->buffer_handle,
01143                               pevent->data_size + sizeof(EVENT_HEADER));
01144 #else
01145          rpc_send_event(interrupt_eq->buffer_handle, pevent,
01146                         pevent->data_size + sizeof(EVENT_HEADER), SYNC);
01147 #endif
01148       }
01149 
01150       /* send event to ODB */
01151       if (interrupt_eq->info.read_on & RO_ODB || interrupt_eq->info.history) {
01152          if (actual_millitime - interrupt_eq->last_called > ODB_UPDATE_TIME) {
01153             interrupt_eq->last_called = actual_millitime;
01154             memcpy(interrupt_odb_buffer, pevent,
01155                    pevent->data_size + sizeof(EVENT_HEADER));
01156             interrupt_odb_buffer_valid = TRUE;
01157             interrupt_eq->odb_out++;
01158          }
01159       }
01160    } else
01161       interrupt_eq->serial_number--;
01162 
01163 }
01164 
01165 /*------------------------------------------------------------------*/
01166 
01167 int message_print(const char *msg)
01168 {
01169    char str[160];
01170 
01171    memset(str, ' ', 159);
01172    str[159] = 0;
01173 
01174    if (msg[0] == '[')
01175       msg = strchr(msg, ']') + 2;
01176 
01177    memcpy(str, msg, strlen(msg));
01178    ss_printf(0, 20, str);
01179 
01180    return 0;
01181 }
01182 
01183 /*------------------------------------------------------------------*/
01184 
01185 void display(BOOL bInit)
01186 {
01187    INT i, status;
01188    time_t full_time;
01189    char str[30];
01190 
01191    if (bInit) {
01192       ss_clear_screen();
01193 
01194       if (host_name[0])
01195          strcpy(str, host_name);
01196       else
01197          strcpy(str, "<local>");
01198 
01199       ss_printf(0, 0, "%s connected to %s. Press \"!\" to exit", frontend_name, str);
01200       ss_printf(0, 1,
01201                 "================================================================================");
01202       ss_printf(0, 2, "Run status:   %s",
01203                 run_state == STATE_STOPPED ? "Stopped" : run_state ==
01204                 STATE_RUNNING ? "Running" : "Paused");
01205       ss_printf(25, 2, "Run number %d   ", run_number);
01206       ss_printf(0, 3,
01207                 "================================================================================");
01208       ss_printf(0, 4,
01209                 "Equipment     Status     Events     Events/sec Rate[kB/s] ODB->FE    FE->ODB");
01210       ss_printf(0, 5,
01211                 "--------------------------------------------------------------------------------");
01212       for (i = 0; equipment[i].name[0]; i++)
01213          ss_printf(0, i + 6, "%s", equipment[i].name);
01214    }
01215 
01216    /* display time */
01217    time(&full_time);
01218    strcpy(str, ctime(&full_time) + 11);
01219    str[8] = 0;
01220    ss_printf(72, 0, "%s", str);
01221 
01222    for (i = 0; equipment[i].name[0]; i++) {
01223       status = equipment[i].status;
01224 
01225       if ((status == 0 || status == FE_SUCCESS) && equipment[i].info.enabled)
01226          ss_printf(14, i + 6, "OK       ");
01227       else if (!equipment[i].info.enabled)
01228          ss_printf(14, i + 6, "Disabled ");
01229       else if (status == FE_ERR_ODB)
01230          ss_printf(14, i + 6, "ODB Error");
01231       else if (status == FE_ERR_HW)
01232          ss_printf(14, i + 6, "HW Error ");
01233       else if (status == FE_ERR_DISABLED)
01234          ss_printf(14, i + 6, "Disabled ");
01235       else
01236          ss_printf(14, i + 6, "Unknown  ");
01237 
01238       if (equipment[i].stats.events_sent > 1E9)
01239          ss_printf(25, i + 6, "%1.3lfG     ", equipment[i].stats.events_sent / 1E9);
01240       else if (equipment[i].stats.events_sent > 1E6)
01241          ss_printf(25, i + 6, "%1.3lfM     ", equipment[i].stats.events_sent / 1E6);
01242       else
01243          ss_printf(25, i + 6, "%1.0lf      ", equipment[i].stats.events_sent);
01244       ss_printf(36, i + 6, "%1.1lf      ", equipment[i].stats.events_per_sec);
01245       ss_printf(47, i + 6, "%1.1lf      ", equipment[i].stats.kbytes_per_sec);
01246       ss_printf(58, i + 6, "%ld       ", equipment[i].odb_in);
01247       ss_printf(69, i + 6, "%ld       ", equipment[i].odb_out);
01248    }
01249 
01250    /* go to next line */
01251    ss_printf(0, i + 6, "");
01252 }
01253 
01254 /*------------------------------------------------------------------*/
01255 
01256 BOOL logger_root()
01257 /* check if logger uses ROOT format */
01258 {
01259    int size, i, status;
01260    char str[80];
01261    HNDLE hKeyRoot, hKey;
01262 
01263    if (db_find_key(hDB, 0, "/Logger/Channels", &hKeyRoot) == DB_SUCCESS) {
01264       for (i = 0;; i++) {
01265          status = db_enum_key(hDB, hKeyRoot, i, &hKey);
01266          if (status == DB_NO_MORE_SUBKEYS)
01267             break;
01268 
01269          strcpy(str, "MIDAS");
01270          size = sizeof(str);
01271          db_get_value(hDB, hKey, "Settings/Format", str, &size, TID_STRING, TRUE);
01272 
01273          if (equal_ustring(str, "ROOT"))
01274             return TRUE;
01275       }
01276    }
01277 
01278    return FALSE;
01279 }
01280 
01281 /*------------------------------------------------------------------*/
01282 
01283 INT scheduler(void)
01284 {
01285    EQUIPMENT_INFO *eq_info;
01286    EQUIPMENT *eq;
01287    EVENT_HEADER *pevent;
01288    DWORD last_time_network = 0, last_time_display = 0, last_time_flush = 0, readout_start;
01289    INT i, j, index, status, ch, source, size, state;
01290    char str[80];
01291    BOOL buffer_done, flag, force_update = FALSE;
01292 
01293    INT opt_max = 0, opt_index = 0, opt_tcp_size = 128, opt_cnt = 0;
01294    INT err;
01295 
01296 #ifdef OS_VXWORKS
01297    rpc_set_opt_tcp_size(1024);
01298 #ifdef PPCxxx
01299    rpc_set_opt_tcp_size(NET_TCP_SIZE);
01300 #endif
01301 #endif
01302 
01303    /*----------------- MAIN equipment loop ------------------------------*/
01304 
01305    do {
01306       actual_millitime = ss_millitime();
01307       actual_time = ss_time();
01308 
01309       /*---- loop over equipment table -------------------------------*/
01310       for (index = 0;; index++) {
01311          eq = &equipment[index];
01312          eq_info = &eq->info;
01313 
01314          /* check if end of equipment list */
01315          if (!eq->name[0])
01316             break;
01317 
01318          if (!eq_info->enabled)
01319             continue;
01320 
01321          if (eq->status != FE_SUCCESS)
01322             continue;
01323 
01324          /*---- call idle routine for slow control equipment ----*/
01325          if ((eq_info->eq_type & EQ_SLOW) && eq->status == FE_SUCCESS) {
01326             if (eq_info->event_limit > 0 && run_state == STATE_RUNNING) {
01327                if (actual_time - eq->last_idle >= (DWORD) eq_info->event_limit) {
01328                   eq->cd(CMD_IDLE, eq);
01329                   eq->last_idle = actual_time;
01330                }
01331             } else
01332                eq->cd(CMD_IDLE, eq);
01333          }
01334 
01335          if (run_state == STATE_STOPPED && (eq_info->read_on & RO_STOPPED) == 0)
01336             continue;
01337          if (run_state == STATE_PAUSED && (eq_info->read_on & RO_PAUSED) == 0)
01338             continue;
01339          if (run_state == STATE_RUNNING && (eq_info->read_on & RO_RUNNING) == 0)
01340             continue;
01341 
01342          /*---- check periodic events ----*/
01343          if ((eq_info->eq_type & EQ_PERIODIC) || (eq_info->eq_type & EQ_SLOW)) {
01344             if (eq_info->period == 0)
01345                continue;
01346 
01347             /* check if period over */
01348             if (actual_millitime - eq->last_called >= (DWORD) eq_info->period) {
01349                /* disable interrupts during readout */
01350                interrupt_enable(FALSE);
01351 
01352                /* readout and send event */
01353                status = send_event(index);
01354 
01355                if (status != CM_SUCCESS) {
01356                   cm_msg(MERROR, "scheduler", "send_event error %d", status);
01357                   goto net_error;
01358                }
01359 
01360                /* re-enable the interrupt after periodic */
01361                interrupt_enable(TRUE);
01362             }
01363          }
01364 
01365          /* end of periodic equipments */
01366          /*---- check polled events ----*/
01367          if (eq_info->eq_type & EQ_POLLED) {
01368             readout_start = actual_millitime;
01369             pevent = NULL;
01370 
01371             while ((source = poll_event(eq_info->source, eq->poll_count, FALSE)) > 0) {
01372                pevent = dm_pointer_get();
01373                if (pevent == NULL) {
01374                   cm_msg(MERROR, "scheduler",
01375                          "polled, dm_pointer_get not returning valid pointer");
01376                   status = SS_NO_MEMORY;
01377                   goto net_error;
01378                }
01379 
01380                /* compose MIDAS event header */
01381                pevent->event_id = eq_info->event_id;
01382                pevent->trigger_mask = eq_info->trigger_mask;
01383                pevent->data_size = 0;
01384                pevent->time_stamp = actual_time;
01385                pevent->serial_number = eq->serial_number;
01386 
01387                /* put source at beginning of event, will be overwritten by 
01388                   user readout code, just a special feature used by some 
01389                   multi-source applications */
01390                *(INT *) (pevent + 1) = source;
01391 
01392                if (eq->info.num_subevents) {
01393                   eq->subevent_number = 0;
01394                   do {
01395                      *(INT *) ((char *) (pevent + 1) + pevent->data_size) = source;
01396 
01397                      /* call user readout routine for subevent indicating offset */
01398                      size = eq->readout((char *) (pevent + 1), pevent->data_size);
01399                      pevent->data_size += size;
01400                      if (size > 0) {
01401                         if (pevent->data_size + sizeof(EVENT_HEADER) >
01402                             (DWORD) max_event_size) {
01403                            cm_msg(MERROR, "scheduler",
01404                                   "Event size %ld larger than maximum size %d",
01405                                   (long) (pevent->data_size + sizeof(EVENT_HEADER)),
01406                                   max_event_size);
01407                         }
01408 
01409                         eq->subevent_number++;
01410                         eq->serial_number++;
01411                      }
01412 
01413                      /* wait for next event */
01414                      do {
01415                         source = poll_event(eq_info->source, eq->poll_count, FALSE);
01416 
01417                         if (source == FALSE) {
01418                            actual_millitime = ss_millitime();
01419 
01420                            /* repeat no more than period */
01421                            if (actual_millitime - readout_start > (DWORD) eq_info->period)
01422                               break;
01423                         }
01424                      } while (source == FALSE);
01425 
01426                   } while (eq->subevent_number < eq->info.num_subevents && source);
01427 
01428                   /* notify readout routine about end of super-event */
01429                   pevent->data_size = eq->readout((char *) (pevent + 1), -1);
01430                } else {
01431                   /* call user readout routine indicating event source */
01432                   pevent->data_size = eq->readout((char *) (pevent + 1), 0);
01433 
01434                   /* check event size */
01435                   if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
01436                      cm_msg(MERROR, "scheduler",
01437                             "Event size %ld larger than maximum size %d",
01438                             (long) (pevent->data_size + sizeof(EVENT_HEADER)),
01439                             max_event_size);
01440                   }
01441 
01442                   /* increment serial number if event read out sucessfully */
01443                   if (pevent->data_size)
01444                      eq->serial_number++;
01445                }
01446 
01447                /* send event */
01448                if (pevent->data_size) {
01449                   if (eq->buffer_handle) {
01450                      /* send first event to ODB if logger writes in root format */
01451                      if (pevent->serial_number == 1)
01452                         if (logger_root())
01453                            update_odb(pevent, eq->hkey_variables, eq->format);
01454 
01455 #ifdef USE_EVENT_CHANNEL
01456                      dm_pointer_increment(eq->buffer_handle,
01457                                           pevent->data_size + sizeof(EVENT_HEADER));
01458 #else
01459                      status = rpc_send_event(eq->buffer_handle, pevent,
01460                                              pevent->data_size + sizeof(EVENT_HEADER),
01461                                              SYNC);
01462 
01463                      if (status != SUCCESS) {
01464                         cm_msg(MERROR, "scheduler", "rpc_send_event error %d", status);
01465                         goto net_error;
01466                      }
01467 #endif
01468 
01469                      eq->bytes_sent += pevent->data_size + sizeof(EVENT_HEADER);
01470 
01471                      if (eq->info.num_subevents)
01472                         eq->events_sent += eq->subevent_number;
01473                      else
01474                         eq->events_sent++;
01475                   }
01476                }
01477 
01478                actual_millitime = ss_millitime();
01479 
01480                /* repeat no more than period */
01481                if (actual_millitime - readout_start > (DWORD) eq_info->period)
01482                   break;
01483 
01484                /* quit if event limit is reached */
01485                if (eq_info->event_limit > 0 &&
01486                    eq->stats.events_sent + eq->events_sent >= eq_info->event_limit)
01487                   break;
01488             }
01489 
01490             /* send event to ODB */
01491             if (pevent && (eq_info->read_on & RO_ODB || eq_info->history)) {
01492                if (actual_millitime - eq->last_called > ODB_UPDATE_TIME && pevent != NULL) {
01493                   eq->last_called = actual_millitime;
01494                   update_odb(pevent, eq->hkey_variables, eq->format);
01495                   eq->odb_out++;
01496                }
01497             }
01498          }
01499 
01500          /*---- send interrupt events ----*/
01501          if (eq_info->eq_type & EQ_INTERRUPT) {
01502             /* not much to do as work being done independently in interrupt_routine() */
01503 
01504             /* update ODB */
01505             if (interrupt_odb_buffer_valid) {
01506                update_odb(interrupt_odb_buffer, interrupt_eq->hkey_variables,
01507                           interrupt_eq->format);
01508                interrupt_odb_buffer_valid = FALSE;
01509             }
01510 
01511          }
01512 
01513          /*---- check if event limit is reached ----*/
01514          if (eq_info->eq_type != EQ_SLOW &&
01515              eq_info->event_limit > 0 &&
01516              eq->stats.events_sent + eq->events_sent >= eq_info->event_limit &&
01517              run_state == STATE_RUNNING) {
01518             /* stop run */
01519             if (cm_transition(TR_STOP, 0, str, sizeof(str), SYNC, FALSE) != CM_SUCCESS)
01520                cm_msg(MERROR, "scheduler", "cannot stop run: %s", str);
01521 
01522             /* check if autorestart, main loop will take care of it */
01523             size = sizeof(BOOL);
01524             flag = FALSE;
01525             db_get_value(hDB, 0, "/Logger/Auto restart", &flag, &size, TID_BOOL, TRUE);
01526 
01527             if (flag)
01528                auto_restart = ss_time() + 20;   /* restart in 20 sec. */
01529 
01530             /* update event display correctly */
01531             force_update = TRUE;
01532          }
01533       }
01534 
01535       /*---- call frontend_loop periodically -------------------------*/
01536       if (frontend_call_loop) {
01537          status = frontend_loop();
01538          if (status != CM_SUCCESS)
01539             status = RPC_SHUTDOWN;
01540       }
01541 
01542       /*---- check for deferred transitions --------------------------*/
01543       cm_check_deferred_transition();
01544 
01545       /*---- calculate rates and update status page periodically -----*/
01546       if (force_update ||
01547           (display_period
01548            && actual_millitime - last_time_display > (DWORD) display_period)
01549           || (!display_period && actual_millitime - last_time_display > 3000)) {
01550          force_update = FALSE;
01551 
01552          /* calculate rates */
01553          if (actual_millitime != last_time_display) {
01554             max_bytes_per_sec = 0;
01555             for (i = 0; equipment[i].name[0]; i++) {
01556                eq = &equipment[i];
01557                eq->stats.events_sent += eq->events_sent;
01558                eq->stats.events_per_sec =
01559                    eq->events_sent / ((actual_millitime - last_time_display) / 1000.0);
01560                eq->stats.kbytes_per_sec =
01561                    eq->bytes_sent / 1024.0 / ((actual_millitime - last_time_display) /
01562                                               1000.0);
01563 
01564                if ((INT) eq->bytes_sent > max_bytes_per_sec)
01565                   max_bytes_per_sec = eq->bytes_sent;
01566 
01567                eq->bytes_sent = 0;
01568                eq->events_sent = 0;
01569             }
01570 
01571             max_bytes_per_sec = (DWORD)
01572                 ((double) max_bytes_per_sec /
01573                  ((actual_millitime - last_time_display) / 1000.0));
01574 
01575             /* tcp buffer size evaluation */
01576             if (optimize) {
01577                opt_max = max(opt_max, (INT) max_bytes_per_sec);
01578                ss_printf(0, opt_index, "%6d : %5.1lf %5.1lf", opt_tcp_size,
01579                          opt_max / 1024.0, max_bytes_per_sec / 1024.0);
01580                if (++opt_cnt == 10) {
01581                   opt_cnt = 0;
01582                   opt_max = 0;
01583                   opt_index++;
01584                   opt_tcp_size = 1 << (opt_index + 7);
01585                   rpc_set_opt_tcp_size(opt_tcp_size);
01586                   if (1 << (opt_index + 7) > 0x8000) {
01587                      opt_index = 0;
01588                      opt_tcp_size = 1 << 7;
01589                      rpc_set_opt_tcp_size(opt_tcp_size);
01590                   }
01591                }
01592             }
01593 
01594          }
01595 
01596          /* propagate changes in equipment to ODB */
01597          rpc_set_option(-1, RPC_OTRANSPORT, RPC_FTCP);
01598          db_send_changed_records();
01599          rpc_set_option(-1, RPC_OTRANSPORT, RPC_TCP);
01600 
01601          if (display_period) {
01602             display(FALSE);
01603 
01604             /* check keyboard */
01605             ch = 0;
01606             status = 0;
01607             while (ss_kbhit()) {
01608                ch = ss_getchar(0);
01609                if (ch == -1)
01610                   ch = getchar();
01611 
01612                if (ch == '!')
01613                   status = RPC_SHUTDOWN;
01614             }
01615 
01616             if (ch > 0)
01617                display(TRUE);
01618             if (status == RPC_SHUTDOWN)
01619                break;
01620          }
01621 
01622          last_time_display = actual_millitime;
01623       }
01624 
01625       /*---- check to flush cache ------------------------------------*/
01626       if (actual_millitime - last_time_flush > 1000) {
01627          last_time_flush = actual_millitime;
01628 
01629          /* if cache on server is not filled in one second at current
01630             data rate, flush it now to make events available to consumers */
01631 
01632          if (max_bytes_per_sec < SERVER_CACHE_SIZE) {
01633             interrupt_enable(FALSE);
01634 
01635 #ifdef USE_EVENT_CHANNEL
01636             if ((status = dm_area_flush()) != CM_SUCCESS)
01637                cm_msg(MERROR, "scheduler", "dm_area_flush: %i", status);
01638 #endif
01639 
01640             for (i = 0; equipment[i].name[0]; i++) {
01641                if (equipment[i].buffer_handle) {
01642                   /* check if buffer already flushed */
01643                   buffer_done = FALSE;
01644                   for (j = 0; j < i; j++)
01645                      if (equipment[i].buffer_handle == equipment[j].buffer_handle) {
01646                         buffer_done = TRUE;
01647                         break;
01648                      }
01649 
01650                   if (!buffer_done) {
01651                      rpc_set_option(-1, RPC_OTRANSPORT, RPC_FTCP);
01652                      rpc_flush_event();
01653                      err = bm_flush_cache(equipment[i].buffer_handle, ASYNC);
01654                      if (err != BM_SUCCESS) {
01655                         cm_msg(MERROR, "scheduler", "bm_flush_cache(ASYNC) error %d",
01656                                err);
01657                         return err;
01658                      }
01659                      rpc_set_option(-1, RPC_OTRANSPORT, RPC_TCP);
01660                   }
01661                }
01662             }
01663             interrupt_enable(TRUE);
01664          }
01665       }
01666 
01667       /*---- check for auto restart --------------------------------*/
01668       if (auto_restart > 0 && ss_time() > auto_restart) {
01669          /* check if really stopped */
01670          size = sizeof(state);
01671          status = db_get_value(hDB, 0, "Runinfo/State", &state, &size, TID_INT, TRUE);
01672          if (status != DB_SUCCESS)
01673             cm_msg(MERROR, "scheduler", "cannot get Runinfo/State in database");
01674 
01675          if (state == STATE_STOPPED) {
01676             auto_restart = 0;
01677             size = sizeof(run_number);
01678             status =
01679                 db_get_value(hDB, 0, "/Runinfo/Run number", &run_number, &size, TID_INT,
01680                              TRUE);
01681             assert(status == SUCCESS);
01682 
01683             if (run_number <= 0) {
01684                cm_msg(MERROR, "main", "aborting on attempt to use invalid run number %d",
01685                       run_number);
01686                abort();
01687             }
01688 
01689             cm_msg(MTALK, "main", "starting new run");
01690             status = cm_transition(TR_START, run_number + 1, NULL, 0, SYNC, FALSE);
01691             if (status != CM_SUCCESS)
01692                cm_msg(MERROR, "main", "cannot restart run");
01693          }
01694       }
01695 
01696       /*---- check network messages ----------------------------------*/
01697       if (run_state == STATE_RUNNING && interrupt_eq == NULL) {
01698          /* only call yield once every 500ms when running */
01699          if (actual_millitime - last_time_network > 500) {
01700             status = cm_yield(0);
01701             last_time_network = actual_millitime;
01702          } else
01703             status = RPC_SUCCESS;
01704       } else
01705          /* when run is stopped or interrupts used, 
01706             call yield with 100ms timeout */
01707          status = cm_yield(100);
01708 
01709       /* exit for VxWorks */
01710       if (fe_stop)
01711          status = RPC_SHUTDOWN;
01712 
01713    } while (status != RPC_SHUTDOWN && status != SS_ABORT);
01714 
01715  net_error:
01716 
01717    return status;
01718 }
01719 
01720 /*------------------------------------------------------------------*/
01721 
01722 #ifdef HAVE_CAMAC
01723 
01724 INT cnaf_callback(INT index, void *prpc_param[])
01725 {
01726    DWORD cmd, b, c, n, a, f, *pdword, *size, *x, *q, dtemp;
01727    WORD *pword, *pdata, temp;
01728    INT i, count;
01729 
01730    /* Decode parameters */
01731    cmd = CDWORD(0);
01732    b = CDWORD(1);
01733    c = CDWORD(2);
01734    n = CDWORD(3);
01735    a = CDWORD(4);
01736    f = CDWORD(5);
01737    pdword = CPDWORD(6);
01738    pword = CPWORD(6);
01739    pdata = CPWORD(6);
01740    size = CPDWORD(7);
01741    x = CPDWORD(8);
01742    q = CPDWORD(9);
01743 
01744    /* determine repeat count */
01745    if (index == RPC_CNAF16)
01746       count = *size / sizeof(WORD);     /* 16 bit */
01747    else
01748       count = *size / sizeof(DWORD);    /* 24 bit */
01749 
01750    switch (cmd) {
01751     /*---- special commands ----*/
01752 
01753    case CNAF_INHIBIT_SET:
01754       cam_inhibit_set(c);
01755       break;
01756    case CNAF_INHIBIT_CLEAR:
01757       cam_inhibit_clear(c);
01758       break;
01759    case CNAF_CRATE_CLEAR:
01760       cam_crate_clear(c);
01761       break;
01762    case CNAF_CRATE_ZINIT:
01763       cam_crate_zinit(c);
01764       break;
01765 
01766    case CNAF_TEST:
01767       break;
01768 
01769    case CNAF:
01770       if (index == RPC_CNAF16) {
01771          for (i = 0; i < count; i++)
01772             if (f < 16)
01773                cam16i_q(c, n, a, f, pword++, (int *) x, (int *) q);
01774             else if (f < 24)
01775                cam16o_q(c, n, a, f, pword[i], (int *) x, (int *) q);
01776             else
01777                cam16i_q(c, n, a, f, &temp, (int *) x, (int *) q);
01778       } else {
01779          for (i = 0; i < count; i++)
01780             if (f < 16)
01781                cam24i_q(c, n, a, f, pdword++, (int *) x, (int *) q);
01782             else if (f < 24)
01783                cam24o_q(c, n, a, f, pdword[i], (int *) x, (int *) q);
01784             else
01785                cam24i_q(c, n, a, f, &dtemp, (int *) x, (int *) q);
01786       }
01787 
01788       break;
01789 
01790    case CNAF_nQ:
01791       if (index == RPC_CNAF16) {
01792          if (f < 16)
01793             cam16i_rq(c, n, a, f, (WORD **) & pdword, count);
01794       } else {
01795          if (f < 16)
01796             cam24i_rq(c, n, a, f, &pdword, count);
01797       }
01798 
01799       /* return reduced return size */
01800       *size = (int) pdword - (int) pdata;
01801       break;
01802 
01803    default:
01804       printf("cnaf: Unknown command 0x%X\n", (unsigned int) cmd);
01805    }
01806 
01807    if (debug) {
01808       if (index == RPC_CNAF16)
01809          printf("cmd=%d r=%d c=%d n=%d a=%d f=%d d=%X x=%d q=%d\n",
01810                 (int) cmd, (int) count, (int) c, (int) n, (int) a, (int) f,
01811                 (int) pword[0], (int) *x, (int) *q);
01812       else if (index == RPC_CNAF24)
01813          printf("cmd=%d r=%d c=%d n=%d a=%d f=%d d=%X x=%d q=%d\n",
01814                 (int) cmd, (int) count, (int) c, (int) n, (int) a, (int) f,
01815                 (int) pdword[0], (int) *x, (int) *q);
01816    }
01817 
01818    return RPC_SUCCESS;
01819 }
01820 
01821 #endif                          /* HAVE_CAMAC */
01822 
01823 /*------------------------------------------------------------------*/
01824 
01825 #ifdef OS_VXWORKS
01826 int mfe(char *ahost_name, char *aexp_name, BOOL adebug)
01827 #else
01828 int main(int argc, char *argv[])
01829 #endif
01830 {
01831    INT status, i, dm_size;
01832    INT daemon;
01833 
01834    host_name[0] = 0;
01835    exp_name[0] = 0;
01836    debug = FALSE;
01837    daemon = 0;
01838 
01839    setbuf(stdout, 0);
01840    setbuf(stderr, 0);
01841 
01842 #ifdef SIGPIPE
01843    signal(SIGPIPE, SIG_IGN);
01844 #endif
01845 
01846 #ifdef OS_VXWORKS
01847    if (ahost_name)
01848       strcpy(host_name, ahost_name);
01849    if (aexp_name)
01850       strcpy(exp_name, aexp_name);
01851    debug = adebug;
01852 #else
01853 
01854    /* get default from environment */
01855    cm_get_environment(host_name, sizeof(host_name), exp_name, sizeof(exp_name));
01856 
01857    /* parse command line parameters */
01858    for (i = 1; i < argc; i++) {
01859       if (argv[i][0] == '-' && argv[i][1] == 'd')
01860          debug = TRUE;
01861       else if (argv[i][0] == '-' && argv[i][1] == 'D')
01862          daemon = 1;
01863       else if (argv[i][0] == '-' && argv[i][1] == 'O')
01864          daemon = 2;
01865       else if (argv[i][0] == '-') {
01866          if (i + 1 >= argc || argv[i + 1][0] == '-')
01867             goto usage;
01868          if (argv[i][1] == 'e')
01869             strcpy(exp_name, argv[++i]);
01870          else if (argv[i][1] == 'h')
01871             strcpy(host_name, argv[++i]);
01872          else {
01873           usage:
01874             printf("usage: frontend [-h Hostname] [-e Experiment] [-d] [-D] [-O]\n");
01875             printf("         [-d]     Used to debug the frontend\n");
01876             printf("         [-D]     Become a daemon\n");
01877             printf("         [-O]     Become a daemon but keep stdout\n");
01878             return 0;
01879          }
01880       }
01881    }
01882 #endif
01883 
01884    /* check event and buffer sizes */
01885    if (event_buffer_size < 2 * max_event_size) {
01886       printf("event_buffer_size too small for max. event size\n");
01887       ss_sleep(5000);
01888       return 1;
01889    }
01890 
01891    if (max_event_size > MAX_EVENT_SIZE) {
01892       printf("Requested max_event_size (%d) exceeds max. system event size (%d)",
01893              max_event_size, MAX_EVENT_SIZE);
01894       ss_sleep(5000);
01895       return 1;
01896    }
01897 
01898    dm_size = event_buffer_size;
01899 
01900 #ifdef OS_VXWORKS
01901    /* override dm_size in case of VxWorks
01902       take remaining free memory and use 20% of it for dm_ */
01903    dm_size = 2 * 10 * (max_event_size + sizeof(EVENT_HEADER) + sizeof(INT));
01904    if (dm_size > memFindMax()) {
01905       cm_msg(MERROR, "mainFE", "Not enough mem space for event size");
01906       return 0;
01907    }
01908    /* takes overall 20% of the available memory resource for dm_() */
01909    dm_size = 0.2 * memFindMax();
01910 
01911    /* there are two buffers */
01912    dm_size /= 2;
01913 #endif
01914 
01915    /* reduce memory size for MS-DOS */
01916 #ifdef OS_MSDOS
01917    if (dm_size > 0x4000)
01918       dm_size = 0x4000;         /* 16k */
01919 #endif
01920 
01921    /* inform user of settings */
01922    printf("Event buffer size      :     %d\n", event_buffer_size);
01923    printf("Buffer allocation      : 2 x %d\n", dm_size);
01924    printf("System max event size  :     %d\n", MAX_EVENT_SIZE);
01925    printf("User max event size    :     %d\n", max_event_size);
01926    if (max_event_size_frag > 0)
01927       printf("User max frag. size    :     %d\n", max_event_size_frag);
01928    printf("# of events per buffer :     %d\n\n", dm_size / max_event_size);
01929 
01930    if (daemon) {
01931       printf("\nBecoming a daemon...\n");
01932       ss_daemon_init(daemon == 2);
01933    }
01934 
01935    /* now connect to server */
01936    if (display_period) {
01937       if (host_name[0])
01938          printf("Connect to experiment %s on host %s...", exp_name, host_name);
01939       else
01940          printf("Connect to experiment %s...", exp_name);
01941    }
01942 
01943    status = cm_connect_experiment1(host_name, exp_name, frontend_name,
01944                                    NULL, DEFAULT_ODB_SIZE, DEFAULT_FE_TIMEOUT);
01945    if (status != CM_SUCCESS) {
01946       /* let user read message before window might close */
01947       ss_sleep(5000);
01948       return 1;
01949    }
01950 
01951    if (display_period)
01952       printf("OK\n");
01953 
01954    /* book buffer space */
01955    status = dm_buffer_create(dm_size, max_event_size);
01956    if (status != CM_SUCCESS) {
01957       printf("dm_buffer_create: Not enough memory or event too big\n");
01958       return 1;
01959    }
01960 
01961    /* remomve any dead frontend */
01962    cm_cleanup(frontend_name, FALSE);
01963 
01964    /* shutdown previous frontend */
01965    status = cm_shutdown(frontend_name, FALSE);
01966    if (status == CM_SUCCESS && display_period) {
01967       printf("Previous frontend stopped\n");
01968 
01969       /* let user read message */
01970       ss_sleep(3000);
01971    }
01972 
01973    /* register transition callbacks */
01974    if (cm_register_transition(TR_START, tr_start) != CM_SUCCESS ||
01975        cm_register_transition(TR_PRESTOP, tr_prestop) != CM_SUCCESS ||
01976        cm_register_transition(TR_PREPAUSE, tr_prepause) != CM_SUCCESS ||
01977        cm_register_transition(TR_RESUME, tr_resume) != CM_SUCCESS) {
01978       printf("Failed to start local RPC server");
01979       cm_disconnect_experiment();
01980       dm_buffer_release();
01981 
01982       /* let user read message before window might close */
01983       ss_sleep(5000);
01984       return 1;
01985    }
01986 #ifdef HAVE_CAMAC
01987 
01988    /* register CNAF callback */
01989    cm_register_function(RPC_CNAF16, cnaf_callback);
01990    cm_register_function(RPC_CNAF24, cnaf_callback);
01991 
01992 #endif
01993 
01994    cm_get_experiment_database(&hDB, &status);
01995 
01996    /* set time from server */
01997 #ifdef OS_VXWORKS
01998    cm_synchronize(NULL);
01999 #endif
02000 
02001    /* turn off watchdog if in debug mode */
02002    if (debug)
02003       cm_set_watchdog_params(TRUE, 0);
02004 
02005    /* increase RPC timeout to 2min for logger with exabyte or blocked disk */
02006    rpc_set_option(-1, RPC_OTIMEOUT, 120000);
02007 
02008    /* set own message print function */
02009    if (display_period)
02010       cm_set_msg_print(MT_ALL, MT_ALL, message_print);
02011 
02012    /* call user init function */
02013    if (display_period)
02014       printf("Init hardware...");
02015    if (frontend_init() != SUCCESS) {
02016       if (display_period)
02017          printf("\n");
02018       cm_disconnect_experiment();
02019       dm_buffer_release();
02020 
02021       /* let user read message before window might close */
02022       ss_sleep(5000);
02023       return 1;
02024    }
02025 
02026    /* reqister equipment in ODB */
02027    if (register_equipment() != SUCCESS) {
02028       if (display_period)
02029          printf("\n");
02030       cm_disconnect_experiment();
02031       dm_buffer_release();
02032 
02033       /* let user read message before window might close */
02034       ss_sleep(5000);
02035       return 1;
02036    }
02037 
02038    if (display_period)
02039       printf("OK\n");
02040 
02041    /* initialize screen display */
02042    if (display_period) {
02043       ss_sleep(1000);
02044       display(TRUE);
02045    }
02046 
02047    /* switch on interrupts if running */
02048    if (interrupt_eq && run_state == STATE_RUNNING)
02049       interrupt_enable(TRUE);
02050 
02051    /* initialize ss_getchar */
02052    ss_getchar(0);
02053 
02054    /* call main scheduler loop */
02055    status = scheduler();
02056 
02057    /* reset terminal */
02058    ss_getchar(TRUE);
02059 
02060    /* switch off interrupts */
02061    if (interrupt_eq) {
02062       interrupt_configure(CMD_INTERRUPT_DISABLE, 0, 0);
02063       interrupt_configure(CMD_INTERRUPT_DETACH, 0, 0);
02064       if (interrupt_odb_buffer)
02065          free(interrupt_odb_buffer);
02066    }
02067 
02068    /* detach interrupts */
02069    if (interrupt_eq != NULL)
02070       interrupt_configure(CMD_INTERRUPT_DETACH, interrupt_eq->info.source, 0);
02071 
02072    /* call user exit function */
02073    frontend_exit();
02074 
02075    /* close slow control drivers */
02076    for (i = 0; equipment[i].name[0]; i++)
02077       if ((equipment[i].info.eq_type & EQ_SLOW) && equipment[i].status == FE_SUCCESS)
02078          equipment[i].cd(CMD_EXIT, &equipment[i]);
02079 
02080    /* close network connection to server */
02081    cm_disconnect_experiment();
02082 
02083    if (display_period) {
02084       if (status == RPC_SHUTDOWN) {
02085          ss_clear_screen();
02086          ss_printf(0, 0, "Frontend shut down.");
02087          ss_printf(0, 1, "");
02088       }
02089    }
02090 
02091    if (status != RPC_SHUTDOWN)
02092       printf("Network connection aborted.\n");
02093 
02094    dm_buffer_release();
02095 
02096    return 0;
02097 }

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