mevb.c

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

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