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

Midas DOC Version 1.9.5 ---- PSI Stefan Ritt ----
Contributions: Pierre-Andre Amaudruz - Suzannah Daviel - Doxygen - Peter Green - Qing Gu - Greg Hackman - Gertjan Hofman - Paul Knowles - Rudi Meier - Glenn Moloney - Dave Morris - John M O'Donnell - Konstantin Olchanski - Renee Poutissou - Andreas Suter - Jan M.Wouters - Piotr Adam Zolnierczuk