mevb.c

Go to the documentation of this file.
00001 /********************************************************************\
00002 Name:         mevb.c
00003 Created by:   Pierre-Andre Amaudruz
00004 
00005 Contents:     Main Event builder task.
00006 $Log: mevb.c,v $
00007 Revision 1.18  2004/10/07 23:11:49  pierre
00008 active enable and fragment request switch
00009 
00010 Revision 1.17  2004/10/07 22:04:00  pierre
00011 Doxygen correction
00012 
00013 Revision 1.16  2004/10/07 20:08:34  pierre
00014 1.9.5
00015 
00016 Revision 1.15  2004/10/04 23:55:28  pierre
00017 move ebuilder into equipment list
00018 
00019 Revision 1.14  2004/09/29 17:55:34  pierre
00020 fix speed problem
00021 
00022 Revision 1.13  2004/09/29 16:20:31  pierre
00023 change Ebuilder structure
00024 
00025 Revision 1.12  2004/01/08 08:40:08  midas
00026 Implemented standard indentation
00027 
00028 Revision 1.11  2004/01/08 06:48:26  pierre
00029 Doxygen the file
00030 
00031 Revision 1.10  2003/08/19 23:26:36  pierre
00032 fix cm_get_environment arg
00033 
00034 Revision 1.9  2002/10/07 17:04:01  pierre
00035 fix tr_stop request
00036 
00037 Revision 1.8  2002/09/28 00:48:33  pierre
00038 Add EB_USER_ERROR handling, handFlush()
00039 
00040 Revision 1.7  2002/09/25 18:37:37  pierre
00041 correct: header passing, user field, abort run
00042 
00043 Revision 1.6  2002/08/29 22:07:47  pierre
00044 fix event header, double task, EOR
00045 
00046 Revision 1.5  2002/07/13 05:45:49  pierre
00047 added swap before user function
00048 
00049 Revision 1.4  2002/06/14 04:59:08  pierre
00050 revised for ybos 
00051 
00052 Revision 1.3  2002/05/08 20:51:41  midas
00053 Added extra parameter to function db_get_value()
00054 
00055 Revision 1.2  2002/01/17 23:34:14  pierre
00056 doc++ format
00057 
00058 Revision 1.1.1.1  2002/01/17 19:49:54  pierre
00059 Initial Version
00060 
00061 \********************************************************************/
00062 
00063 /**dox***************************************************************/
00064 /* @file mevb.c
00065 The Event builder main file 
00066 */
00067 
00068 #include <stdio.h>
00069 #include "midas.h"
00070 #include "mevb.h"
00071 #include "msystem.h"
00072 #include "ybos.h"
00073 
00074 #define SERVER_CACHE_SIZE  100000       /* event cache before buffer */
00075 
00076 #define ODB_UPDATE_TIME      1000       /* 1 seconds for ODB update */
00077 
00078 #define DEFAULT_FE_TIMEOUT  60000       /* 60 seconds for watchdog timeout */
00079 
00080 EBUILDER_SETTINGS ebset;
00081 EBUILDER_CHANNEL ebch[MAX_CHANNELS];
00082 
00083 INT run_state;                     /* STATE_RUNNING, STATE_STOPPED, STATE_PAUSED */
00084 INT run_number;
00085 DWORD last_time;
00086 DWORD actual_time;                 /* current time in seconds since 1970 */
00087 DWORD actual_millitime;            /* current time in milliseconds */
00088 
00089 char host_name[HOST_NAME_LENGTH];
00090 char expt_name[NAME_LENGTH];
00091 char full_frontend_name[256];
00092 char buffer_name[NAME_LENGTH];
00093 INT   nfragment;
00094 char *dest_event;
00095 HNDLE hDB, hKey, hStatKey, hSubkey, hEqKey, hESetKey;
00096 BOOL debug = FALSE, debug1 = FALSE;
00097 
00098 BOOL wheel = FALSE;
00099 char bars[] = "|\\-/";
00100 int i_bar;
00101 BOOL abort_requested = FALSE, stop_requested = TRUE;
00102 DWORD stop_time = 0, request_stop_time = 0;
00103 
00104 INT(*meb_fragment_add) (char *, char *, INT *);
00105 INT handFlush(void);
00106 INT source_booking(void);
00107 INT source_unbooking(void);
00108 INT close_buffers(void);
00109 INT source_scan(INT fmt, EQUIPMENT_INFO *eq_info);
00110 INT eb_mfragment_add(char *pdest, char *psrce, INT * size);
00111 INT eb_yfragment_add(char *pdest, char *psrce, INT * size);
00112 
00113 INT eb_begin_of_run(INT, char *, char *);
00114 INT eb_end_of_run(INT, char *);
00115 INT eb_user(INT, BOOL mismatch, EBUILDER_CHANNEL *, EVENT_HEADER *, void *, INT *);
00116 INT load_fragment(void);
00117 INT scan_fragment(void);
00118 extern char *frontend_name;
00119 extern char *frontend_file_name;
00120 extern BOOL frontend_call_loop;
00121 
00122 extern INT max_event_size;
00123 extern INT max_event_size_frag;
00124 extern INT event_buffer_size;
00125 extern INT display_period;
00126 extern INT ebuilder_init(void);
00127 extern INT ebuilder_exit(void);
00128 extern INT ebuilder_loop(void);
00129 
00130 extern EQUIPMENT equipment[];
00131 extern INT ybos_event_swap(DWORD * pevt);
00132 
00133 #define EQUIPMENT_COMMON_STR "\
00134 Event ID = WORD : 0\n\
00135 Trigger mask = WORD : 0\n\
00136 Buffer = STRING : [32] SYSTEM\n\
00137 Type = INT : 0\n\
00138 Source = INT : 0\n\
00139 Format = STRING : [8] FIXED\n\
00140 Enabled = BOOL : 0\n\
00141 Read on = INT : 0\n\
00142 Period = INT : 0\n\
00143 Event limit = DOUBLE : 0\n\
00144 Num subevents = DWORD : 0\n\
00145 Log history = INT : 0\n\
00146 Frontend host = STRING : [32] \n\
00147 Frontend name = STRING : [32] \n\
00148 Frontend file name = STRING : [256] \n\
00149 "
00150 
00151 #define EQUIPMENT_STATISTICS_STR "\
00152 Events sent = DOUBLE : 0\n\
00153 Events per sec. = DOUBLE : 0\n\
00154 kBytes per sec. = DOUBLE : 0\n\
00155 "
00156 
00157 /********************************************************************/
00158 INT register_equipment(void)
00159 {
00160   INT index, size, status;
00161   char str[256];
00162   EQUIPMENT_INFO *eq_info;
00163   EQUIPMENT_STATS *eq_stats;
00164   HNDLE hKey;
00165 
00166   /* get current ODB run state */
00167   size = sizeof(run_state);
00168   run_state = STATE_STOPPED;
00169   db_get_value(hDB, 0, "/Runinfo/State", &run_state, &size, TID_INT, TRUE);
00170   size = sizeof(run_number);
00171   run_number = 1;
00172   status = db_get_value(hDB, 0, "/Runinfo/Run number", &run_number, &size, TID_INT, TRUE);
00173   assert(status == SUCCESS);
00174 
00175   /* scan EQUIPMENT table from mevb.C */
00176   for (index = 0; equipment[index].name[0]; index++) {
00177     eq_info = &equipment[index].info;
00178     eq_stats = &equipment[index].stats;
00179 
00180     if (eq_info->event_id == 0) {
00181       printf("\nEvent ID 0 for %s not allowed\n", equipment[index].name);
00182       cm_disconnect_experiment();
00183       ss_sleep(5000);
00184       exit(0);
00185     }
00186 
00187     /* init status */
00188     equipment[index].status = EB_SUCCESS;
00189 
00190     sprintf(str, "/Equipment/%s/Common", equipment[index].name);
00191 
00192     /* get last event limit from ODB */
00193     if (eq_info->eq_type != EQ_SLOW) {
00194       db_find_key(hDB, 0, str, &hKey);
00195       size = sizeof(double);
00196       if (hKey)
00197         db_get_value(hDB, hKey, "Event limit", &eq_info->event_limit, &size,
00198         TID_DOUBLE, TRUE);
00199     }
00200 
00201     /* Create common subtree */
00202     status = db_check_record(hDB, 0, str, EQUIPMENT_COMMON_STR, TRUE);
00203     if (status != DB_SUCCESS) {
00204       printf("Cannot check equipment record, status = %d\n", status);
00205       ss_sleep(3000);
00206     }
00207     db_find_key(hDB, 0, str, &hKey);
00208 
00209     if (equal_ustring(eq_info->format, "YBOS"))
00210       equipment[index].format = FORMAT_YBOS;
00211     else if (equal_ustring(eq_info->format, "FIXED"))
00212       equipment[index].format = FORMAT_FIXED;
00213     else    /* default format is MIDAS */
00214       equipment[index].format = FORMAT_MIDAS;
00215 
00216     gethostname(eq_info->frontend_host, sizeof(eq_info->frontend_host));
00217     strcpy(eq_info->frontend_name, full_frontend_name);
00218     strcpy(eq_info->frontend_file_name, frontend_file_name);
00219 
00220     /* set record from equipment[] table in frontend.c */
00221     db_set_record(hDB, hKey, eq_info, sizeof(EQUIPMENT_INFO), 0);
00222 
00223     /* get record once at the start equipment info */
00224     size = sizeof(EQUIPMENT_INFO);
00225     db_get_record(hDB, hKey, eq_info, &size, 0);
00226 
00227     /*---- Create just the key , leave it empty ---------------------------------*/
00228     sprintf(str, "/Equipment/%s/Variables", equipment[index].name);
00229     db_create_key(hDB, 0, str, TID_KEY);
00230     db_find_key(hDB, 0, str, &hKey);
00231     equipment[index].hkey_variables = hKey;
00232 
00233     /*---- Create and initialize statistics tree -------------------*/
00234     sprintf(str, "/Equipment/%s/Statistics", equipment[index].name);
00235 
00236     status = db_check_record(hDB, 0, str, EQUIPMENT_STATISTICS_STR, TRUE);
00237     if (status != DB_SUCCESS) {
00238       printf("Cannot create/check statistics record, error %d\n", status);
00239       ss_sleep(3000);
00240     }
00241 
00242     status = db_find_key(hDB, 0, str, &hKey);
00243     if (status != DB_SUCCESS) {
00244       printf("Cannot find statistics record, error %d\n", status);
00245       ss_sleep(3000);
00246     }
00247 
00248     eq_stats->events_sent = 0;
00249     eq_stats->events_per_sec = 0;
00250     eq_stats->kbytes_per_sec = 0;
00251 
00252     /* open hot link to statistics tree */
00253     status = db_open_record(hDB, hKey, eq_stats, sizeof(EQUIPMENT_STATS)
00254       , MODE_WRITE, NULL, NULL);
00255     if (status != DB_SUCCESS) {
00256       cm_msg(MERROR, "register_equipment", 
00257         "Cannot open statistics record, error %d. Probably other FE is using it",
00258         status);
00259       ss_sleep(3000);
00260     }
00261 
00262     /*---- open event buffer ---------------------------------------*/
00263     if (eq_info->buffer[0]) {
00264       status = bm_open_buffer(eq_info->buffer, EVENT_BUFFER_SIZE,
00265         &equipment[index].buffer_handle);
00266       if (status != BM_SUCCESS && status != BM_CREATED) {
00267         cm_msg(MERROR, "register_equipment",
00268           "Cannot open event buffer. Try to reduce EVENT_BUFFER_SIZE in midas.h \
00269           and rebuild the system.");
00270         return 0;
00271       }
00272 
00273       /* set the default buffer cache size */
00274       bm_set_cache_size(equipment[index].buffer_handle, 0, SERVER_CACHE_SIZE);
00275     } else {
00276       cm_msg(MERROR, "register_equipment", "Destination buffer must be present");
00277       ss_sleep(3000);
00278       exit(0);
00279     }
00280   }
00281   return SUCCESS;
00282 }
00283 
00284 /********************************************************************/
00285 INT load_fragment(void)
00286 {
00287   INT i, size, type;
00288   HNDLE hEqKey, hSubkey;
00289   EQUIPMENT_INFO *eq_info;
00290   KEY  key;
00291   char  buffer[NAME_LENGTH];
00292   char  format[8];
00293 
00294   /* Get equipment pointer, only one eqp for now */
00295   eq_info = &equipment[0].info;
00296 
00297   /* Scan Equipment/Common listing */
00298   if (db_find_key(hDB, 0, "Equipment", &hEqKey) != DB_SUCCESS) {
00299     cm_msg(MINFO, "load_fragment", "Equipment listing not found");
00300     return EB_ERROR;
00301   }
00302 
00303   /* Scan the Equipment list for fragment info collection */
00304   for (i = 0, nfragment=0 ; ; i++) {
00305     db_enum_key(hDB, hEqKey, i, &hSubkey);
00306     if (!hSubkey)
00307       break;
00308     db_get_key(hDB, hSubkey, &key);
00309     if (key.type == TID_KEY) {
00310       /* Equipment name */
00311       if (debug) printf("Equipment name:%s\n", key.name);
00312       /* Check if equipment is EQ_EB */
00313       size = sizeof(INT);
00314       db_get_value(hDB, hSubkey, "common/type", &type, &size, TID_INT, 0);
00315       size = sizeof(buffer);
00316       db_get_value(hDB, hSubkey, "common/Buffer", buffer, &size, TID_STRING, 0);
00317       size = sizeof(format);
00318       db_get_value(hDB, hSubkey, "common/Format", format, &size, TID_STRING, 0);
00319       /* Check if equipment match EB requirements */
00320       if ((type & EQ_EB)
00321         && (strncmp(buffer, buffer_name, strlen(buffer_name)) == 0)
00322         && (strncmp(format, eq_info->format, strlen(format)) == 0)) {
00323           /* match=> fill internal eb structure */
00324           strcpy(ebch[nfragment].format, format);
00325           strcpy(ebch[nfragment].buffer, buffer);
00326           size = sizeof(WORD);
00327           db_get_value(hDB, hSubkey, "common/Trigger Mask", &ebch[nfragment].trigger_mask, &size, TID_WORD, 0);
00328           size = sizeof(WORD);
00329           db_get_value(hDB, hSubkey, "common/Event ID", &ebch[nfragment].event_id, &size, TID_WORD, 0);
00330           nfragment++;
00331         }
00332     }
00333   }
00334 
00335   printf("Found %d fragment matching EB setting\n", nfragment);
00336   /* Point to the Ebuilder settings */
00337   /* Set fragment_add function based on the format */
00338   if (equipment[0].format == FORMAT_MIDAS)
00339     meb_fragment_add = eb_mfragment_add;
00340   else if (equipment[0].format == FORMAT_YBOS)
00341     meb_fragment_add = eb_yfragment_add;
00342   else {
00343     cm_msg(MERROR, "mevb", "Unknown data format :%d", format);
00344     return EB_ERROR;
00345   }
00346 
00347   /* allocate destination event buffer */
00348   dest_event = (char *) malloc(nfragment * (max_event_size + sizeof(EVENT_HEADER)));
00349   memset(dest_event, 0, nfragment * (max_event_size + sizeof(EVENT_HEADER)));
00350   if (dest_event == NULL) {
00351     cm_msg(MERROR, "EBuilder", "%s: Not enough memory for event buffer", full_frontend_name);
00352     return EB_ERROR;
00353   }
00354   return EB_SUCCESS;
00355 }
00356 
00357 /********************************************************************/
00358 INT scan_fragment(void)
00359 {
00360   INT fragn, status;
00361   EQUIPMENT *eq;
00362   EQUIPMENT_INFO *eq_info;
00363 
00364   /* Get equipment pointer, only one eqp for now */
00365   eq_info = &equipment[0].info;
00366 
00367   /* Main event loop */
00368   do {
00369     switch (run_state) {
00370       case STATE_STOPPED:
00371       case STATE_PAUSED:
00372         /* skip the source scan and yield */
00373         status = cm_yield(500);
00374         if (wheel) {
00375           printf("...%c Snoring\r", bars[i_bar++ % 4]);
00376           fflush(stdout);
00377         }
00378         break;
00379       case STATE_RUNNING:
00380         status = source_scan(equipment[0].format, eq_info);
00381         switch (status) {
00382             case BM_ASYNC_RETURN:  // No event found for now, Check for timeout 
00383               for (fragn = 0; fragn < nfragment; fragn++) {
00384                 if (ebch[fragn].timeout > TIMEOUT) {        /* Timeout */
00385                   if (stop_requested) {                     /* Stop */
00386                     if (debug) printf("Stop requested on timeout %d\n", status);
00387                       status = close_buffers();
00388                     break;
00389                   } 
00390                   else {         /* No stop requested  but timeout */
00391                     if (wheel) {
00392                       printf("...%c Timoing on %1.0lf\r", bars[i_bar++ % 4],
00393                         eq->stats.events_sent);
00394                       fflush(stdout);
00395                       status = cm_yield(50);
00396                     }
00397                   }
00398                 }
00399                 //else { /* No timeout loop back */
00400               } // for loop over all fragments
00401               break;
00402             case EB_ERROR:
00403             case EB_USER_ERROR:
00404               abort_requested = TRUE;
00405               if (status == EB_USER_ERROR)
00406                 cm_msg(MTALK, "EBuilder", "%s: Error signaled by user code - stopping run...", full_frontend_name);
00407               else
00408                 cm_msg(MTALK, "EBuilder", "%s: Event mismatch - Stopping run...", full_frontend_name);
00409               if (cm_transition(TR_STOP, 0, NULL, 0, ASYNC, 0) != CM_SUCCESS) {
00410                 cm_msg(MERROR, "EBuilder", "%s: Stop Transition request failed", full_frontend_name);
00411                 return status;
00412               }
00413               if (debug) printf("Stop requested on Error %d\n", status);
00414               status = close_buffers();
00415               return status;
00416               break;
00417             case EB_SUCCESS:
00418             case EB_SKIP:
00419               //   Normal path if event has been assembled
00420               //   No yield in this case.
00421               break;
00422             default:
00423               cm_msg(MERROR, "Source_scan", "unexpected return %d", status);
00424               status = SS_ABORT;
00425               }  // switch scan_source
00426         break;
00427     }
00428     /* EB job done, update statistics if its time */
00429     /* Check if it's time to do statistics job */
00430     if ((actual_millitime = ss_millitime()) - last_time > 1000) {
00431       /* Force event to appear at the destination if Ebuilder is remote */
00432       rpc_flush_event();
00433       /* Force event ot appear at the destination if Ebuilder is local */
00434       bm_flush_cache(equipment[0].buffer_handle, ASYNC);
00435 
00436       status = cm_yield(10);
00437 
00438       eq = &equipment[0];
00439       eq->stats.events_sent += eq->events_sent;
00440       eq->stats.events_per_sec =
00441         eq->events_sent / ((actual_millitime - last_time) / 1000.0);
00442       eq->stats.kbytes_per_sec =
00443         eq->bytes_sent / 1024.0 / ((actual_millitime - last_time) /
00444         1000.0);
00445       eq->bytes_sent = 0;
00446       eq->events_sent = 0;
00447       /* update destination statistics */
00448       db_send_changed_records();
00449       /* Keep track of last ODB update */
00450       last_time = ss_millitime();
00451     }
00452   } while (status != RPC_SHUTDOWN && status != SS_ABORT);
00453 
00454   return status;
00455   }
00456 
00457 /********************************************************************/
00458 INT eb_mfragment_add(char *pdest, char *psrce, INT * size)
00459 {
00460    BANK_HEADER *psbh, *pdbh;
00461    char *psdata, *pddata;
00462    INT bksize;
00463 
00464    /* Condition for new EVENT the data_size should be ZERO */
00465    *size = ((EVENT_HEADER *) pdest)->data_size;
00466 
00467    /* destination pointer */
00468    pddata = pdest + *size + sizeof(EVENT_HEADER);
00469 
00470    if (*size) {
00471       /* NOT the first fragment */
00472 
00473       /* Swap event source if necessary */
00474       psbh = (BANK_HEADER *) (((EVENT_HEADER *) psrce) + 1);
00475       bk_swap(psbh, FALSE);
00476 
00477       /* source pointer */
00478       psbh = (BANK_HEADER *) (((EVENT_HEADER *) psrce) + 1);
00479       psdata = (char *) (psbh + 1);
00480 
00481       /* copy all banks without the bank header */
00482       bksize = psbh->data_size;
00483 
00484       /* copy */
00485       memcpy(pddata, psdata, bksize);
00486 
00487       /* update event size */
00488       ((EVENT_HEADER *) pdest)->data_size += bksize;
00489 
00490       /* update bank size */
00491       pdbh = (BANK_HEADER *) (((EVENT_HEADER *) pdest) + 1);
00492       pdbh->data_size += bksize;
00493 
00494       *size = ((EVENT_HEADER *) pdest)->data_size;
00495    } else {
00496       /* First event without the event header but with the 
00497          bank header as the size is zero */
00498       *size = ((EVENT_HEADER *) psrce)->data_size;
00499 
00500       /* Swap event if necessary */
00501       psbh = (BANK_HEADER *) (((EVENT_HEADER *) psrce) + 1);
00502       bk_swap(psbh, FALSE);
00503 
00504       /* copy first fragment */
00505       memcpy(pddata, psbh, *size);
00506 
00507       /* update destination event size */
00508       ((EVENT_HEADER *) pdest)->data_size = *size;
00509    }
00510    return CM_SUCCESS;
00511 }
00512 
00513 /*--------------------------------------------------------------------*/
00514 INT eb_yfragment_add(char *pdest, char *psrce, INT * size)
00515 {
00516    /* pdest : EVENT_HEADER pointer
00517       psrce : EVENT_HEADER pointer
00518       Keep pbkh for later incrementation
00519     */
00520    char *psdata, *pddata;
00521    DWORD *pslrl, *pdlrl;
00522    INT i4frgsize, i1frgsize, status;
00523 
00524    /* Condition for new EVENT the data_size should be ZERO */
00525    *size = ((EVENT_HEADER *) pdest)->data_size;
00526 
00527    /* destination pointer skip the header as it has been already
00528       composed and the usere may have modified it on purpose (Midas Control) */
00529    pddata = pdest + *size + sizeof(EVENT_HEADER);
00530 
00531    /* the Midas header is present for logger */
00532    if (*size) {                 /* already filled with a fragment */
00533 
00534       /* source pointer: number of DWORD (lrl included) */
00535       pslrl = (DWORD *) (((EVENT_HEADER *) psrce) + 1);
00536 
00537       /* Swap event if necessary */
00538       status = ybos_event_swap(pslrl);
00539 
00540       /* copy done in bytes, do not include LRL */
00541       psdata = (char *) (pslrl + 1);
00542 
00543       /* copy size in I*4 (lrl included, remove it) */
00544       i4frgsize = (*pslrl);
00545       i1frgsize = 4 * i4frgsize;
00546 
00547       /* append fragment */
00548       memcpy(pddata, psdata, i1frgsize);
00549 
00550       /* update Midas header event size */
00551       ((EVENT_HEADER *) pdest)->data_size += i1frgsize;
00552 
00553       /* update LRL size (I*4) */
00554       pdlrl = (DWORD *) (((EVENT_HEADER *) pdest) + 1);
00555       *pdlrl += i4frgsize;
00556 
00557       /* Return event size in bytes */
00558       *size = ((EVENT_HEADER *) pdest)->data_size;
00559    } else {                     /* new destination event */
00560       /* The composed event has already the MIDAS header.
00561          which may have been modified by the user in ebuser.c
00562          Will be stripped by the logger (YBOS).
00563          Copy the first full event ( no EVID suppression )
00564          First event (without the event header) */
00565 
00566       /* source pointer */
00567       pslrl = (DWORD *) (((EVENT_HEADER *) psrce) + 1);
00568 
00569       /* Swap event if necessary */
00570       status = ybos_event_swap(pslrl);
00571 
00572       /* size in byte from the source midas header */
00573       *size = ((EVENT_HEADER *) psrce)->data_size;
00574 
00575       /* copy first fragment */
00576       memcpy(pddata, (char *) pslrl, *size);
00577 
00578       /* update destination Midas header event size */
00579       ((EVENT_HEADER *) pdest)->data_size += *size;
00580 
00581    }
00582    return CM_SUCCESS;
00583 }
00584 
00585 /*--------------------------------------------------------------------*/
00586 INT tr_start(INT rn, char *error)
00587 {
00588   EBUILDER(ebuilder_str);
00589   INT status, size, i;
00590   char   str[128];
00591   KEY    key;
00592   HNDLE  hKey, hEqkey, hEqFRkey;
00593   EQUIPMENT_INFO *eq_info;
00594   
00595 
00596   eq_info = &equipment[0].info;
00597 
00598   /* Get update eq_info from ODB */
00599   sprintf(str, "/Equipment/%s/Common", equipment[0].name);
00600   status = db_find_key(hDB, 0, str, &hKey);
00601   size = sizeof(EQUIPMENT_INFO);
00602   db_get_record(hDB, hKey, eq_info, &size, 0);
00603 
00604   ebset.nfragment = nfragment;
00605 
00606   /* reset serial numbers */
00607   for (i = 0; equipment[i].name[0]; i++) {
00608     equipment[i].serial_number = 1;
00609     equipment[i].subevent_number = 0;
00610     equipment[i].stats.events_sent = 0;
00611     equipment[i].odb_in = equipment[i].odb_out = 0;
00612   }
00613 
00614   /* Get / Set Settings */
00615   sprintf(str, "/Equipment/%s/Settings", equipment[0].name);
00616   if (db_find_key(hDB, 0, str, &hEqkey) != DB_SUCCESS) {
00617     status = db_create_record(hDB, 0, str, strcomb(ebuilder_str));
00618   }
00619 
00620   /* Keep Key on Ebuilder/Settings */
00621   sprintf(str, "/Equipment/%s/Settings", equipment[0].name);
00622   if (db_find_key(hDB, 0, str, &hEqkey) != DB_SUCCESS) {
00623     cm_msg(MINFO, "load_fragment", "/Equipment/%s/Settings not found", equipment[0].name);
00624   }
00625   
00626   /* Update or Create User_field */
00627   size = sizeof(ebset.user_field);
00628   status = db_get_value(hDB, hEqkey, "User Field", ebset.user_field, &size, TID_STRING, TRUE);
00629 
00630   /* Update or Create User_Build */
00631   size = sizeof(ebset.user_build);
00632   status = db_get_value(hDB, hEqkey, "User Build", &ebset.user_build, &size, TID_BOOL, TRUE);
00633 
00634   /* update ODB */
00635   size = sizeof(INT);
00636   status = db_set_value(hDB, hEqkey, "Number of Fragment", &ebset.nfragment, size, 1, TID_INT);  
00637 
00638     /* Create or update the fragment request list */
00639   status = db_find_key(hDB, hEqkey, "Fragment Required", &hEqFRkey);
00640   status = db_get_key (hDB, hEqFRkey, &key);
00641   if (key.num_values != ebset.nfragment) {
00642     cm_msg(MINFO, "mevb", "Number of Fragment mismatch ODB:%d - CUR:%d", key.num_values, ebset.nfragment);
00643     free (ebset.preqfrag);
00644     size = ebset.nfragment*sizeof(BOOL);
00645     ebset.preqfrag = malloc(size);
00646     for (i=0 ; i<ebset.nfragment ; i++)
00647       ebset.preqfrag[i] = TRUE;
00648     status = db_set_value(hDB, hEqkey, "Fragment Required", ebset.preqfrag, size, ebset.nfragment, TID_BOOL);  
00649   } else {  // Take from ODBedit
00650     size = key.total_size;
00651     free (ebset.preqfrag);
00652     ebset.preqfrag = malloc(size);
00653     status = db_get_data(hDB, hEqFRkey, ebset.preqfrag, &size, TID_BOOL);
00654   }
00655   /* Cleanup fragment flags */
00656   free (ebset.received);
00657   ebset.received = malloc(size);
00658   for (i=0 ; i < ebset.nfragment ; i++) 
00659     ebset.received[i] = FALSE;
00660 
00661   /* Call BOR user function */
00662   status = eb_begin_of_run(run_number, ebset.user_field, error);
00663   if (status != EB_SUCCESS) {
00664     cm_msg(MERROR, "eb_prestart", "run start aborted due to eb_begin_of_run (%d)",
00665       status);
00666     return status;
00667   }
00668 
00669   /* Book all fragment */
00670   status = source_booking();
00671   if (status != SUCCESS)
00672     return status;
00673 
00674   if (!eq_info->enabled) {
00675     cm_msg(MINFO,"ebuilder", "Event Builder disabled");
00676     return CM_SUCCESS;
00677   }
00678 
00679   /* local run state */
00680   run_state = STATE_RUNNING;
00681   run_number = rn;
00682   stop_requested = FALSE;
00683   abort_requested = FALSE;
00684   printf("%s-Starting New Run: %d\n", full_frontend_name, rn);
00685 
00686   /* Reset global trigger mask */
00687   return CM_SUCCESS;
00688 }
00689 
00690 /*--------------------------------------------------------------------*/
00691 INT tr_stop(INT rn, char *error)
00692 {
00693    printf("\n%s-Stopping Run: %d detected\n", full_frontend_name, rn);
00694 
00695    /* local stop */
00696    stop_requested = TRUE;
00697 
00698    /* local stop time */
00699    request_stop_time = ss_millitime();
00700    return CM_SUCCESS;
00701 }
00702 
00703 /*--------------------------------------------------------------------*/
00704 void free_event_buffer(INT nfrag)
00705 {
00706    INT i;
00707    for (i = 0; i < nfrag; i++) {
00708       if (ebch[i].pfragment) {
00709          free(ebch[i].pfragment);
00710          ebch[i].pfragment = NULL;
00711       }
00712    }
00713 }
00714 
00715 /*--------------------------------------------------------------------*/
00716 INT handFlush()
00717 {
00718    int i, size, status;
00719    char strout[256];
00720 
00721    /* Do Hand flush until better way to  garantee the input buffer to be empty */
00722    if (debug)
00723      printf("Hand flushing system buffer... \n");
00724    for (i = 0; i < nfragment; i++) {
00725      do {
00726        if (ebset.preqfrag[i]) { 
00727          size = max_event_size;
00728          status = bm_receive_event(ebch[i].hBuf, ebch[i].pfragment, &size, ASYNC);
00729          if (debug1) {
00730            sprintf(strout,
00731              "booking:Hand flush bm_receive_event[%d] hndle:%d stat:%d  Last Ser:%d",
00732              i, ebch[i].hBuf, status,
00733              ((EVENT_HEADER *) ebch[i].pfragment)->serial_number);
00734            printf("%s\n", strout);
00735          }
00736        }
00737      } while (status == BM_SUCCESS);
00738    }
00739 
00740    /* Empty source buffer */
00741    status = bm_empty_buffers();
00742    if (status != BM_SUCCESS)
00743       cm_msg(MERROR, "handFlush", "bm_empty_buffers failure [%d]", status);
00744    run_state = STATE_STOPPED;
00745    return status;
00746 }
00747 
00748 
00749 /*--------------------------------------------------------------------*/
00750 INT source_booking()
00751 {
00752    INT j, i, status, status1, status2;
00753 
00754    if (debug)
00755       printf("Entering booking\n");
00756 
00757    /* Book all the source channels */
00758    for (i = 0; i < nfragment; i++) {
00759       /* Book only the requested event mask */
00760      if (ebset.preqfrag[i]) {
00761          /* Connect channel to source buffer */
00762          status1 = bm_open_buffer(ebch[i].buffer, EVENT_BUFFER_SIZE, &(ebch[i].hBuf));
00763 
00764          if (debug)
00765            printf("bm_open_buffer frag:%d buf:%s handle:%d stat:%d\n",
00766                    i, ebch[i].buffer, ebch[i].hBuf, status1);
00767          /* Register for specified channel event ID and Trigger mask */
00768          status2 =
00769              bm_request_event(ebch[i].hBuf, ebch[i].event_id,
00770                               ebch[i].trigger_mask, GET_ALL, &ebch[i].req_id, NULL);
00771          if (debug)
00772            printf("bm_request_event frag:%d id:%d msk:%d req_id:%d stat:%d\n",
00773                    i, ebch[i].event_id, ebch[i].trigger_mask, ebch[i].req_id, status2);
00774          if (((status1 != BM_SUCCESS) && (status1 != BM_CREATED)) ||
00775              ((status2 != BM_SUCCESS) && (status2 != BM_CREATED))) {
00776             cm_msg(MERROR, "source_booking",
00777                    "Open buffer/event request failure [%d %d %d]", i, status1, status2);
00778             return BM_CONFLICT;
00779          }
00780 
00781          /* allocate local source event buffer */
00782          if (ebch[i].pfragment)
00783             free(ebch[i].pfragment);
00784          ebch[i].pfragment = (char *) malloc(max_event_size + sizeof(EVENT_HEADER));
00785          if (debug)
00786             printf("malloc pevent frag:%d pevent:%p\n", i, ebch[i].pfragment);
00787          if (ebch[i].pfragment == NULL) {
00788             free_event_buffer(nfragment);
00789             cm_msg(MERROR, "source_booking", "Can't allocate space for buffer");
00790             return BM_NO_MEMORY;
00791          }
00792       }
00793    }
00794 
00795    /* Empty source buffer */
00796    status = bm_empty_buffers();
00797    if (status != BM_SUCCESS) {
00798       cm_msg(MERROR, "source_booking", "bm_empty_buffers failure [%d]", status);
00799       return status;
00800    }
00801 
00802    if (debug) {
00803       printf("bm_empty_buffers stat:%d\n", status);
00804       for (j = 0; j < ebset.nfragment; j++) {
00805          printf(" buff:%s", ebch[j].buffer);
00806          printf(" ser#:%d", ebch[j].serial);
00807          printf(" hbuf:%2d", ebch[j].hBuf);
00808          printf(" rqid:%2d", ebch[j].req_id);
00809          printf(" opst:%d", status1);
00810          printf(" rqst:%d", status2);
00811          printf(" evid:%2d", ebch[j].event_id);
00812          printf(" tmsk:0x%4.4x\n", ebch[j].trigger_mask);
00813       }
00814    }
00815 
00816    return SUCCESS;
00817 }
00818 
00819 /*--------------------------------------------------------------------*/
00820 INT source_unbooking()
00821 {
00822    INT i, status;
00823 
00824    /* Skip unbooking if already done */
00825    if (ebch[0].pfragment == NULL)
00826       return EB_SUCCESS;
00827 
00828    /* unbook all source channels */
00829    for (i = 0; i< nfragment; i++) {
00830       bm_empty_buffers();
00831 
00832       /* Remove event ID registration */
00833       status = bm_delete_request(ebch[i].req_id);
00834       if (debug)
00835          printf("unbook: bm_delete_req[%d] req_id:%d stat:%d\n", i, ebch[i].req_id,
00836                 status);
00837 
00838       /* Close source buffer */
00839       status = bm_close_buffer(ebch[i].hBuf);
00840       if (debug)
00841          printf("unbook: bm_close_buffer[%d] hndle:%d stat:%d\n", i, ebch[i].hBuf,
00842                 status);
00843       if (status != BM_SUCCESS) {
00844          cm_msg(MERROR, "source_unbooking", "Close buffer[%d] stat:", i, status);
00845          return status;
00846       }
00847    }
00848 
00849    /* release local event buffer memory */
00850    free_event_buffer(nfragment);
00851 
00852    return EB_SUCCESS;
00853 }
00854 
00855 /*--------------------------------------------------------------------*/
00856 INT close_buffers(void)
00857 {
00858   INT status;
00859   char error[256];
00860   EQUIPMENT *eq;
00861 
00862   eq = &equipment[0];
00863 
00864   /* Flush local destination cache */
00865   bm_flush_cache(equipment[0].buffer_handle, SYNC);
00866   /* Call user function */
00867   eb_end_of_run(run_number, error);
00868   /* Cleanup buffers */
00869   handFlush();
00870   /* Detach all source from midas */
00871   status = source_unbooking();
00872 
00873   /* Compose message */
00874   stop_time = ss_millitime() - request_stop_time;
00875   sprintf(error, "Run %d Stop after %1.0lf events sent DT:%d[ms]",
00876     run_number, eq->stats.events_sent, stop_time);
00877   cm_msg(MINFO, "EBuilder", "%s", error);
00878 
00879   run_state = STATE_STOPPED;
00880   abort_requested = FALSE;
00881   return status;
00882 }
00883 
00884 /********************************************************************/
00885 /**
00886 Scan all the fragment source once per call.
00887 
00888 -# This will retrieve the full midas event not swapped (except the
00889 MIDAS_HEADER) for each fragment if possible. The fragment will
00890 be stored in the channel event pointer.
00891 -# if after a full nfrag path some frag are still not cellected, it
00892 returns with the frag# missing for timeout check.
00893 -# If ALL fragments are present it will check the midas serial#
00894 for a full match across all the fragments.
00895 -# If the serial check fails it returns with "event mismatch"
00896 and will abort the event builder but not stop the run for now.
00897 -# If the serial check is passed, it will call the user_build function
00898 where the destination event is going to be composed.
00899 
00900 @param fmt Fragment format type 
00901 @param eq_info Equipement pointer
00902 @return   EB_NO_MORE_EVENT, EB_COMPOSE_TIMEOUT
00903 if different then SUCCESS (bm_compose, rpc_sent error)
00904 */
00905 INT source_scan(INT fmt, EQUIPMENT_INFO *eq_info)
00906 {
00907    static char bars[] = "|/-\\";
00908    static int i_bar;
00909    static DWORD serial;
00910    DWORD *plrl;
00911    BOOL   complete;
00912    INT i, status, size;
00913    INT act_size;
00914    BOOL found, event_mismatch;
00915    BANK_HEADER *psbh;
00916 
00917    /* Scan all channels at least once */
00918    for (i = 0; i < nfragment; i++) {
00919       /* Check if current channel needs to be received */
00920      if (ebset.preqfrag[i] && !ebset.received[i]) {
00921          /* Get fragment and store it in ebch[i].pfragment */
00922          size = max_event_size;
00923          status = bm_receive_event(ebch[i].hBuf, ebch[i].pfragment, &size, ASYNC);
00924          switch (status) {
00925          case BM_SUCCESS:      /* event received */
00926             /* Mask event */
00927             ebset.received[i] = TRUE;
00928             /* Keep local serial */
00929             ebch[i].serial = ((EVENT_HEADER *) ebch[i].pfragment)->serial_number;
00930 
00931             /* Swap event depending on data format */
00932             switch (fmt) {
00933             case FORMAT_YBOS:
00934                plrl = (DWORD *) (((EVENT_HEADER *) ebch[i].pfragment) + 1);
00935                ybos_event_swap(plrl);
00936                break;
00937             case FORMAT_MIDAS:
00938                psbh = (BANK_HEADER *) (((EVENT_HEADER *) ebch[i].pfragment) + 1);
00939                bk_swap(psbh, FALSE);
00940                break;
00941             }
00942 
00943             if (debug1) {
00944               printf("SUCC: ch:%d ser:%d rec:%d sz:%d\n", i,
00945                       ebch[i].serial, ebset.received[i], size);
00946             }
00947             break;
00948          case BM_ASYNC_RETURN: /* timeout */
00949             ebch[i].timeout++;
00950             if (debug1) {
00951               printf("ASYNC: ch:%d ser:%d rec:%d sz:%d\n", i,
00952                       ebch[i].serial, ebset.received[i], size);
00953             }
00954             break;
00955          default:              /* Error */
00956             cm_msg(MERROR, "event_scan", "bm_receive_event error %d", status);
00957             return status;
00958             break;
00959          }
00960       }    /* next channel */
00961    }
00962 
00963    /* Check if all fragments have been received */
00964    complete = FALSE;
00965    for (i = 0; i < nfragment;i++) {
00966      if (ebset.preqfrag[i] && !ebset.received[i])
00967        break;
00968    }
00969    if (i == nfragment) {
00970      complete = TRUE;
00971      /* Check if serial matches */
00972      found = event_mismatch = FALSE;
00973      /* Check Serial, mark first serial */
00974      for (i = 0; i < nfragment; i++) {
00975          if (ebset.preqfrag[i] && ebset.received[i] && !found) {
00976             serial = ebch[i].serial;
00977             found = TRUE;
00978          } else {
00979             if (ebset.preqfrag[i] && ebset.received[i] && (serial != ebch[i].serial)) {
00980                /* Event mismatch */
00981                event_mismatch = TRUE;
00982             }
00983          }
00984       }
00985 
00986     /* internal action in case of event mismatch */
00987      if (event_mismatch && debug) {
00988        char str[256];
00989        char strsub[128];
00990        strcpy(str, "event mismatch: ");
00991        for (i = 0; i < nfragment; i++) {
00992          sprintf(strsub, "Ser[%d]:%d ", i, ebch[i].serial);
00993          strcat(str, strsub);
00994        }
00995        printf("event serial mismatch %s\n", str);
00996      }
00997 
00998      /* In any case reset destination buffer */
00999      memset(dest_event, 0, sizeof(EVENT_HEADER));
01000      act_size = 0;
01001 
01002      /* Fill reserved header space of destination event with
01003      final header information */
01004      bm_compose_event((EVENT_HEADER *) dest_event, eq_info->event_id, eq_info->trigger_mask,
01005        act_size, ebch[0].serial);
01006 
01007      /* Pass fragments to user with mismatch flag, for final check before assembly */
01008      status = eb_user(nfragment, event_mismatch, ebch
01009        , (EVENT_HEADER *) dest_event,(void *) ((EVENT_HEADER *) dest_event + 1), &act_size);
01010      if (status != EB_SUCCESS) {
01011        if (status == EB_SKIP) {
01012          /* Reset mask and timeouts as even thave been succesfully send */
01013          for (i = 0; i < nfragment; i++) {
01014            ebch[i].timeout = 0;
01015            ebset.received[i] = FALSE;
01016          }
01017        }
01018        return status;        // Event mark as EB_SKIP or EB_ABORT by user
01019      }
01020 
01021      /* Allow bypass of fragment assembly if user did it on its own */
01022      if (!ebset.user_build) {
01023        for (i = 0; i < nfragment; i++) {
01024          if (ebset.preqfrag[i]) {
01025            status = meb_fragment_add(dest_event, ebch[i].pfragment, &act_size);
01026            if (status != EB_SUCCESS) {
01027              cm_msg(MERROR, "source_scan",
01028                "compose fragment:%d current size:%d (%d)", i, act_size, status);
01029              return EB_ERROR;
01030            }
01031          }
01032        }
01033      }
01034 
01035      /* Overall event to be sent */
01036      act_size = ((EVENT_HEADER *) dest_event)->data_size + sizeof(EVENT_HEADER);
01037 
01038      /* Send event and wait for completion */
01039      status = rpc_send_event(equipment[0].buffer_handle, dest_event, act_size, SYNC);
01040      if (status != BM_SUCCESS) {
01041        if (debug)
01042          printf("rpc_send_event returned error %d, event_size %d\n",
01043          status, act_size);
01044        cm_msg(MERROR, "EBuilder", "%s: rpc_send_event returned error %d", full_frontend_name, status);
01045        return EB_ERROR;
01046      }
01047 
01048      /* Keep track of the total byte count */
01049      equipment[0].bytes_sent += act_size;
01050 
01051      /* update destination event count */
01052      equipment[0].events_sent++;
01053 
01054      /* Reset mask and timeouts as even thave been succesfully send */
01055      for (i = 0; i < nfragment; i++) {
01056        ebch[i].timeout = 0;
01057        ebset.received[i] = FALSE;
01058      }
01059    } // all fragment recieved for this event
01060 
01061    return status;
01062 }
01063 
01064 /*--------------------------------------------------------------------*/
01065 int main(unsigned int argc, char **argv)
01066 {
01067   INT status;
01068   unsigned int i;
01069   BOOL daemon = FALSE;
01070   
01071   /* init structure */
01072   memset(&ebch[0], 0, sizeof(ebch));
01073 
01074   /* set default */
01075   cm_get_environment(host_name, sizeof(host_name), expt_name, sizeof(expt_name));
01076 
01077   /* get parameters */
01078   for (i = 1; i < argc; i++) {
01079     if (argv[i][0] == '-' && argv[i][1] == 'd')
01080       debug = TRUE;
01081     else if (argv[i][0] == '-' && argv[i][1] == 'D')
01082       daemon = TRUE;
01083     else if (argv[i][0] == '-' && argv[i][1] == 'w')
01084       wheel = TRUE;
01085     else if (argv[i][0] == '-') {
01086       if (i + 1 >= argc || argv[i + 1][0] == '-')
01087         goto usage;
01088       if (strncmp(argv[i], "-e", 2) == 0)
01089         strcpy(expt_name, argv[++i]);
01090       else if (strncmp(argv[i], "-h", 2) == 0)
01091         strcpy(host_name, argv[++i]);
01092       else if (strncmp(argv[i], "-b", 2) == 0)
01093         strcpy(buffer_name, argv[++i]);
01094     } else {
01095 usage:
01096       printf("usage: mevb [-h <Hostname>] [-e <Experiment>] -b <buffername> [-d debug]\n");
01097       printf("             -w show wheel -D to start as a daemon\n\n");
01098       return 0;
01099     }
01100   }
01101 
01102   printf("Program mevb version 5 started\n\n");
01103   if (daemon) {
01104     printf("Becoming a daemon...\n");
01105     ss_daemon_init(FALSE);
01106   }
01107 
01108   /* Check buffer arg */
01109   if (buffer_name[0] == 0) {
01110     printf("Buffer name must be specified with -b argument\n");
01111     goto exit;
01112   }
01113 
01114   /* Compose frontend name */
01115    strcpy(full_frontend_name, frontend_name);
01116 
01117   /* Connect to experiment */
01118   status = cm_connect_experiment(host_name, expt_name, full_frontend_name, NULL);
01119   if (status != CM_SUCCESS) {
01120     ss_sleep(5000);
01121     goto exit;
01122   }
01123 
01124   if (debug)
01125     cm_set_watchdog_params(TRUE, 0);
01126 
01127   /* Connect to ODB */
01128   status = cm_get_experiment_database(&hDB, &hKey);
01129   if (status != EB_SUCCESS) {
01130     ss_sleep(5000);
01131     goto exit;
01132   }
01133   
01134   /* check if Ebuilder is already running */
01135   status = cm_exist(full_frontend_name, FALSE);
01136   if (status == CM_SUCCESS) {
01137     cm_msg(MERROR, "Ebuilder", "%s running already!.", full_frontend_name);
01138     cm_disconnect_experiment();
01139     goto exit;
01140   }
01141 
01142   if (ebuilder_init() != SUCCESS) {
01143     cm_disconnect_experiment();
01144     /* let user read message before window might close */
01145     ss_sleep(5000);
01146     goto exit;
01147   }
01148 
01149   /* Register single equipment */
01150   status = register_equipment();
01151   if (status != EB_SUCCESS) {
01152     ss_sleep(5000);
01153     goto exit;
01154   }
01155 
01156   /* Load Fragment info */
01157   status = load_fragment();
01158   if (status != EB_SUCCESS) {
01159     ss_sleep(5000);
01160     goto exit;
01161   }
01162 
01163   /* Register transition for reset counters */
01164   if (cm_register_transition(TR_START, tr_start, 300) != CM_SUCCESS)
01165     return status;
01166   if (cm_register_transition(TR_STOP, tr_stop, 700) != CM_SUCCESS)
01167     goto exit;
01168 
01169   /* Scan fragments... will stay in */
01170   status = scan_fragment();
01171   printf("%s-Out of scan_fragment\n", full_frontend_name);
01172 
01173   /* Detach all source from midas */
01174   printf("%s-Unbooking\n", full_frontend_name);
01175   source_unbooking();
01176   
01177   ebuilder_exit();
01178 
01179 exit:
01180   /* Free local memory */
01181   free_event_buffer(ebset.nfragment);
01182 
01183   /* Clean disconnect from midas */
01184   cm_disconnect_experiment();
01185   return 0;
01186 }

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 - John M O'Donnell - Konstantin Olchanski - Renee Poutissou - Andreas Suter - Jan M.Wouters - Piotr Adam Zolnierczuk