MIDAS
Loading...
Searching...
No Matches
mfe.cxx
Go to the documentation of this file.
1/********************************************************************\
2
3 Name: mfe.c
4 Created by: Stefan Ritt
5
6 Contents: The system part of the MIDAS frontend. Has to be
7 linked with user code to form a complete frontend
8
9\********************************************************************/
10
11#undef NDEBUG// midas required assert() to be always enabled
12
13#include "mfe.h"
14
15#include "midas.h"
16#include "msystem.h"
17#include "mstrlcpy.h"
18
19#include <assert.h>
20#include <stdio.h>
21
22
23/*------------------------------------------------------------------*/
24
25/* globals */
26
27INT rpc_mode = 1; // 0 for RPC socket, 1 for event socket
28
29#define ODB_UPDATE_TIME 1000 /* 1 seconds for ODB update */
30
31#define DEFAULT_FE_TIMEOUT 10000 /* 10 seconds for watchdog timeout */
32
33#define MAX_N_THREADS 32 /* maximum number of readout threads */
34
35INT run_state = 0; /* STATE_RUNNING, STATE_STOPPED, STATE_PAUSED */
37DWORD actual_time = 0; /* current time in seconds since 1970 */
38DWORD actual_millitime = 0; /* current time in milliseconds */
39DWORD rate_period = 0; /* period in ms for rate calculations */
40
41int gWriteCacheSize = 0; /* remember max write cache size to use in periodic flush buffer */
42
46
48INT optimize = 0; /* set this to one to opimize TCP buffer size */
49INT fe_stop = 0; /* stop switch for VxWorks */
50BOOL debug = 0; /* disable watchdog messages from server */
51DWORD auto_restart = 0; /* restart run after event limit reached stop */
52INT manual_trigger_event_id = 0; /* set from the manual_trigger callback */
53static INT frontend_index = -1; /* frontend index for event building */
54INT verbosity_level = 0; /* can be used by user code for debugging output */
55BOOL lockout_readout_thread = TRUE; /* manual triggers, periodic events and 1Hz flush cache lockout the readout thread */
57
60
67
69
70/* inter-thread communication */
71static int rbh[MAX_N_THREADS];
72std::atomic<bool> _stop_all_threads(false);
73static int _readout_thread(void *param);
75
76void mfe_error_check(void);
77
78static int send_event(INT idx, BOOL manual_trig);
81static void interrupt_routine(void);
82void readout_enable(bool flag);
83bool readout_enabled(void);
84void display(BOOL bInit);
85void rotate_wheel(void);
86BOOL logger_root(void);
87static INT check_polled_events(void);
88static INT check_user_events(void);
89static int flush_user_events(void);
90
91/*------------------------------------------------------------------*/
92
95}
96
98 return rate_period;
99}
100
101/*-- transition callbacks ------------------------------------------*/
102
103/*-- start ---------------------------------------------------------*/
104
105static INT tr_start(INT rn, char *error) {
106 INT i, status;
107
108 /* disable interrupts or readout thread
109 * if somehow it was not stopped from previous run */
111
112 /* flush all buffers with EQ_USER events */
114
115 /* reset serial numbers and statistics */
116 for (i = 0; equipment[i].name[0]; i++) {
117 equipment[i].serial_number = 0;
118 equipment[i].subevent_number = 0;
119 equipment[i].events_collected = 0;
120 equipment[i].stats.events_sent = 0;
121 equipment[i].stats.events_per_sec = 0;
122 equipment[i].stats.kbytes_per_sec = 0;
123 equipment[i].odb_in = equipment[i].odb_out = 0;
124 n_events[i] = 0;
125 }
127
128 status = begin_of_run(rn, error);
129
130 if (status == CM_SUCCESS) {
132 run_number = rn;
133
135
136 if (display_period && !mfe_debug) {
137 ss_printf(14, 2, "Running ");
138 ss_printf(36, 2, "%d", rn);
139 } else
140 printf("Started run %d\n", rn);
141
142 /* enable interrupts or readout thread */
144 }
145
147
148 return status;
149}
150
151/*-- prestop -------------------------------------------------------*/
152
153static INT tr_stop(INT rn, char *error) {
154 INT status, i;
155 EQUIPMENT *eq;
156
157 /* disable interrupts or readout thread */
159
160 status = end_of_run(rn, error);
161
162 /* allow last event to be sent from frontend thread */
163 ss_sleep(100);
164
165 /* check if event(s) happened just before disabling the trigger */
168
169 if (status == CM_SUCCESS) {
170 /* don't send events if already stopped */
173
175 run_number = rn;
176
178 ss_printf(14, 2, "Stopped ");
179 else
180 printf("Run stopped\n");
181 } else
183
184 for (i = 0; equipment[i].name[0]; i++) {
185 /* flush remaining buffered events */
187 if (equipment[i].buffer_handle) {
188 INT err = bm_flush_cache(equipment[i].buffer_handle, BM_WAIT);
189 if (err != BM_SUCCESS) {
190 cm_msg(MERROR, "tr_stop", "bm_flush_cache(BM_WAIT) error %d", err);
191 return err;
192 }
193 }
194 }
195
196 /* update final statistics record in ODB */
197 for (i = 0; equipment[i].name[0]; i++) {
198 eq = &equipment[i];
199 eq->stats.events_sent += eq->events_sent;
200 eq->stats.events_per_sec = 0;
201 eq->stats.kbytes_per_sec = 0;
202 eq->bytes_sent = 0;
203 eq->events_sent = 0;
204 n_events[i] = 0;
205 }
206
209 return status;
210}
211
212/*-- pause ---------------------------------------------------------*/
213
214static INT tr_pause(INT rn, char *error) {
215 INT status;
216
217 /* disable interrupts or readout thread */
219
220 status = pause_run(rn, error);
221
222 if (status == CM_SUCCESS) {
224 run_number = rn;
225
227
229 ss_printf(14, 2, "Paused ");
230 else
231 printf("Paused\n");
232 } else
234
236 return status;
237}
238
239/*-- resume --------------------------------------------------------*/
240
241static INT tr_resume(INT rn, char *error) {
242 INT status;
243
244 status = resume_run(rn, error);
245
246 if (status == CM_SUCCESS) {
248 run_number = rn;
249
251
253 ss_printf(14, 2, "Running ");
254 else
255 printf("Running\n");
256
257 /* enable interrupts or readout thread */
259 }
260
262 return status;
263}
264
265/*------------------------------------------------------------------*/
266
269 return SUCCESS;
270}
271
272/*------------------------------------------------------------------*/
273
274static void eq_common_watcher(INT hDB, INT, INT, void *info) {
275 int status;
276 assert(info != NULL);
277 EQUIPMENT *eq = (EQUIPMENT *) info;
279 std::string path;
280 path += "/Equipment/";
281 path += eq->name;
282 path += "/Common";
283 status = db_find_key(hDB, 0, path.c_str(), &hCommon);
284 if (status != DB_SUCCESS)
285 return;
286 int size = sizeof(eq->info);
288 if (status != DB_SUCCESS) {
289 cm_msg(MINFO, "eq_common_watcher", "db_get_record(%s) status %d", path.c_str(), status);
290 return;
291 }
292}
293
294/*------------------------------------------------------------------*/
295
297 INT idx, size, status;
298 char str[256];
301 HNDLE hKey;
302 BANK_LIST *bank_list;
303 DWORD dummy;
304
305 /* get current ODB run state */
306 size = sizeof(run_state);
308 db_get_value(hDB, 0, "/Runinfo/State", &run_state, &size, TID_INT, TRUE);
309 size = sizeof(run_number);
310 run_number = 1;
311 status = db_get_value(hDB, 0, "/Runinfo/Run number", &run_number, &size, TID_INT, TRUE);
312 assert(status == SUCCESS);
313
314 /* scan EQUIPMENT table from user frontend */
315 for (idx = 0; equipment[idx].name[0]; idx++) {
316 eq_info = &equipment[idx].info;
317 eq_stats = &equipment[idx].stats;
318
319 if (eq_info->event_id == 0) {
320 printf("\nEvent ID 0 for %s not allowed\n", equipment[idx].name);
322 ss_sleep(5000);
323 exit(0);
324 }
325
326 /* init status */
327 equipment[idx].status = FE_SUCCESS;
328
329#pragma GCC diagnostic push
330#pragma GCC diagnostic ignored "-Wformat-nonliteral" // need for snprintf below
331
332 /* check for % in equipment (needed for event building) */
333 if (frontend_index != -1) {
334 /* modify equipment name to <name>xx where xx is the frontend index */
335 if (strchr(equipment[idx].name, '%')) {
338 }
339
340 /* modify event buffer name to <name>xx where xx is the frontend index */
341 if (strchr(eq_info->buffer, '%')) {
342 snprintf(str, sizeof(str), eq_info->buffer, frontend_index);
343 mstrlcpy(eq_info->buffer, str, sizeof(eq_info->buffer));
344 }
345 } else {
346 /* stip %.. */
347 if (strchr(equipment[idx].name, '%'))
348 *strchr(equipment[idx].name, '%') = 0;
349 if (strchr(eq_info->buffer, '%'))
350 *strchr(eq_info->buffer, '%') = 0;
351 }
352#pragma GCC diagnostic pop
353
354 /* check for '${HOSTNAME}' in equipment name, replace with env var (needed for sysmon) */
355 std::string name = equipment[idx].name;
356 size_t namepos = name.find("${HOSTNAME}");
357
358 /* if there is a ${HOSTNAME} ... */
359 if (namepos != std::string::npos) {
360 // Grab text before and after
361 std::string before = name.substr(0, namepos);
362 std::string after = name.substr(namepos + 11);//11 = length of "${HOSTNAME}"
363 // Get local_host_name (ODB entry not set yet)
364 std::string thishost = ss_gethostname();
365 // cut the hostname string at the first '.'
366 size_t p = thishost.find('.');
367 thishost = thishost.substr(0, p == std::string::npos ? thishost.length() : p);
368 name = before;
369 name += thishost;
370 name += after;
371 if (name.length() >= 32) {
372 cm_msg(MERROR, "equipment name too long",
373 "Equipment name %s%s%s too long, trimming down to %d characters",
374 before.c_str(),thishost.c_str(),after.c_str(),
375 32);
376 }
377 mstrlcpy(equipment[idx].name, name.c_str(), 32);
378 printf("\t became:%s\n", equipment[idx].name);
379 }
380
381 sprintf(str, "/Equipment/%s/Common", equipment[idx].name);
382
384 if (status == DB_NO_KEY) {
386 db_find_key(hDB, 0, str, &hKey);
388 if (status != DB_SUCCESS) {
389 printf("ERROR: Cannot create equipment record \"%s\", db_set_record() status %d\n", str, status);
391 ss_sleep(3000);
392 return 0;
393 }
394 } else if (status == DB_STRUCT_MISMATCH) {
395 cm_msg(MINFO, "register_equipment", "Correcting \"%s\", db_check_record() status %d", str, status);
397 } else if (status != DB_SUCCESS) {
398 printf("ERROR: Cannot check equipment record \"%s\", db_check_record() status %d\n", str, status);
400 ss_sleep(3000);
401 exit(0);
402 }
403
404 status = db_find_key(hDB, 0, str, &hKey);
405 if (status != DB_SUCCESS) {
406 printf("ERROR: Cannot find \"%s\", db_find_key() status %d", str, status);
408 ss_sleep(3000);
409 exit(0);
410 }
411
413 if (status != DB_SUCCESS) {
414 printf("ERROR: Cannot check record \"%s\", db_check_record() status %d", str, status);
416 ss_sleep(3000);
417 exit(0);
418 }
419
420 /* set equipment Common from equipment[] list if flag is set in user frontend code */
422 // do not overwrite "enabled" and "hidden" flags, these is always defined in the ODB
425 double prev_event_limit;
426 int size;
427 size = sizeof(prev_enabled);
428 db_get_value(hDB, hKey, "Enabled", &prev_enabled, &size, TID_BOOL, FALSE);
429 size = sizeof(prev_hidden);
430 db_get_value(hDB, hKey, "Hidden", &prev_hidden, &size, TID_BOOL, FALSE);
431 size = sizeof(prev_event_limit);
432 db_get_value(hDB, hKey, "Event limit", &prev_event_limit, &size, TID_DOUBLE, FALSE);
434 if (status != DB_SUCCESS) {
435 printf("ERROR: Cannot set record \"%s\", db_set_record() status %d", str, status);
437 ss_sleep(3000);
438 exit(0);
439 }
440 eq_info->enabled = prev_enabled;
441 db_set_value(hDB, hKey, "Enabled", &prev_enabled, sizeof(prev_enabled), 1, TID_BOOL);
442 eq_info->hidden = prev_hidden;
443 db_set_value(hDB, hKey, "Hidden", &prev_hidden, sizeof(prev_hidden), 1, TID_BOOL);
444 if ((eq_info->eq_type & EQ_SLOW) == 0) {
445 eq_info->event_limit = prev_event_limit;
446 db_set_value(hDB, hKey, "Event limit", &prev_event_limit, sizeof(prev_event_limit), 1, TID_DOUBLE);
447 }
448 } else {
449 size = sizeof(EQUIPMENT_INFO);
450 status = db_get_record(hDB, hKey, eq_info, &size, 0);
451 if (status != DB_SUCCESS) {
452 printf("ERROR: Cannot get record \"%s\", db_get_record() status %d", str, status);
454 ss_sleep(3000);
455 exit(0);
456 }
457 }
458
459 /* open hot link to equipment info */
461 if (status != DB_SUCCESS) {
462 printf("ERROR: Cannot hotlink \"%s\", db_watch() status %d", str, status);
464 ss_sleep(3000);
465 exit(0);
466 }
467
468 if (equal_ustring(eq_info->format, "FIXED"))
469 equipment[idx].format = FORMAT_FIXED;
470 else /* default format is MIDAS */
471 equipment[idx].format = FORMAT_MIDAS;
472
473 size = sizeof(str);
474 status = db_get_value(hDB, hClient, "Host", str, &size, TID_STRING, FALSE);
475 assert(status == DB_SUCCESS);
476 mstrlcpy(eq_info->frontend_host, str, sizeof(eq_info->frontend_host));
477 mstrlcpy(eq_info->frontend_name, full_frontend_name, sizeof(eq_info->frontend_name));
478 mstrlcpy(eq_info->frontend_file_name, frontend_file_name, sizeof(eq_info->frontend_file_name));
479 mstrlcpy(eq_info->status, full_frontend_name, sizeof(eq_info->status));
480 mstrlcat(eq_info->status, "@", sizeof(eq_info->status));
481 mstrlcat(eq_info->status, eq_info->frontend_host, sizeof(eq_info->status));
482 mstrlcpy(eq_info->status_color, "greenLight", sizeof(eq_info->status_color));
483
484 /* update variables in ODB */
486
487 if (status != DB_SUCCESS) {
488 cm_msg(MERROR, "register_equipment", "Cannot update equipment Common, db_set_record() status %d", status);
489 return 0;
490 }
491
492 /* check for consistent common settings */
493 if ((eq_info->read_on & RO_STOPPED) &&
494 (eq_info->eq_type == EQ_POLLED ||
495 eq_info->eq_type == EQ_INTERRUPT ||
496 eq_info->eq_type == EQ_MULTITHREAD ||
497 eq_info->eq_type == EQ_USER)) {
498 cm_msg(MERROR, "register_equipment", "Equipment \"%s\" contains RO_STOPPED or RO_ALWAYS. This can lead to undesired side-effect and should be removed.", equipment[idx].name);
499 }
500
501 /*---- Create variables record ---------------------------------*/
502
503 sprintf(str, "/Equipment/%s/Variables", equipment[idx].name);
504 if (equipment[idx].event_descrip) {
505 if (equipment[idx].format == FORMAT_FIXED)
506 db_check_record(hDB, 0, str, (char *) equipment[idx].event_descrip, TRUE);
507 else {
508 /* create bank descriptions */
509 bank_list = (BANK_LIST *) equipment[idx].event_descrip;
510
511 for (; bank_list->name[0]; bank_list++) {
512 /* mabye needed later...
513 if (bank_list->output_flag == 0)
514 continue;
515 */
516
517 if (bank_list->type == TID_STRUCT) {
518 sprintf(str, "/Equipment/%s/Variables/%s", equipment[idx].name,
519 bank_list->name);
520 status = db_check_record(hDB, 0, str, strcomb1((const char **) bank_list->init_str).c_str(), TRUE);
521 if (status != DB_SUCCESS) {
522 printf("Cannot check/create record \"%s\", status = %d\n", str,
523 status);
524 ss_sleep(3000);
525 }
526 } else {
527 sprintf(str, "/Equipment/%s/Variables/%s", equipment[idx].name,
528 bank_list->name);
529 dummy = 0;
530 db_set_value(hDB, 0, str, &dummy, rpc_tid_size(bank_list->type), 1,
531 bank_list->type);
532 }
533 }
534 }
535 } else
537
538 sprintf(str, "/Equipment/%s/Variables", equipment[idx].name);
539 db_find_key(hDB, 0, str, &hKey);
540 equipment[idx].hkey_variables = hKey;
541
542 /*---- Create and initialize statistics tree -------------------*/
543
544 sprintf(str, "/Equipment/%s/Statistics", equipment[idx].name);
545
547 if (status != DB_SUCCESS) {
548 printf("Cannot create/check statistics record \'%s\', error %d\n", str, status);
549 ss_sleep(3000);
550 }
551
552 status = db_find_key(hDB, 0, str, &hKey);
553 if (status != DB_SUCCESS) {
554 printf("Cannot find statistics record \'%s\', error %d\n", str, status);
555 ss_sleep(3000);
556 }
557
558 eq_stats->events_sent = 0;
559 eq_stats->events_per_sec = 0;
560 eq_stats->kbytes_per_sec = 0;
561
562 /* open hot link to statistics tree */
564 if (status == DB_NO_ACCESS) {
565 /* record is probably still in exclusive access by dead FE, so reset it */
567 if (status != DB_SUCCESS)
568 cm_msg(MERROR, "register_equipment",
569 "Cannot change access mode for record \'%s\', error %d", str, status);
570 else
571 cm_msg(MINFO, "register_equipment", "Recovered access mode for record \'%s\'", str);
573 }
574 if (status != DB_SUCCESS) {
575 cm_msg(MERROR, "register_equipment",
576 "Cannot open statistics record \'%s\', error %d", str, status);
577 ss_sleep(3000);
578 }
579
580 /*---- open event buffer ---------------------------------------*/
581
582 /* check for fragmented event */
583 if (eq_info->eq_type & EQ_FRAGMENTED) {
584 if (frag_buffer == NULL)
586
587 if (frag_buffer == NULL) {
588 cm_msg(MERROR, "register_equipment",
589 "Not enough memory to allocate buffer for fragmented events");
590 return SS_NO_MEMORY;
591 }
592 }
593
594 if (eq_info->buffer[0]) {
595 status = bm_open_buffer(eq_info->buffer, DEFAULT_BUFFER_SIZE, &equipment[idx].buffer_handle);
596 if (status != BM_SUCCESS && status != BM_CREATED) {
597 cm_msg(MERROR, "register_equipment", "Cannot open event buffer \"%s\" size %d, bm_open_buffer() status %d", eq_info->buffer, DEFAULT_BUFFER_SIZE, status);
598 return 0;
599 }
600 } else
601 equipment[idx].buffer_handle = 0;
602 }
603
604 n_events = (int *) calloc(sizeof(int), idx);
605
606 return SUCCESS;
607}
608
609/*------------------------------------------------------------------*/
610
612 INT idx, i, j, k, n;
613 double count;
614 char str[256];
615 DWORD start_time, delta_time;
618
619 /* scan EQUIPMENT table from user frontend */
620 for (idx = 0; equipment[idx].name[0]; idx++) {
621 eq_info = &equipment[idx].info;
622
623 /*---- initialize interrupt events -----------------------------*/
624
625 if (eq_info->eq_type & EQ_INTERRUPT) {
626 /* install interrupt for interrupt events */
627
628 for (i = 0; equipment[i].name[0]; i++)
629 if (equipment[i].info.eq_type & EQ_POLLED) {
631 cm_msg(MINFO, "initialize_equipment",
632 "Interrupt readout cannot be combined with polled readout");
633 }
634
636 if (eq_info->enabled) {
638
639 /* create ring buffer for inter-thread data transfer */
641
642 /* establish interrupt handler */
645 } else {
646 equipment[idx].status = FE_ERR_DISABLED;
647 cm_msg(MINFO, "initialize_equipment",
648 "Equipment %s disabled in frontend",
650 }
651 }
652 }
653
654 /*---- evaluate polling count ----------------------------------*/
655
656 if (eq_info->eq_type & (EQ_POLLED | EQ_MULTITHREAD)) {
657 if (eq_info->eq_type & EQ_INTERRUPT) {
658 if (eq_info->eq_type & EQ_POLLED)
659 cm_msg(MERROR, "register_equipment",
660 "Equipment \"%s\" cannot be of type EQ_INTERRUPT and EQ_POLLED at the same time",
662 else
663 cm_msg(MERROR, "register_equipment",
664 "Equipment \"%s\" cannot be of type EQ_INTERRUPT and EQ_MULTITHREAD at the same time",
666 return 0;
667 }
668
669 if (polled_eq) {
670 equipment[idx].status = FE_ERR_DISABLED;
671 cm_msg(MINFO, "initialize_equipment",
672 "Defined more than one polled equipment \'%s\' in frontend \'%s\'", equipment[idx].name, frontend_name);
673 } else
675
676 if (display_period)
677 printf("\nCalibrating");
678
679 count = 1;
680 do {
681 if (display_period)
682 printf(".");
683
684 start_time = ss_millitime();
685
687
688 delta_time = ss_millitime() - start_time;
689
690 if (count == 1 && delta_time > eq_info->period * 1.2) {
691 cm_msg(MERROR, "register_equipment", "Polling routine with count=1 takes %d ms", delta_time);
692 ss_sleep(3000);
693 break;
694 }
695
696 if (delta_time > 0)
697 count = count * eq_info->period / delta_time;
698 else
699 count *= 100;
700
701 // avoid overflows
702 if (count > 2147483647.0) {
703 count = 2147483647.0;
704 break;
705 }
706
707 } while (delta_time > eq_info->period * 1.2 || delta_time < eq_info->period * 0.8);
708
709 equipment[idx].poll_count = (INT) count;
710 }
711
712 /*---- initialize multithread events -------------------------*/
713
714 if (eq_info->eq_type & EQ_MULTITHREAD) {
715 /* install interrupt for interrupt events */
716
717 for (i = 0; equipment[i].name[0]; i++)
718 if (equipment[i].info.eq_type & EQ_POLLED) {
719 equipment[idx].status = FE_ERR_DISABLED;
720 cm_msg(MINFO, "initialize_equipment",
721 "Multi-threaded readout cannot be combined with polled readout for equipment \'%s\'", equipment[i].name);
722 }
723
725 if (eq_info->enabled) {
726 if (multithread_eq) {
727 equipment[idx].status = FE_ERR_DISABLED;
728 cm_msg(MINFO, "initialize_equipment",
729 "Defined more than one equipment with multi-threaded readout for equipment \'%s\'", equipment[i].name);
730 } else {
732
733 /* create ring buffer for inter-thread data transfer */
735
736 /* create hardware reading thread */
739 }
740 } else {
741 equipment[idx].status = FE_ERR_DISABLED;
742 cm_msg(MINFO, "initialize_equipment",
743 "Equipment %s disabled in frontend",
745 }
746 }
747 }
748
749 /*---- initialize user events -------------------------------*/
750
751 if (eq_info->eq_type & EQ_USER) {
753 if (!eq_info->enabled) {
754 equipment[idx].status = FE_ERR_DISABLED;
755 cm_msg(MINFO, "initialize_equipment",
756 "Equipment %s disabled in frontend",
758 }
759 }
760 }
761
762 /*---- initialize slow control equipment ---------------------*/
763
764 if (eq_info->eq_type & EQ_SLOW) {
765
766 set_equipment_status(equipment[idx].name, "Initializing...", "yellowLight");
767
768 if (equipment[idx].driver == nullptr) {
769 cm_msg(MERROR, "initialize_equipment", "Found slow control equipment \"%s\" with no device driver list, aborting",
771 return FE_ERR_DRIVER;
772 }
773
774 /* resolve duplicate device names */
775 for (i = 0; equipment[idx].driver[i].name[0]; i++) {
776 equipment[idx].driver[i].pequipment_name = new std::string(equipment[idx].name);
777
778 for (j = i + 1; equipment[idx].driver[j].name[0]; j++)
781 strcpy(str, equipment[idx].driver[i].name);
782 for (k = 0, n = 0; equipment[idx].driver[k].name[0]; k++)
784 //sprintf(equipment[idx].driver[k].name, "%s_%d", str, n++);
787 char tmp[256];
788 sprintf(tmp, "%d", n++);
790 }
791
792 break;
793 }
794 }
795
796 /* loop over equipment list and call class driver's init method */
797 if (eq_info->enabled) {
798 equipment[idx].status = equipment[idx].cd(CMD_INIT, &equipment[idx]);
799
801 strcpy(str, "Ok");
802 else if (equipment[idx].status == FE_ERR_HW)
803 strcpy(str, "Hardware error");
804 else if (equipment[idx].status == FE_ERR_ODB)
805 strcpy(str, "ODB error");
806 else if (equipment[idx].status == FE_ERR_DRIVER)
807 strcpy(str, "Driver error");
809 strcpy(str, "Partially disabled");
810 else
811 strcpy(str, "Error");
812
814 set_equipment_status(equipment[idx].name, str, "greenLight");
816 set_equipment_status(equipment[idx].name, str, "yellowGreenLight");
817 cm_msg(MINFO, "initialize_equipment", "Equipment %s partially disabled", equipment[idx].name);
818 } else {
820 cm_msg(MERROR, "initialize_equipment", "Equipment %s disabled because of %s", equipment[idx].name, str);
821 }
822
823 } else {
824 equipment[idx].status = FE_ERR_DISABLED;
825 set_equipment_status(equipment[idx].name, "Disabled", "yellowLight");
826 }
827
828 /* remember that we have slowcontrol equipment (needed later for scheduler) */
830
831 /* let user read error messages */
833 ss_sleep(3000);
834 }
835
836 /*---- register callback for manual triggered events -----------*/
837 if (eq_info->eq_type & EQ_MANUAL_TRIG) {
838 if (!manual_trig_flag)
840
842 }
843 }
844
845 /* start threads after all equipment has been initialized */
846 for (idx = 0; equipment[idx].name[0]; idx++) {
847 eq_info = &equipment[idx].info;
848
849 if (eq_info->eq_type & EQ_SLOW) {
851 equipment[idx].cd(CMD_START, &equipment[idx]); /* start threads for this equipment */
852 }
853 }
854
855 if (slowcont_eq)
856 cm_msg(MINFO, "initialize_equipment", "Slow control equipment initialized");
857
858 return SUCCESS;
859}
860
861/*------------------------------------------------------------------*/
862
863int set_equipment_status(const char *name, const char *equipment_status, const char *status_class) {
864 int status, idx;
865 char str[256];
866 HNDLE hKey;
867
868 for (idx = 0; equipment[idx].name[0]; idx++)
870 break;
871
873 sprintf(str, "/Equipment/%s/Common", name);
874 db_find_key(hDB, 0, str, &hKey);
875 assert(hKey);
876
877 mstrlcpy(str, equipment_status, sizeof(str));
878 status = db_set_value(hDB, hKey, "Status", str, 256, 1, TID_STRING);
879 assert(status == DB_SUCCESS);
880 mstrlcpy(str, status_class, sizeof(str));
881 status = db_set_value(hDB, hKey, "Status color", str, 32, 1, TID_STRING);
882 assert(status == DB_SUCCESS);
883 }
884
885 return SUCCESS;
886}
887
888/*------------------------------------------------------------------*/
889
890static void update_odb(const EVENT_HEADER *pevent, HNDLE hKey, INT format) {
891 cm_write_event_to_odb(hDB, hKey, pevent, format);
892}
893
894/*------------------------------------------------------------------*/
895
898 EVENT_HEADER *pevent, *pfragment;
899 char *pdata;
900 unsigned char *pd;
901 INT i, status;
902 DWORD sent, size;
903
904 eq_info = &equipment[idx].info;
905
906 /* check for fragmented event */
907 if (eq_info->eq_type & EQ_FRAGMENTED)
908 pevent = (EVENT_HEADER *) frag_buffer;
909 else
910 pevent = (EVENT_HEADER *) event_buffer;
911
912 /* compose MIDAS event header */
913 pevent->event_id = eq_info->event_id;
914 pevent->trigger_mask = eq_info->trigger_mask;
915 pevent->data_size = (INT) manual_trig;
916 pevent->time_stamp = ss_time();
917 pevent->serial_number = equipment[idx].serial_number++;
918
919 equipment[idx].last_called = ss_millitime();
920
921 /* call user readout routine */
922 *((EQUIPMENT **) (pevent + 1)) = &equipment[idx];
923 pevent->data_size = equipment[idx].readout((char *) (pevent + 1), 0);
924
925 /* send event */
926 if (pevent->data_size) {
927 if (eq_info->eq_type & EQ_FRAGMENTED) {
928 /* fragment event */
929 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size_frag) {
930 cm_msg(MERROR, "send_event",
931 "Event size %ld larger than maximum size %d for frag. ev.",
932 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
934 return SS_NO_MEMORY;
935 }
936
937 /* compose fragments */
938 pfragment = (EVENT_HEADER *) event_buffer;
939
940 /* compose MIDAS event header */
941 memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
942 pfragment->event_id |= EVENTID_FRAG1;
943
944 /* store total event size */
945 pd = (unsigned char *) (pfragment + 1);
946 size = pevent->data_size;
947 for (i = 0; i < 4; i++) {
948 pd[i] = (unsigned char) (size & 0xFF); /* little endian, please! */
949 size >>= 8;
950 }
951
952 pfragment->data_size = sizeof(DWORD);
953
954 pdata = (char *) (pevent + 1);
955
956 for (i = 0, sent = 0; sent < pevent->data_size; i++) {
957 if (i > 0) {
958 pfragment = (EVENT_HEADER *) event_buffer;
959
960 /* compose MIDAS event header */
961 memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
962 pfragment->event_id |= EVENTID_FRAG;
963
964 /* copy portion of event */
965 size = pevent->data_size - sent;
966 if (size > max_event_size - sizeof(EVENT_HEADER))
967 size = max_event_size - sizeof(EVENT_HEADER);
968
969 memcpy(pfragment + 1, pdata, size);
970 pfragment->data_size = size;
971 sent += size;
972 pdata += size;
973 }
974
975 /* send event to buffer */
976 if (equipment[idx].buffer_handle) {
977 status = rpc_send_event(equipment[idx].buffer_handle, pfragment,
978 pfragment->data_size + sizeof(EVENT_HEADER), BM_WAIT, rpc_mode);
979 if (status != RPC_SUCCESS) {
980 cm_msg(MERROR, "send_event", "rpc_send_event(BM_WAIT) error %d", status);
981 return status;
982 }
983
984 /* flush events from buffer */
986 }
987 }
988
989 if (equipment[idx].buffer_handle) {
990 /* flush buffer cache on server side */
991 status = bm_flush_cache(equipment[idx].buffer_handle, BM_WAIT);
992 if (status != BM_SUCCESS) {
993 cm_msg(MERROR, "send_event", "bm_flush_cache(BM_WAIT) error %d", status);
994 return status;
995 }
996 }
997 } else {
998 /* send un-fragmented event */
999
1000 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
1001 cm_msg(MERROR, "send_event", "Event size %ld larger than maximum size %d",
1002 (long) (pevent->data_size + sizeof(EVENT_HEADER)), max_event_size);
1003 return SS_NO_MEMORY;
1004 }
1005
1006 /* send event to buffer */
1007 if (equipment[idx].buffer_handle) {
1008 status = rpc_send_event(equipment[idx].buffer_handle, pevent,
1009 pevent->data_size + sizeof(EVENT_HEADER), BM_WAIT, rpc_mode);
1010 if (status != BM_SUCCESS) {
1011 cm_msg(MERROR, "send_event", "bm_send_event(BM_WAIT) error %d", status);
1012 return status;
1013 }
1015 status = bm_flush_cache(equipment[idx].buffer_handle, BM_WAIT);
1016 if (status != BM_SUCCESS) {
1017 cm_msg(MERROR, "send_event", "bm_flush_cache(BM_WAIT) error %d", status);
1018 return status;
1019 }
1020 }
1021
1022 /* send event to ODB if RO_ODB flag is set */
1023 if (eq_info->read_on & RO_ODB) {
1024 update_odb(pevent, equipment[idx].hkey_variables, equipment[idx].format);
1025 equipment[idx].odb_out++;
1026 }
1027 }
1028
1029 equipment[idx].bytes_sent += pevent->data_size + sizeof(EVENT_HEADER);
1030 equipment[idx].events_sent++;
1031 } else
1032 equipment[idx].serial_number--;
1033
1034 for (i = 0; equipment[i].name[0]; i++)
1035 if (equipment[i].buffer_handle) {
1036 status = bm_flush_cache(equipment[i].buffer_handle, BM_WAIT);
1037 if (status != BM_SUCCESS) {
1038 cm_msg(MERROR, "send_event", "bm_flush_cache(BM_WAIT) error %d", status);
1039 return status;
1040 }
1041 }
1042
1043 return CM_SUCCESS;
1044}
1045
1046/*------------------------------------------------------------------*/
1047
1050 INT i;
1051
1052 for (i = 0; equipment[i].name[0]; i++) {
1053 eq_info = &equipment[i].info;
1054
1055 if (!eq_info->enabled || equipment[i].status != FE_SUCCESS)
1056 continue;
1057
1058 if (transition == TR_START && (eq_info->read_on & RO_BOR) == 0)
1059 continue;
1060 if (transition == TR_STOP && (eq_info->read_on & RO_EOR) == 0)
1061 continue;
1062 if (transition == TR_PAUSE && (eq_info->read_on & RO_PAUSE) == 0)
1063 continue;
1064 if (transition == TR_RESUME && (eq_info->read_on & RO_RESUME) == 0)
1065 continue;
1066
1067 send_event(i, FALSE);
1068 }
1069}
1070
1071/*------------------------------------------------------------------*/
1072
1073static std::atomic<bool> _readout_enabled_flag(false);
1074
1076 return _readout_enabled_flag;
1077}
1078
1081
1082 if (interrupt_eq) {
1083 if (flag)
1085 else
1087 }
1088}
1089
1090/*------------------------------------------------------------------*/
1091
1092static void interrupt_routine(void) {
1093 int status;
1094 EVENT_HEADER *pevent;
1095 void *p;
1096
1097 /* get pointer for upcoming event.
1098 This is a blocking call if no space available */
1099 status = rb_get_wp(get_event_rbh(0), &p, 100000);
1100
1101 if (status == DB_SUCCESS) {
1102 pevent = (EVENT_HEADER *) p;
1103
1104 /* compose MIDAS event header */
1107 pevent->data_size = 0;
1108 pevent->time_stamp = actual_time;
1110
1111 /* call user readout routine */
1112 pevent->data_size = interrupt_eq->readout((char *) (pevent + 1), 0);
1113
1114 /* send event */
1115 if (pevent->data_size) {
1116
1117 /* put event into ring buffer */
1118 rb_increment_wp(get_event_rbh(0), sizeof(EVENT_HEADER) + pevent->data_size);
1119
1120 } else
1122 }
1123}
1124
1125/*------------------------------------------------------------------*/
1126
1127/* routines to be called from user code */
1128
1130 int status;
1131
1132 assert(i < MAX_N_THREADS);
1133 assert(rbh[i] == 0);
1135 assert(status == DB_SUCCESS);
1136 return rbh[i];
1137}
1138
1140 return rbh[i];
1141}
1142
1144 _stop_all_threads = true;
1145}
1146
1150
1152 int i;
1153 for (i = 0; i < MAX_N_THREADS; i++)
1155 return TRUE;
1156 return FALSE;
1157}
1158
1162
1163/*------------------------------------------------------------------*/
1164
1165static int _readout_thread(void *param) {
1166 int status, source;
1167 EVENT_HEADER *pevent;
1168 void *p;
1169
1170 /* indicate activity to framework */
1172
1173 p = param; /* avoid compiler warning */
1174 while (!_stop_all_threads) {
1175 /* obtain buffer space */
1176
1177 status = rb_get_wp(get_event_rbh(0), &p, 0);
1179 break;
1180 if (status == DB_TIMEOUT) {
1181 // printf("readout_thread: Ring buffer is full, waiting for space!\n");
1182 ss_sleep(10);
1183 continue;
1184 }
1185 if (status != DB_SUCCESS)
1186 break;
1187
1188 if (readout_enabled()) {
1189
1190 /* check for new event */
1192
1193 if (source > 0) {
1194
1196 break;
1197
1198 pevent = (EVENT_HEADER *) p;
1199 /* put source at beginning of event, will be overwritten by
1200 user readout code, just a special feature used by some
1201 multi-source applications */
1202 *(INT *) (pevent + 1) = source;
1203
1204 /* compose MIDAS event header */
1207 pevent->data_size = 0;
1208 pevent->time_stamp = actual_time;
1210
1211 /* call user readout routine */
1212 pevent->data_size = multithread_eq->readout((char *) (pevent + 1), 0);
1213
1214 /* check event size */
1215 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
1216 cm_msg(MERROR, "readout_thread",
1217 "Event size %ld larger than maximum size %d",
1218 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1220 assert(FALSE);
1221 }
1222
1223 if (pevent->data_size > 0) {
1224 /* put event into ring buffer */
1225 rb_increment_wp(get_event_rbh(0), sizeof(EVENT_HEADER) + pevent->data_size);
1226 } else
1228 }
1229
1230 } else // readout_enabled
1231 ss_sleep(10);
1232 }
1233
1235
1236 return 0;
1237}
1238
1239/*-- Receive event from readout thread or interrupt routine --------*/
1240
1242 int index, status;
1243 EVENT_HEADER *prb = NULL, *pevent;
1244 void *p;
1245 static unsigned int last_event_time = 0;
1246 static unsigned int last_error = 0;
1247 unsigned int last_serial = 0;
1248
1249 unsigned int serial = eq->events_collected;
1250 if (serial == 0)
1251 last_serial = 0; // BOR
1252
1253 // search all ring buffers for next event
1254 status = 0;
1255 for (index = 0; get_event_rbh(index); index++) {
1256 status = rb_get_rp(get_event_rbh(index), &p, 10);
1257 prb = (EVENT_HEADER *) p;
1258 if (status == DB_SUCCESS)
1259 if (prb->serial_number > last_serial)
1260 last_serial = prb->serial_number;
1261 if (status == DB_SUCCESS && prb->serial_number == serial)
1262 break;
1263 }
1264
1265 if (get_event_rbh(index) == 0) {
1266 if (serial > 0 && last_serial > serial &&
1267 last_event_time > 0 && ss_millitime() > last_event_time + 5000) {
1268 if (ss_time() - last_error > 30) {
1269 last_error = ss_time();
1270 cm_msg(MERROR, "receive_trigger_event",
1271 "Event collector: waiting for event serial %d since %1.1lf seconds, received already serial %d",
1273 }
1274 }
1275 return 0;
1276 }
1277
1279 pevent = prb;
1280
1281 /* send event */
1282 if (pevent->data_size) {
1283 if (eq->buffer_handle) {
1284
1285 /* save event in temporary buffer to push it to the ODB later */
1286 if (eq->info.read_on & RO_ODB)
1287 memcpy(event_buffer, pevent, pevent->data_size + sizeof(EVENT_HEADER));
1288
1289 /* send first event to ODB if logger writes in root format */
1290 if (pevent->serial_number == 0)
1291 if (logger_root())
1292 update_odb(pevent, eq->hkey_variables, eq->format);
1293
1294 status = rpc_send_event(eq->buffer_handle, pevent,
1295 pevent->data_size + sizeof(EVENT_HEADER),
1296 BM_WAIT, rpc_mode);
1297
1298 if (status != SUCCESS) {
1299 cm_msg(MERROR, "receive_trigger_event", "rpc_send_event error %d", status);
1300 return -1;
1301 }
1302
1303 eq->bytes_sent += pevent->data_size + sizeof(EVENT_HEADER);
1304
1305 if (eq->info.num_subevents)
1306 eq->events_sent += eq->subevent_number;
1307 else
1308 eq->events_sent++;
1309
1310 eq->events_collected++;
1311
1312 rotate_wheel();
1313 }
1314 }
1315
1316 rb_increment_rp(get_event_rbh(index), sizeof(EVENT_HEADER) + prb->data_size);
1317 return prb->data_size;
1318}
1319
1320/*------------------------------------------------------------------*/
1321
1322static int flush_user_events() {
1323 int index, status;
1324 EVENT_HEADER *pevent;
1325 void *p;
1326
1327 for (int idx = 0; equipment[idx].name[0]; idx++) {
1329
1330 if (eq->info.eq_type == EQ_USER) {
1331 for (index = 0; get_event_rbh(index); index++) {
1332 do {
1333 status = rb_get_rp(get_event_rbh(index), &p, 10);
1334 pevent = (EVENT_HEADER *) p;
1335 if (status == DB_SUCCESS) {
1337 }
1338 } while (status == DB_SUCCESS);
1339 }
1340 }
1341 }
1342
1343 return FE_SUCCESS;
1344}
1345
1346/*------------------------------------------------------------------*/
1347
1348static int message_print(const char *msg) {
1349 char str[160];
1350
1351 memset(str, ' ', 159);
1352 str[159] = 0;
1353
1354 if (msg[0] == '[')
1355 msg = strchr(msg, ']') + 2;
1356
1357 memcpy(str, msg, strlen(msg));
1358 ss_printf(0, 20, str);
1359
1360 return 0;
1361}
1362
1363/*------------------------------------------------------------------*/
1364
1366 INT i, status;
1368 char str[30];
1369
1370 if (bInit) {
1372
1373 if (host_name[0])
1374 strcpy(str, host_name);
1375 else
1376 strcpy(str, "<local>");
1377
1378 ss_printf(0, 0, "%s connected to %s. Press \"!\" to exit", full_frontend_name, str);
1379 ss_printf(0, 1,
1380 "================================================================================");
1381 ss_printf(0, 2, "Run status: %s",
1382 run_state == STATE_STOPPED ? "Stopped" : run_state == STATE_RUNNING ? "Running"
1383 : "Paused");
1384 ss_printf(25, 2, "Run number %d ", run_number);
1385 ss_printf(0, 3,
1386 "================================================================================");
1387 ss_printf(0, 4,
1388 "Equipment Status Events Events/sec Rate[B/s] ODB->FE FE->ODB");
1389 ss_printf(0, 5,
1390 "--------------------------------------------------------------------------------");
1391 for (i = 0; equipment[i].name[0]; i++)
1392 ss_printf(0, i + 6, "%s", equipment[i].name);
1393 }
1394
1395 /* display time */
1396 time(&full_time);
1397 char ctimebuf[32];
1399 mstrlcpy(str, ctimebuf + 11, sizeof(str));
1400 str[8] = 0;
1401 ss_printf(72, 0, "%s", str);
1402
1403 for (i = 0; equipment[i].name[0]; i++) {
1404 status = equipment[i].status;
1405
1406 if ((status == 0 || status == FE_SUCCESS) && equipment[i].info.enabled)
1407 ss_printf(14, i + 6, "OK ");
1408 else if (!equipment[i].info.enabled)
1409 ss_printf(14, i + 6, "Disabled ");
1410 else if (status == FE_ERR_ODB)
1411 ss_printf(14, i + 6, "ODB Error");
1412 else if (status == FE_ERR_HW)
1413 ss_printf(14, i + 6, "HW Error ");
1414 else if (status == FE_ERR_DISABLED)
1415 ss_printf(14, i + 6, "Disabled ");
1416 else if (status == FE_ERR_DRIVER)
1417 ss_printf(14, i + 6, "Driver err");
1418 else
1419 ss_printf(14, i + 6, "Unknown ");
1420
1421 if (equipment[i].stats.events_sent > 1E9)
1422 ss_printf(25, i + 6, "%1.3lfG ", equipment[i].stats.events_sent / 1E9);
1423 else if (equipment[i].stats.events_sent > 1E6)
1424 ss_printf(25, i + 6, "%1.3lfM ", equipment[i].stats.events_sent / 1E6);
1425 else
1426 ss_printf(25, i + 6, "%1.0lf ", equipment[i].stats.events_sent);
1427
1428 if (equipment[i].stats.events_per_sec > 1E6)
1429 ss_printf(36, i + 6, "%1.3lfM ", equipment[i].stats.events_per_sec / 1E6);
1430 else if (equipment[i].stats.events_per_sec > 1E3)
1431 ss_printf(36, i + 6, "%1.3lfk ", equipment[i].stats.events_per_sec / 1E3);
1432 else
1433 ss_printf(36, i + 6, "%1.1lf ", equipment[i].stats.events_per_sec);
1434
1435 if (equipment[i].stats.kbytes_per_sec > 1E3)
1436 ss_printf(47, i + 6, "%1.3lfM ", equipment[i].stats.kbytes_per_sec / 1E3);
1437 else if (equipment[i].stats.kbytes_per_sec < 1E3)
1438 ss_printf(47, i + 6, "%1.1lf ", equipment[i].stats.kbytes_per_sec * 1E3);
1439 else
1440 ss_printf(47, i + 6, "%1.3lfk ", equipment[i].stats.kbytes_per_sec);
1441
1442 ss_printf(58, i + 6, "%ld ", equipment[i].odb_in);
1443 ss_printf(69, i + 6, "%ld ", equipment[i].odb_out);
1444 }
1445
1446 /* go to next line */
1447 ss_printf(0, i + 6, "");
1448}
1449
1450/*------------------------------------------------------------------*/
1451
1453 INT i;
1455 char str[30];
1456
1457 /* display time */
1458 time(&full_time);
1459 char ctimebuf[32];
1461 mstrlcpy(str, ctimebuf + 11, sizeof(str));
1462 str[8] = 0;
1463 printf("%s ", str);
1464
1465 for (i = 0; equipment[i].name[0]; i++) {
1466 printf(" %s:", equipment[i].name);
1467
1468 if (equipment[i].stats.events_per_sec > 1E6)
1469 printf("%6.3lfM", equipment[i].stats.events_per_sec / 1E6);
1470 else if (equipment[i].stats.events_per_sec > 1E3)
1471 printf("%6.3lfk", equipment[i].stats.events_per_sec / 1E3);
1472 else
1473 printf("%6.1lf ", equipment[i].stats.events_per_sec);
1474 }
1475
1476 /* go to next line */
1477 printf("\n");
1478}
1479
1480/*------------------------------------------------------------------*/
1481
1482void rotate_wheel(void) {
1483 static DWORD last_wheel = 0, wheel_index = 0;
1484 static char wheel_char[] = {'-', '\\', '|', '/'};
1485
1486 if (display_period && !mfe_debug) {
1487 if (ss_millitime() - last_wheel > 300) {
1489 ss_printf(79, 2, "%c", wheel_char[wheel_index]);
1490 wheel_index = (wheel_index + 1) % 4;
1491 }
1492 }
1493}
1494
1495/*------------------------------------------------------------------*/
1496
1498/* check if logger uses ROOT format */
1499{
1500 int size, i, status;
1501 char str[80];
1503
1504 if (db_find_key(hDB, 0, "/Logger/Channels", &hKeyRoot) == DB_SUCCESS) {
1505 for (i = 0;; i++) {
1508 break;
1509
1510 strcpy(str, "MIDAS");
1511 size = sizeof(str);
1512 db_get_value(hDB, hKey, "Settings/Format", str, &size, TID_STRING, TRUE);
1513
1514 if (equal_ustring(str, "ROOT"))
1515 return TRUE;
1516 }
1517 }
1518
1519 return FALSE;
1520}
1521
1522/*------------------------------------------------------------------*/
1523
1526 EQUIPMENT *eq;
1527 EVENT_HEADER *pevent, *pfragment;
1528 DWORD readout_start, sent, size;
1529 INT i, idx, source, events_sent, status;
1530 char *pdata;
1531 unsigned char *pd;
1532
1533 events_sent = 0;
1535
1536 /*---- loop over equipment table -------------------------------*/
1537 for (idx = 0;; idx++) {
1538 eq = &equipment[idx];
1539 eq_info = &eq->info;
1540
1541 /* check if end of equipment list */
1542 if (!eq->name[0])
1543 break;
1544
1545 if (!eq_info->enabled)
1546 continue;
1547
1548 if (eq->status != FE_SUCCESS)
1549 continue;
1550
1551 if ((eq_info->eq_type & EQ_POLLED) == 0)
1552 continue;
1553
1554 /*---- check polled events ----*/
1556 pevent = NULL;
1557
1558 while ((source = poll_event(eq_info->source, eq->poll_count, FALSE)) > 0) {
1559
1560 if (eq_info->eq_type & EQ_FRAGMENTED)
1561 pevent = (EVENT_HEADER *) frag_buffer;
1562 else
1563 pevent = (EVENT_HEADER *) event_buffer;
1564
1565 /* compose MIDAS event header */
1566 pevent->event_id = eq_info->event_id;
1567 pevent->trigger_mask = eq_info->trigger_mask;
1568 pevent->data_size = 0;
1569 pevent->time_stamp = actual_time;
1570 pevent->serial_number = eq->serial_number;
1571
1572 /* put source at beginning of event, will be overwritten by
1573 user readout code, just a special feature used by some
1574 multi-source applications */
1575 *(INT *) (pevent + 1) = source;
1576
1577 if (eq->info.num_subevents) {
1578 eq->subevent_number = 0;
1579 do {
1580 *(INT *) ((char *) (pevent + 1) + pevent->data_size) = source;
1581
1582 /* call user readout routine for subevent indicating offset */
1583 size = eq->readout((char *) (pevent + 1), pevent->data_size);
1584 pevent->data_size += size;
1585 if (size > 0) {
1586 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
1587 cm_msg(MERROR, "check_polled_events",
1588 "Event size %ld larger than maximum size %d",
1589 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1591 }
1592
1593 eq->subevent_number++;
1594 eq->serial_number++;
1595 }
1596
1597 /* wait for next event */
1598 do {
1599 source = poll_event(eq_info->source, eq->poll_count, FALSE);
1600
1601 if (source == FALSE) {
1603
1604 /* repeat no more than period */
1605 if (actual_millitime - readout_start > (DWORD) eq_info->period)
1606 break;
1607 }
1608 } while (source == FALSE);
1609
1610 } while (eq->subevent_number < eq->info.num_subevents && source);
1611
1612 /* notify readout routine about end of super-event */
1613 pevent->data_size = eq->readout((char *) (pevent + 1), -1);
1614 } else {
1615 /* call user readout routine indicating event source */
1616 pevent->data_size = eq->readout((char *) (pevent + 1), 0);
1617
1618 /* check event size */
1619 if (eq_info->eq_type & EQ_FRAGMENTED) {
1620 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size_frag) {
1621 cm_msg(MERROR, "check_polled_events",
1622 "Event size %ld larger than maximum size %d for frag. ev.",
1623 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1625 assert(FALSE);
1626 }
1627 } else {
1628 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
1629 cm_msg(MERROR, "check_polled_events",
1630 "Event size %ld larger than maximum size %d",
1631 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1633 assert(FALSE);
1634 }
1635 }
1636
1637 /* increment serial number if event read out sucessfully */
1638 if (pevent->data_size)
1639 eq->serial_number++;
1640 }
1641
1642 /* send event */
1643 if (pevent->data_size) {
1644
1645 /* check for fragmented event */
1646 if (eq_info->eq_type & EQ_FRAGMENTED) {
1647 /* compose fragments */
1648 pfragment = (EVENT_HEADER *) event_buffer;
1649
1650 /* compose MIDAS event header */
1651 memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
1652 pfragment->event_id |= EVENTID_FRAG1;
1653
1654 /* store total event size */
1655 pd = (unsigned char *) (pfragment + 1);
1656 size = pevent->data_size;
1657 for (i = 0; i < 4; i++) {
1658 pd[i] = (unsigned char) (size & 0xFF); /* little endian, please! */
1659 size >>= 8;
1660 }
1661
1662 pfragment->data_size = sizeof(DWORD);
1663
1664 pdata = (char *) (pevent + 1);
1665
1666 for (i = 0, sent = 0; sent < pevent->data_size; i++) {
1667 if (i > 0) {
1668 pfragment = (EVENT_HEADER *) event_buffer;
1669
1670 /* compose MIDAS event header */
1671 memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
1672 pfragment->event_id |= EVENTID_FRAG;
1673
1674 /* copy portion of event */
1675 size = pevent->data_size - sent;
1676 if (size > max_event_size - sizeof(EVENT_HEADER))
1677 size = max_event_size - sizeof(EVENT_HEADER);
1678
1679 memcpy(pfragment + 1, pdata, size);
1680 pfragment->data_size = size;
1681 sent += size;
1682 pdata += size;
1683 }
1684
1685 /* send event to buffer */
1686 if (equipment[idx].buffer_handle) {
1687 status = rpc_send_event(equipment[idx].buffer_handle, pfragment,
1688 pfragment->data_size + sizeof(EVENT_HEADER), BM_WAIT, rpc_mode);
1689 if (status != RPC_SUCCESS) {
1690 cm_msg(MERROR, "check_polled_events", "rpc_send_event(BM_WAIT) error %d", status);
1691 return status;
1692 }
1693
1694 /* flush events from buffer */
1696 }
1697 }
1698
1699 } else { /*-------------------*/
1700
1701 /* send unfragmented event */
1702
1703 /* send first event to ODB if logger writes in root format */
1704 if (pevent->serial_number == 0)
1705 if (logger_root())
1706 update_odb(pevent, eq->hkey_variables, eq->format);
1707
1708 status = rpc_send_event(eq->buffer_handle, pevent,
1709 pevent->data_size + sizeof(EVENT_HEADER),
1710 BM_WAIT, rpc_mode);
1711
1712 if (status != SUCCESS) {
1713 cm_msg(MERROR, "check_polled_events", "rpc_send_event error %d", status);
1714 break;
1715 }
1716 }
1717
1718 eq->bytes_sent += pevent->data_size + sizeof(EVENT_HEADER);
1719
1720 if (eq->info.num_subevents) {
1721 eq->events_sent += eq->subevent_number;
1722 events_sent += eq->subevent_number;
1723 } else {
1724 eq->events_sent++;
1725 events_sent++;
1726 }
1727
1728 rotate_wheel();
1729 }
1730
1732
1733 /* repeat no more than period */
1734 if (actual_millitime - readout_start > (DWORD) eq_info->period)
1735 break;
1736
1737 /* quit if event limit is reached */
1738 if (eq_info->event_limit > 0 && eq->stats.events_sent + eq->events_sent >= eq_info->event_limit)
1739 break;
1740 }
1741 }
1742
1743 return events_sent;
1744}
1745
1746/*------------------------------------------------------------------*/
1747
1750 EQUIPMENT *eq;
1751 DWORD size;
1752 INT idx, events_sent;
1753
1754 events_sent = 0;
1755
1756 /*---- loop over equipment table -------------------------------*/
1757 for (idx = 0;; idx++) {
1758 eq = &equipment[idx];
1759 eq_info = &eq->info;
1760
1761 /* check if end of equipment list */
1762 if (!eq->name[0])
1763 break;
1764
1765 if (!eq_info->enabled)
1766 continue;
1767
1768 if (eq->status != FE_SUCCESS)
1769 continue;
1770
1771 if ((eq_info->eq_type & (EQ_INTERRUPT | EQ_MULTITHREAD | EQ_USER)) == 0)
1772 continue;
1773
1774 do {
1775 size = receive_trigger_event(eq);
1776 if (size > 0)
1777 events_sent++;
1778 } while (size > 0);
1779 }
1780
1781 return events_sent;
1782}
1783
1784/*------------------------------------------------------------------*/
1785
1786static INT scheduler() {
1788 EQUIPMENT *eq;
1789 EVENT_HEADER *pevent, *pfragment;
1791 readout_start, sent, size, last_time_rate = 0;
1792 INT i, j, idx, status = 0, ch, source, state, old_flag;
1793 char *pdata;
1794 unsigned char *pd;
1796
1797 INT opt_max = 0, opt_index = 0, opt_tcp_size = 128, opt_cnt = 0;
1798 INT err;
1799
1800#ifdef OS_VXWORKS
1802#ifdef PPCxxx
1804#endif
1805#endif
1806
1807 /*----------------- MAIN equipment loop ------------------------------*/
1808
1810
1811 do {
1813 actual_time = ss_time();
1814
1815 /*---- loop over equipment table -------------------------------*/
1816 for (idx = 0;; idx++) {
1817 eq = &equipment[idx];
1818 eq_info = &eq->info;
1819
1820 /* check if end of equipment list */
1821 if (!eq->name[0])
1822 break;
1823
1824 if (!eq_info->enabled)
1825 continue;
1826
1827 if (eq->status != FE_SUCCESS && eq->status != FE_PARTIALLY_DISABLED)
1828 continue;
1829
1830 /*---- call idle routine for slow control equipment ----*/
1831 if ((eq_info->eq_type & EQ_SLOW) && (eq->status == FE_SUCCESS || eq->status == FE_PARTIALLY_DISABLED)) {
1832 if (eq_info->history > 0) {
1833 if (actual_millitime - eq->last_idle >= (DWORD) eq_info->history) {
1834 eq->cd(CMD_IDLE, eq);
1835 eq->last_idle = actual_millitime;
1836 }
1837 } else
1838 eq->cd(CMD_IDLE, eq);
1839 }
1840
1841 if (run_state == STATE_STOPPED && (eq_info->read_on & RO_STOPPED) == 0)
1842 continue;
1843 if (run_state == STATE_PAUSED && (eq_info->read_on & RO_PAUSED) == 0)
1844 continue;
1845 if (run_state == STATE_RUNNING && (eq_info->read_on & RO_RUNNING) == 0)
1846 continue;
1847
1848 /*---- check periodic events ----*/
1849 if ((eq_info->eq_type & EQ_PERIODIC) || (eq_info->eq_type & EQ_SLOW)) {
1850 if (eq_info->period == 0)
1851 continue;
1852
1853 /* check if period over */
1854 if (actual_millitime - eq->last_called >= (DWORD) eq_info->period) {
1855 /* disable interrupts or readout thread during this event */
1859
1860 /* readout and send event */
1862
1863 if (status != CM_SUCCESS) {
1864 cm_msg(MERROR, "scheduler", "send_event error %d", status);
1865 goto net_error;
1866 }
1867
1868 /* re-enable the interrupt or readout thread after readout */
1869 if (old_flag)
1871 }
1872 }
1873
1874 /*---- check polled events ----*/
1875 if (eq_info->eq_type & EQ_POLLED) {
1877 pevent = NULL;
1878
1879 while ((source = poll_event(eq_info->source, eq->poll_count, FALSE)) > 0) {
1880
1881 if (eq_info->eq_type & EQ_FRAGMENTED)
1882 pevent = (EVENT_HEADER *) frag_buffer;
1883 else
1884 pevent = (EVENT_HEADER *) event_buffer;
1885
1886 /* compose MIDAS event header */
1887 pevent->event_id = eq_info->event_id;
1888 pevent->trigger_mask = eq_info->trigger_mask;
1889 pevent->data_size = 0;
1890 pevent->time_stamp = actual_time;
1891 pevent->serial_number = eq->serial_number;
1892
1893 /* put source at beginning of event, will be overwritten by
1894 user readout code, just a special feature used by some
1895 multi-source applications */
1896 *(INT *) (pevent + 1) = source;
1897
1898 if (eq->info.num_subevents) {
1899 eq->subevent_number = 0;
1900 do {
1901 *(INT *) ((char *) (pevent + 1) + pevent->data_size) = source;
1902
1903 /* call user readout routine for subevent indicating offset */
1904 size = eq->readout((char *) (pevent + 1), pevent->data_size);
1905 pevent->data_size += size;
1906 if (size > 0) {
1907 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
1908 cm_msg(MERROR, "scheduler",
1909 "Event size %ld larger than maximum size %d",
1910 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1912 }
1913
1914 eq->subevent_number++;
1915 eq->serial_number++;
1916 }
1917
1918 /* wait for next event */
1919 do {
1920 source = poll_event(eq_info->source, eq->poll_count, FALSE);
1921
1922 if (source == FALSE) {
1924
1925 /* repeat no more than period */
1926 if (actual_millitime - readout_start > (DWORD) eq_info->period)
1927 break;
1928 }
1929 } while (source == FALSE);
1930
1931 } while (eq->subevent_number < eq->info.num_subevents && source);
1932
1933 /* notify readout routine about end of super-event */
1934 pevent->data_size = eq->readout((char *) (pevent + 1), -1);
1935 } else {
1936 /* call user readout routine indicating event source */
1937 pevent->data_size = eq->readout((char *) (pevent + 1), 0);
1938
1939 /* check event size */
1940 if (eq_info->eq_type & EQ_FRAGMENTED) {
1941 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size_frag) {
1942 cm_msg(MERROR, "send_event",
1943 "Event size %ld larger than maximum size %d for frag. ev.",
1944 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1946 pevent->data_size = 0;
1947 }
1948 } else {
1949 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
1950 cm_msg(MERROR, "scheduler",
1951 "Event size %ld larger than maximum size %d",
1952 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1954 pevent->data_size = 0;
1955 }
1956 }
1957
1958 /* increment serial number if event read out sucessfully */
1959 if (pevent->data_size)
1960 eq->serial_number++;
1961 }
1962
1963 /* send event */
1964 if (pevent->data_size) {
1965
1966 /* check for fragmented event */
1967 if (eq_info->eq_type & EQ_FRAGMENTED) {
1968 /* compose fragments */
1969 pfragment = (EVENT_HEADER *) event_buffer;
1970
1971 /* compose MIDAS event header */
1972 memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
1973 pfragment->event_id |= EVENTID_FRAG1;
1974
1975 /* store total event size */
1976 pd = (unsigned char *) (pfragment + 1);
1977 size = pevent->data_size;
1978 for (i = 0; i < 4; i++) {
1979 pd[i] = (unsigned char) (size & 0xFF); /* little endian, please! */
1980 size >>= 8;
1981 }
1982
1983 pfragment->data_size = sizeof(DWORD);
1984
1985 pdata = (char *) (pevent + 1);
1986
1987 for (i = 0, sent = 0; sent < pevent->data_size; i++) {
1988 if (i > 0) {
1989 pfragment = (EVENT_HEADER *) event_buffer;
1990
1991 /* compose MIDAS event header */
1992 memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
1993 pfragment->event_id |= EVENTID_FRAG;
1994
1995 /* copy portion of event */
1996 size = pevent->data_size - sent;
1997 if (size > max_event_size - sizeof(EVENT_HEADER))
1998 size = max_event_size - sizeof(EVENT_HEADER);
1999
2000 memcpy(pfragment + 1, pdata, size);
2001 pfragment->data_size = size;
2002 sent += size;
2003 pdata += size;
2004 }
2005
2006 /* send event to buffer */
2007 if (equipment[idx].buffer_handle) {
2008 status = rpc_send_event(equipment[idx].buffer_handle, pfragment,
2009 pfragment->data_size + sizeof(EVENT_HEADER), BM_WAIT, rpc_mode);
2010 if (status != RPC_SUCCESS) {
2011 cm_msg(MERROR, "scheduler", "rpc_send_event(BM_WAIT) error %d", status);
2012 return status;
2013 }
2014
2015 /* flush events from buffer */
2017 }
2018 }
2019
2020 } else { /*-------------------*/
2021
2022 /* send unfragmented event */
2023
2024 /* send first event to ODB if logger writes in root format */
2025 if (pevent->serial_number == 0)
2026 if (logger_root())
2027 update_odb(pevent, eq->hkey_variables, eq->format);
2028
2029 status = rpc_send_event(eq->buffer_handle, pevent,
2030 pevent->data_size + sizeof(EVENT_HEADER),
2031 BM_WAIT, rpc_mode);
2032
2033 if (status != SUCCESS) {
2034 cm_msg(MERROR, "scheduler", "rpc_send_event error %d", status);
2035 goto net_error;
2036 }
2037 }
2038
2039 eq->bytes_sent += pevent->data_size + sizeof(EVENT_HEADER);
2040
2041 if (eq->info.num_subevents)
2042 eq->events_sent += eq->subevent_number;
2043 else
2044 eq->events_sent++;
2045
2046 rotate_wheel();
2047 }
2048
2050
2051 /* send event to ODB */
2052 if (pevent->data_size && (eq_info->read_on & RO_ODB)) {
2053 if (actual_millitime - eq->last_called > ODB_UPDATE_TIME) {
2054 eq->last_called = actual_millitime;
2055 update_odb(pevent, eq->hkey_variables, eq->format);
2056 eq->odb_out++;
2057 }
2058 }
2059
2060 /* repeat no more than period */
2061 if (actual_millitime - readout_start > (DWORD) eq_info->period)
2062 break;
2063
2064 /* quit if event limit is reached */
2065 if (eq_info->event_limit > 0 && eq->stats.events_sent + eq->events_sent >= eq_info->event_limit)
2066 break;
2067 }
2068 }
2069
2070 /*---- send interrupt events ----*/
2071 if (eq_info->eq_type & (EQ_INTERRUPT | EQ_MULTITHREAD | EQ_USER)) {
2073
2074 do {
2075 size = receive_trigger_event(eq);
2076 if ((int) size == -1)
2077 goto net_error;
2078
2080
2081 /* repeat no more than period */
2082 if (actual_millitime - readout_start > (DWORD) eq_info->period)
2083 break;
2084
2085 /* quit if event limit is reached */
2086 if (eq_info->event_limit > 0 && eq->stats.events_sent + eq->events_sent >= eq_info->event_limit)
2087 break;
2088
2089 } while (size > 0);
2090
2091 /* send event to ODB */
2092 pevent = (EVENT_HEADER *) event_buffer;
2093 if (size > 0 && pevent->data_size && ((eq_info->read_on & RO_ODB) || eq_info->history)) {
2094 if (actual_millitime - eq->last_called > ODB_UPDATE_TIME && pevent != NULL) {
2095 eq->last_called = actual_millitime;
2096 update_odb(pevent, eq->hkey_variables, eq->format);
2097 eq->odb_out++;
2098 }
2099 }
2100 }
2101
2102 /*---- check if event limit is reached ----*/
2103 if (eq_info->eq_type != EQ_SLOW && eq_info->event_limit > 0 && eq->stats.events_sent + eq->events_sent >= eq_info->event_limit && run_state == STATE_RUNNING) {
2104 /* stop run */
2106 if (cm_transition(TR_STOP, 0, str, sizeof(str), TR_SYNC, FALSE) != CM_SUCCESS)
2107 cm_msg(MERROR, "scheduler", "cannot stop run: %s", str);
2108
2109 /* check if auto-restart, main loop will take care of it */
2110 flag = FALSE;
2111 size = sizeof(flag);
2112 db_get_value(hDB, 0, "/Logger/Auto restart", &flag, (INT *) &size, TID_BOOL, TRUE);
2113
2114 if (flag) {
2115 UINT32 delay = 20;
2116 size = sizeof(delay);
2117 db_get_value(hDB, 0, "/Logger/Auto restart delay", &delay, (INT *) &size, TID_UINT32, TRUE);
2118 auto_restart = ss_time() + delay;
2119 }
2120
2121 /* update event display correctly */
2123 }
2124 }
2125
2126 /*---- check for error messages periodically -------------------*/
2128
2129 /*---- call frontend_loop periodically -------------------------*/
2130 if (frontend_call_loop) {
2132 if (status == RPC_SHUTDOWN || status == SS_ABORT) {
2134 break;
2135 }
2136 }
2137
2138 /*---- check for deferred transitions --------------------------*/
2140
2141 /*---- check for manual triggered events -----------------------*/
2146
2147 /* readout and send event */
2149 for (i = 0; equipment[i].name[0]; i++)
2150 if (equipment[i].info.event_id == manual_trigger_event_id) {
2151 status = send_event(i, TRUE);
2152 break;
2153 }
2154
2156
2157 if (status != CM_SUCCESS) {
2158 cm_msg(MERROR, "scheduler", "send_event error %d", status);
2159 goto net_error;
2160 }
2161
2162 /* re-enable the interrupt after periodic */
2163 if (old_flag)
2165 }
2166
2167 int overflow = 0;
2168
2169 for (i = 0; equipment[i].name[0]; i++) {
2170 if (equipment[i].bytes_sent > 0xDFFFFFFF)
2171 overflow = (int) equipment[i].bytes_sent;
2172 }
2173
2174 /*---- calculate rates and update status page periodically -----*/
2178
2179 for (i = 0; equipment[i].name[0]; i++) {
2180 eq = &equipment[i];
2181 eq->stats.events_sent += eq->events_sent;
2182 n_events[i] += (int) eq->events_sent;
2183 eq->events_sent = 0;
2184 }
2185
2186 /* calculate rates after requested period */
2187 if (overflow || (actual_millitime - last_time_rate > (DWORD) get_rate_period())) {
2189 for (i = 0; equipment[i].name[0]; i++) {
2190 eq = &equipment[i];
2191 double e = n_events[i] / ((actual_millitime - last_time_rate) / 1000.0);
2192 eq->stats.events_per_sec = ((int)(e * 100 + 0.5)) / 100.0;
2193
2194 e = eq->bytes_sent / 1000.0 / ((actual_millitime - last_time_rate) / 1000.0);
2195 eq->stats.kbytes_per_sec = ((int)(e * 1000 + 0.5)) / 1000.0;
2196
2197 if ((INT) eq->bytes_sent > max_bytes_per_sec)
2198 max_bytes_per_sec = (INT) eq->bytes_sent;
2199
2200 eq->bytes_sent = 0;
2201 n_events[i] = 0;
2202 }
2203
2205
2207 }
2208
2209 /* tcp buffer size evaluation */
2210 if (optimize) {
2212 ss_printf(0, opt_index, "%6d : %5.1lf %5.1lf", opt_tcp_size,
2213 opt_max / 1000.0, max_bytes_per_sec / 1000.0);
2214 if (++opt_cnt == 10) {
2215 opt_cnt = 0;
2216 opt_max = 0;
2217 opt_index++;
2218 opt_tcp_size = 1 << (opt_index + 7);
2220 if (1 << (opt_index + 7) > 0x8000) {
2221 opt_index = 0;
2222 opt_tcp_size = 1 << 7;
2224 }
2225 }
2226 }
2227
2228 /* propagate changes in equipment to ODB */
2230
2231 if (display_period && !mfe_debug) {
2232 display(FALSE);
2233
2234 /* check keyboard */
2235 ch = 0;
2236 status = 0;
2237 while (ss_kbhit()) {
2238 ch = ss_getchar(0);
2239 if (ch == -1)
2240 ch = getchar();
2241
2242 if (ch == '!')
2244 }
2245
2246 if (ch > 0)
2247 display(TRUE);
2248 if (status == RPC_SHUTDOWN)
2249 break;
2250 }
2251
2252 if (display_period && mfe_debug) {
2254 }
2255
2257 }
2258
2259 /*---- check to flush cache ------------------------------------*/
2260 if (actual_millitime - last_time_flush > 1000) {
2262
2263 /* if cache on server is not filled in one second at current
2264 data rate, flush it now to make events available to consumers */
2265
2270
2271 for (i = 0; equipment[i].name[0]; i++) {
2272 if (equipment[i].buffer_handle) {
2273 /* if the same buffer is open multiple times, only flush it once */
2275 for (j = 0; j < i; j++)
2276 if (equipment[i].buffer_handle == equipment[j].buffer_handle) {
2277 buffer_done = TRUE;
2278 break;
2279 }
2280
2281 //printf("mfe: eq %d, buffer %d, done %d\n", i, equipment[i].buffer_handle, buffer_done);
2282
2283 if (!buffer_done) {
2285 if (rpc_is_remote()) {
2287 } else {
2288 err = bm_flush_cache(equipment[i].buffer_handle, BM_NO_WAIT);
2289 }
2290 if ((err != BM_SUCCESS) && (err != BM_ASYNC_RETURN)) {
2291 cm_msg(MERROR, "scheduler", "bm_flush_cache(BM_NO_WAIT) returned status %d", err);
2292 return err;
2293 }
2294 }
2295 }
2296 }
2297
2298 if (old_flag)
2300 }
2301 }
2302
2303 /*---- check for auto restart --------------------------------*/
2304 if (auto_restart > 0 && ss_time() > auto_restart) {
2305 /* check if really stopped */
2306 size = sizeof(state);
2307 status = db_get_value(hDB, 0, "Runinfo/State", &state, (INT *) &size, TID_INT, TRUE);
2308 if (status != DB_SUCCESS)
2309 cm_msg(MERROR, "scheduler", "cannot get Runinfo/State in database");
2310
2311 if (state == STATE_STOPPED) {
2312 auto_restart = 0;
2313 size = sizeof(run_number);
2314 status =
2315 db_get_value(hDB, 0, "/Runinfo/Run number", &run_number, (INT *) &size, TID_INT,
2316 TRUE);
2317 assert(status == SUCCESS);
2318
2319 if (run_number <= 0) {
2320 cm_msg(MERROR, "main", "aborting on attempt to use invalid run number %d",
2321 run_number);
2322 abort();
2323 }
2324
2325 cm_msg(MTALK, "main", "starting new run");
2327 if (status != CM_SUCCESS)
2328 cm_msg(MERROR, "main", "cannot restart run");
2329 }
2330 }
2331
2332 /*---- check network messages ----------------------------------*/
2334
2335 /* yield 10 ms if no polled equipment present */
2337 status = cm_yield(10);
2338 else {
2339 /* only call yield once every 10ms when running */
2341 status = cm_yield(0);
2343 } else
2345 }
2346 } else
2347 /* when run is stopped or interrupts used,
2348 call yield with 100ms timeout */
2349 status = cm_yield(100);
2350
2351 /* exit for VxWorks */
2352 if (fe_stop)
2354
2355 /* exit if CTRL-C pressed */
2356 if (cm_is_ctrlc_pressed())
2358
2359 } while (status != RPC_SHUTDOWN && status != SS_ABORT);
2360
2361net_error:
2362
2363 return status;
2364}
2365
2366/*------------------------------------------------------------------*/
2367
2371
2372/*------------------------------------------------------------------*/
2373
2374void (*mfe_error_dispatcher)(const char *) = NULL;
2375
2376#define MFE_ERROR_SIZE 10
2380
2381void mfe_set_error(void (*dispatcher)(const char *)) {
2382 int status;
2383
2384 mfe_error_dispatcher = dispatcher;
2386 memset(mfe_error_str, 0, sizeof(mfe_error_str));
2387
2388 if (mfe_mutex == NULL) {
2390 if (status != SS_SUCCESS && status != SS_CREATED)
2391 cm_msg(MERROR, "mfe_set_error", "Cannot create mutex\n");
2392 }
2393}
2394
2395void mfe_error(const char *error)
2396/* central error dispatcher routine which can be called by any device
2397 or class driver */
2398{
2399 if (mfe_mutex == NULL) {
2401 if (status != SS_SUCCESS && status != SS_CREATED) {
2402 cm_msg(MERROR, "mfe_error", "Cannot create mutex\n");
2403 return;
2404 }
2405 }
2406
2407 /* put error into FIFO */
2409 mstrlcpy(mfe_error_str[mfe_error_w], error, 256);
2412}
2413
2425
2426/*------------------------------------------------------------------*/
2427
2428static int _argc = 0;
2429static char **_argv = NULL;
2430
2431void mfe_get_args(int *argc, char ***argv) {
2432 *argc = _argc;
2433 *argv = _argv;
2434}
2435
2436/*------------------------------------------------------------------*/
2437
2438#ifdef OS_VXWORKS
2439int mfe(char *ahost_name, char *aexp_name, BOOL adebug)
2440#else
2441int main(int argc, char *argv[])
2442#endif
2443{
2444 INT status, i, j;
2446
2447 host_name[0] = 0;
2448 exp_name[0] = 0;
2449 daemon_flag = 0;
2450
2451 setbuf(stdout, 0);
2452 setbuf(stderr, 0);
2453
2454#ifdef SIGPIPE
2456#endif
2457
2458#ifdef OS_VXWORKS
2459 if (ahost_name)
2460 strcpy(host_name, ahost_name);
2461 if (aexp_name)
2462 strcpy(exp_name, aexp_name);
2463 mfe_debug = adebug;
2464#else
2465
2466 /* get default from environment */
2468
2469 /* store arguments for user use */
2470 _argc = argc;
2471 _argv = (char **) malloc(sizeof(char *) * argc);
2472 for (i = 0; i < argc; i++) {
2473 _argv[i] = argv[i];
2474 }
2475
2476 /* parse command line parameters */
2477 for (i = 1; i < argc; i++) {
2478 if (argv[i][0] == '-' && argv[i][1] == 'd')
2479 mfe_debug = TRUE;
2480 else if (argv[i][0] == '-' && argv[i][1] == 'D')
2481 daemon_flag = 1;
2482 else if (argv[i][0] == '-' && argv[i][1] == 'O')
2483 daemon_flag = 2;
2484 else if (argv[i][1] == 'v') {
2485 if (i < argc - 1 && atoi(argv[i + 1]) > 0)
2486 verbosity_level = atoi(argv[++i]);
2487 else
2488 verbosity_level = 1;
2489 } else if (argv[i][0] == '-') {
2490 if (i + 1 >= argc || argv[i + 1][0] == '-')
2491 goto usage;
2492 if (argv[i][1] == 'e')
2493 strcpy(exp_name, argv[++i]);
2494 else if (argv[i][1] == 'h')
2495 strcpy(host_name, argv[++i]);
2496 else if (argv[i][1] == 'i')
2497 frontend_index = atoi(argv[++i]);
2498 else if (argv[i][1] == '-') {
2499 usage:
2500 printf("usage: frontend [-h Hostname] [-e Experiment] [-d] [-D] [-O] [-v <n>] [-i <n>]\n");
2501 printf(" [-d] Used to debug the frontend\n");
2502 printf(" [-D] Become a daemon\n");
2503 printf(" [-O] Become a daemon but keep stdout\n");
2504 printf(" [-v <n>] Set verbosity level\n");
2505 printf(" [-i <n>] Set frontend index (used for event building)\n");
2506 return 0;
2507 }
2508 }
2509 }
2510#endif
2511
2512#ifdef OS_VXWORKS
2513 /* override event_buffer_size in case of VxWorks
2514 take remaining free memory and use 20% of it for rb_ */
2515 event_buffer_size = 2 * 10 * (max_event_size + sizeof(EVENT_HEADER) + sizeof(INT));
2516 if (event_buffer_size > memFindMax()) {
2517 cm_msg(MERROR, "mainFE", "Not enough mem space for event size");
2518 return 0;
2519 }
2520 /* takes overall 20% of the available memory resource for rb_() */
2521 event_buffer_size = 0.2 * memFindMax();
2522#endif
2523
2524 /* retrieve frontend index from environment if defined */
2525 if (getenv("MIDAS_FRONTEND_INDEX"))
2526 frontend_index = atoi(getenv("MIDAS_FRONTEND_INDEX"));
2527
2528 /* add frontend index to frontend name if present */
2530 if (frontend_index >= 0)
2532
2533 if (daemon_flag) {
2534 printf("\nBecoming a daemon...\n");
2536 }
2537
2538 /* set default rate period */
2539 set_rate_period(3000);
2540
2541 /* now connect to server */
2542 if (host_name[0]) {
2543 if (exp_name[0])
2544 printf("Connect to experiment %s on host %s...\n", exp_name, host_name);
2545 else
2546 printf("Connect to experiment on host %s...\n", host_name);
2547 } else if (exp_name[0])
2548 printf("Connect to experiment %s...\n", exp_name);
2549 else
2550 printf("Connect to experiment...\n");
2551
2554 if (status != CM_SUCCESS) {
2555 cm_msg(MERROR, "mfe_main", "Cannot connect to experiment \'%s\' on host \'%s\', status %d", exp_name, host_name,
2556 status);
2557 /* let user read message before window might close */
2558 ss_sleep(5000);
2559 return 1;
2560 }
2561
2562 printf("OK\n");
2563
2564 /* allocate buffer space */
2566 if (event_buffer == NULL) {
2567 cm_msg(MERROR, "mfe_main", "mfe: Cannot allocate event buffer of max_event_size %d\n", max_event_size);
2568 return 1;
2569 }
2570
2571 cm_msg(MINFO, "mfe_main", "Frontend \"%s\" started", full_frontend_name);
2572
2573 /* remove any dead frontend */
2575
2576 /* shutdown previous frontend */
2578 if (status == CM_SUCCESS) {
2579 cm_msg(MINFO, "mfe_main", "Previous frontend \"%s\" stopped", full_frontend_name);
2580
2581 /* let user read message */
2582 ss_sleep(3000);
2583
2584 // set full name again, because previously we could have a "1" added to our name
2587 nullptr, DEFAULT_FE_TIMEOUT);
2588 }
2589
2590 /* register transition callbacks */
2595 printf("Failed to start local RPC server");
2597
2598 /* let user read message before window might close */
2599 ss_sleep(5000);
2600 return 1;
2601 }
2603
2605 /* set time from server */
2606#ifdef OS_VXWORKS
2608#endif
2609
2610 /* turn off watchdog if in debug mode */
2611 if (mfe_debug)
2613
2615
2616 /* reqister equipment in ODB */
2617 if (register_equipment() != SUCCESS) {
2618 printf("\n");
2620
2621 /* let user read message before window might close */
2622 ss_sleep(5000);
2623 return 1;
2624 }
2625
2626 /* call user init function */
2627 printf("Init hardware...\n");
2628 if (frontend_init() != SUCCESS) {
2629 printf("\n");
2631 return 1;
2632 }
2633
2634 /* inform user of settings */
2635 printf("Frontend name : %s\n", full_frontend_name);
2636 printf("Event buffer size : %d\n", event_buffer_size);
2637 printf("User max event size : %d\n", max_event_size);
2638 if (max_event_size_frag > 0)
2639 printf("User max frag. size : %d\n", max_event_size_frag);
2640 printf("# of events per buffer : %d\n\n", event_buffer_size / max_event_size);
2641
2642 /* check event and buffer sizes */
2644 cm_msg(MERROR, "mfe_main", "event_buffer_size %d too small for max. event size %d\n", event_buffer_size,
2646 ss_sleep(5000);
2647 return 1;
2648 }
2649
2650 int max_allowed_buffer_size = 1024 * 1024 * 1024; // 1 GB
2651
2652 // Check buffer size. If this value is too large, the end-of-run
2653 // might take quite long to drain a full buffer
2655 cm_msg(MERROR, "mfe_main", "event_buffer_size %d MB exceeds maximum allowed size of %d MB\n",
2656 event_buffer_size / 1024 / 1024, max_allowed_buffer_size / 1024 / 1024);
2657 ss_sleep(5000);
2658 return 1;
2659 }
2660
2661 /* initialize all equipment */
2663 if (status != SUCCESS) {
2664 printf("\n");
2665 cm_msg(MERROR, "mfe_main", "Error status %d received from initialize_equipment, aborting", status);
2667
2668 /* let user read message before window might close */
2669 ss_sleep(5000);
2670 return 1;
2671 }
2672
2673 printf("OK\n");
2674
2675 /* switch on interrupts or readout thread if running */
2676 if (run_state == STATE_RUNNING)
2678
2679 if (!mfe_debug) {
2680 /* initialize ss_getchar */
2681 ss_getchar(0);
2682
2683 /* initialize screen display */
2684 if (display_period) {
2685 ss_sleep(500);
2686 display(TRUE);
2687 }
2688 }
2689
2690 /* set own message print function */
2691 if (display_period && !mfe_debug)
2693
2694 /* call main scheduler loop */
2695 status = scheduler();
2696
2697 /* reset terminal */
2699
2700 if (display_period && !mfe_debug) {
2702 ss_printf(0, 0, "");
2703 }
2704
2705 /* stop readout thread */
2708 while (is_readout_thread_active()) {
2710 ss_sleep(100);
2711 }
2712
2713 /* switch off interrupts and detach */
2714 if (interrupt_eq) {
2717 }
2718
2719 /* call user exit function */
2720 frontend_exit();
2721
2722 /* close slow control drivers */
2723 for (i = 0; equipment[i].name[0]; i++)
2724 if ((equipment[i].info.eq_type & EQ_SLOW) && (equipment[i].status == FE_SUCCESS || equipment[i].status == FE_PARTIALLY_DISABLED)) {
2725
2726 for (j = 0; equipment[i].driver[j].name[0]; j++)
2727 if (equipment[i].driver[j].flags & DF_MULTITHREAD)
2728 break;
2729
2730 /* stop all threads if multithreaded */
2732 equipment[i].cd(CMD_STOP, &equipment[i]); /* stop all threads */
2733 }
2734 for (i = 0; equipment[i].name[0]; i++)
2735 if ((equipment[i].info.eq_type & EQ_SLOW) && (equipment[i].status == FE_SUCCESS || equipment[i].status == FE_PARTIALLY_DISABLED))
2736 equipment[i].cd(CMD_EXIT, &equipment[i]); /* close physical connections */
2737
2738 free(n_events);
2739
2740 if (cm_is_ctrlc_pressed()) {
2741 cm_msg(MINFO, "mfe_main", "Frontend \"%s\" stopped via Ctrl-C", full_frontend_name);
2742 } else if (status == RPC_SHUTDOWN) {
2743 cm_msg(MINFO, "mfe_main", "Frontend \"%s\" stopped via network command", full_frontend_name);
2744 } else if (status != RPC_SHUTDOWN) {
2745 cm_msg(MINFO, "mfe_main", "Frontend \"%s\" stopped because of network error", full_frontend_name);
2746 } else
2747 cm_msg(MINFO, "mfe_main", "Frontend \"%s\" stopped", full_frontend_name);
2748
2749 /* close network connection to server */
2751
2752 return 0;
2753}
2754
2755#ifdef LINK_TEST
2756char *frontend_name;
2757char *frontend_file_name;
2760int max_event_size;
2762int display_period;
2764int frontend_init() { return 0; };
2765int frontend_exit() { return 0; };
2766int begin_of_run(int runno, char *errstr) { return 0; };
2767int end_of_run(int runno, char *errstr) { return 0; };
2768int pause_run(int runno, char *errstr) { return 0; };
2769int resume_run(int runno, char *errstr) { return 0; };
2770int interrupt_configure(INT cmd, INT source, POINTER_T adr) { return 0; };
2771int frontend_loop() { return 0; };
2772int poll_event(INT source, INT count, BOOL test) { return 0; };
2773#endif
2774/* emacs
2775 * Local Variables:
2776 * tab-width: 8
2777 * c-basic-offset: 3
2778 * indent-tabs-mode: nil
2779 * End:
2780 */
#define FALSE
Definition cfortran.h:309
INT transition(INT run_number, char *error)
Definition consume.cxx:35
static void usage()
INT bm_open_buffer(const char *buffer_name, INT buffer_size, INT *buffer_handle)
Definition midas.cxx:6725
INT bm_flush_cache(int buffer_handle, int timeout_msec)
Definition midas.cxx:10215
INT cm_register_transition(INT transition, INT(*func)(INT, char *), INT sequence_number)
Definition midas.cxx:3601
INT cm_shutdown(const char *name, BOOL bUnique)
Definition midas.cxx:7408
INT cm_yield(INT millisec)
Definition midas.cxx:5650
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3011
INT cm_start_watchdog_thread()
Definition midas.cxx:7363
INT cm_set_client_run_state(INT state)
Definition midas.cxx:3791
INT cm_transition(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:5294
INT cm_register_function(INT id, INT(*func)(INT, void **))
Definition midas.cxx:5798
INT cm_connect_experiment1(const char *host_name, const char *default_exp_name, const char *client_name, void(*func)(char *), INT odb_size, DWORD watchdog_timeout)
Definition midas.cxx:2297
INT cm_cleanup(const char *client_name, BOOL ignore_timeout)
Definition midas.cxx:7618
INT cm_set_client_info(HNDLE hDB, HNDLE *hKeyClient, const char *host_name, char *client_name, INT hw_type, const char *password, DWORD watchdog_timeout)
Definition midas.cxx:1893
INT cm_disconnect_experiment(void)
Definition midas.cxx:2846
INT cm_synchronize(DWORD *seconds)
Definition midas.cxx:1369
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition midas.cxx:2134
INT cm_check_deferred_transition()
Definition midas.cxx:3897
BOOL cm_is_ctrlc_pressed()
Definition midas.cxx:5460
INT cm_set_watchdog_params(BOOL call_watchdog, DWORD timeout)
Definition midas.cxx:3283
#define CM_SUCCESS
Definition midas.h:582
#define BM_INVALID_PARAM
Definition midas.h:619
#define BM_ASYNC_RETURN
Definition midas.h:613
#define BM_SUCCESS
Definition midas.h:605
#define BM_CREATED
Definition midas.h:606
#define DB_STRUCT_MISMATCH
Definition midas.h:654
#define DB_NO_ACCESS
Definition midas.h:648
#define DB_SUCCESS
Definition midas.h:631
#define DB_NO_KEY
Definition midas.h:642
#define DB_TIMEOUT
Definition midas.h:655
#define DB_NO_MORE_SUBKEYS
Definition midas.h:646
#define SS_SUCCESS
Definition midas.h:663
#define SS_ABORT
Definition midas.h:677
#define SS_NO_MEMORY
Definition midas.h:665
#define SS_CREATED
Definition midas.h:664
#define RPC_SHUTDOWN
Definition midas.h:707
#define RPC_SUCCESS
Definition midas.h:698
#define FE_SUCCESS
Definition midas.h:717
#define CMD_INIT
Definition midas.h:762
#define CMD_IDLE
Definition midas.h:766
#define CMD_STOP
Definition midas.h:765
#define FE_ERR_ODB
Definition midas.h:718
#define CMD_INTERRUPT_ATTACH
Definition midas.h:822
#define FE_ERR_HW
Definition midas.h:719
#define CMD_INTERRUPT_DISABLE
Definition midas.h:821
#define CMD_INTERRUPT_ENABLE
Definition midas.h:820
#define FE_PARTIALLY_DISABLED
Definition midas.h:722
#define CMD_START
Definition midas.h:764
#define FE_ERR_DRIVER
Definition midas.h:721
#define CMD_EXIT
Definition midas.h:763
#define CMD_INTERRUPT_DETACH
Definition midas.h:823
#define FE_ERR_DISABLED
Definition midas.h:720
unsigned int DWORD
Definition mcstd.h:51
#define SUCCESS
Definition mcstd.h:54
#define RO_STOPPED
Definition midas.h:427
#define TR_RESUME
Definition midas.h:408
#define EQ_POLLED
Definition midas.h:415
#define TR_PAUSE
Definition midas.h:407
#define TID_DOUBLE
Definition midas.h:343
#define TID_KEY
Definition midas.h:349
#define TID_BOOL
Definition midas.h:340
#define TR_START
Definition midas.h:405
#define RO_ODB
Definition midas.h:438
#define EQ_USER
Definition midas.h:422
#define TR_SYNC
Definition midas.h:358
#define MT_ALL
Definition midas.h:549
#define BM_NO_WAIT
Definition midas.h:366
#define FORMAT_FIXED
Definition midas.h:314
#define RO_RESUME
Definition midas.h:432
#define RO_PAUSE
Definition midas.h:431
#define EQ_PERIODIC
Definition midas.h:414
#define RO_EOR
Definition midas.h:430
#define STATE_STOPPED
Definition midas.h:305
#define MINFO
Definition midas.h:560
#define EQ_FRAGMENTED
Definition midas.h:420
#define MODE_DELETE
Definition midas.h:372
#define EQ_MULTITHREAD
Definition midas.h:417
#define RPC_NO_REPLY
Definition midas.h:396
#define RO_BOR
Definition midas.h:429
#define RO_PAUSED
Definition midas.h:428
#define TID_STRUCT
Definition midas.h:348
#define STATE_PAUSED
Definition midas.h:306
#define TID_STRING
Definition midas.h:346
#define MODE_WRITE
Definition midas.h:371
#define MERROR
Definition midas.h:559
#define STATE_RUNNING
Definition midas.h:307
#define MODE_READ
Definition midas.h:370
#define EQ_MANUAL_TRIG
Definition midas.h:419
#define FORMAT_MIDAS
Definition midas.h:311
#define EQ_INTERRUPT
Definition midas.h:416
#define MTALK
Definition midas.h:564
#define TID_UINT32
Definition midas.h:337
#define TID_INT
Definition midas.h:338
#define TR_STOP
Definition midas.h:406
#define BM_WAIT
Definition midas.h:365
#define RO_RUNNING
Definition midas.h:426
#define EQ_SLOW
Definition midas.h:418
#define MAX(a, b)
Definition midas.h:509
std::string ss_gethostname()
Definition system.cxx:5712
INT ss_mutex_release(MUTEX_T *mutex)
Definition system.cxx:3157
BOOL ss_kbhit()
Definition system.cxx:3664
DWORD ss_millitime()
Definition system.cxx:3393
INT ss_getchar(BOOL reset)
Definition system.cxx:7509
INT ss_mutex_create(MUTEX_T **mutex, BOOL recursive)
Definition system.cxx:2941
midas_thread_t ss_thread_create(INT(*thread_func)(void *), void *param)
Definition system.cxx:2310
INT ss_daemon_init(BOOL keep_stdout)
Definition system.cxx:2001
DWORD ss_time()
Definition system.cxx:3462
INT ss_sleep(INT millisec)
Definition system.cxx:3628
void ss_clear_screen()
Definition system.cxx:7305
void ss_printf(INT x, INT y, const char *format,...)
Definition system.cxx:7388
INT ss_mutex_wait_for(MUTEX_T *mutex, INT timeout)
Definition system.cxx:3037
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:915
INT cm_set_msg_print(INT system_mask, INT user_mask, int(*func)(const char *))
Definition midas.cxx:647
BOOL equal_ustring(const char *str1, const char *str2)
Definition odb.cxx:3201
INT db_send_changed_records()
Definition odb.cxx:13778
INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, void *data, INT *buf_size, DWORD type, BOOL create)
Definition odb.cxx:5415
std::string strcomb1(const char **list)
Definition odb.cxx:598
INT db_get_record1(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align, const char *rec_str)
Definition odb.cxx:11806
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3308
INT db_check_record(HNDLE hDB, HNDLE hKey, const char *keyname, const char *rec_str, BOOL correct)
Definition odb.cxx:12973
INT db_get_record(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT align)
Definition odb.cxx:11709
INT db_set_mode(HNDLE hDB, HNDLE hKey, WORD mode, BOOL recurse)
Definition odb.cxx:8027
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:13814
INT db_set_value(HNDLE hDB, HNDLE hKeyRoot, const char *key_name, const void *data, INT data_size, INT num_values, DWORD type)
Definition odb.cxx:5261
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4079
INT db_open_record1(HNDLE hDB, HNDLE hKey, void *ptr, INT rec_size, WORD access_mode, void(*dispatcher)(INT, INT, void *), void *info, const char *rec_str)
Definition odb.cxx:13442
INT db_set_record(HNDLE hDB, HNDLE hKey, void *data, INT buf_size, INT align)
Definition odb.cxx:12292
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5586
INT db_create_record(HNDLE hDB, HNDLE hKey, const char *orig_key_name, const char *init_str)
Definition odb.cxx:12801
int rb_get_rp(int handle, void **p, int millisec)
Definition midas.cxx:17576
int rb_get_wp(int handle, void **p, int millisec)
Definition midas.cxx:17435
int rb_increment_rp(int handle, int size)
Definition midas.cxx:17638
int rb_set_nonblocking()
Definition midas.cxx:17303
int rb_increment_wp(int handle, int size)
Definition midas.cxx:17510
int rb_create(int size, int max_event_size, int *handle)
Definition midas.cxx:17344
bool rpc_is_remote(void)
Definition midas.cxx:12769
INT rpc_get_hw_type()
Definition midas.cxx:12842
INT rpc_call(DWORD routine_id,...)
Definition midas.cxx:13671
INT rpc_flush_event()
Definition midas.cxx:14046
INT rpc_send_event(INT buffer_handle, const EVENT_HEADER *pevent, int unused, INT async_flag, INT mode)
Definition midas.cxx:13909
INT rpc_set_opt_tcp_size(INT tcp_size)
Definition midas.cxx:13872
#define RPC_BM_FLUSH_CACHE
Definition mrpc.h:46
#define RPC_MANUAL_TRIG
Definition mrpc.h:128
INT rpc_tid_size(INT id)
Definition midas.cxx:11765
int main()
Definition hwtest.cxx:23
void ** info
Definition fesimdaq.cxx:41
HNDLE hKey
DWORD n[4]
Definition mana.cxx:247
INT index
Definition mana.cxx:271
char param[10][256]
Definition mana.cxx:250
DWORD delta_time
Definition mchart.cxx:37
double count
Definition mdump.cxx:33
INT i
Definition mdump.cxx:32
std::vector< FMT_ID > eq
Definition mdump.cxx:55
INT get_frontend_index()
Definition mfe.cxx:2368
static int _argc
Definition mfe.cxx:2428
#define DEFAULT_FE_TIMEOUT
Definition mfe.cxx:31
void set_rate_period(int ms)
Definition mfe.cxx:93
static INT tr_resume(INT rn, char *error)
Definition mfe.cxx:241
static int flush_user_events(void)
Definition mfe.cxx:1322
int mfe_error_w
Definition mfe.cxx:2378
char exp_name[NAME_LENGTH]
Definition mfe.cxx:44
INT run_number
Definition mfe.cxx:36
INT optimize
Definition mfe.cxx:48
BOOL logger_root(void)
Definition mfe.cxx:1497
INT rpc_mode
Definition mfe.cxx:27
static INT scheduler()
Definition mfe.cxx:1786
std::atomic< bool > _stop_all_threads(false)
int * n_events
Definition mfe.cxx:68
INT max_bytes_per_sec
Definition mfe.cxx:47
void readout_enable(bool flag)
Definition mfe.cxx:1079
static int rbh[MAX_N_THREADS]
Definition mfe.cxx:71
static std::atomic< bool > _readout_enabled_flag(false)
static void eq_common_watcher(INT hDB, INT, INT, void *info)
Definition mfe.cxx:274
static int message_print(const char *msg)
Definition mfe.cxx:1348
#define ODB_UPDATE_TIME
Definition mfe.cxx:29
static void send_all_periodic_events(INT transition)
Definition mfe.cxx:1048
int get_rate_period()
Definition mfe.cxx:97
BOOL mfe_debug
Definition mfe.cxx:56
BOOL slowcont_eq
Definition mfe.cxx:64
INT manual_trigger(INT, void *prpc_param[])
Definition mfe.cxx:267
static int send_event(INT idx, BOOL manual_trig)
Definition mfe.cxx:896
void display_inline()
Definition mfe.cxx:1452
static INT initialize_equipment(void)
Definition mfe.cxx:611
DWORD rate_period
Definition mfe.cxx:39
void signal_readout_thread_active(int index, int flag)
Definition mfe.cxx:1159
int create_event_rb(int i)
Definition mfe.cxx:1129
int is_readout_thread_active()
Definition mfe.cxx:1151
DWORD actual_time
Definition mfe.cxx:37
MUTEX_T * mfe_mutex
Definition mfe.cxx:2379
void(* mfe_error_dispatcher)(const char *)
Definition mfe.cxx:2374
EQUIPMENT * polled_eq
Definition mfe.cxx:63
int mfe_error_r
Definition mfe.cxx:2378
EQUIPMENT * multithread_eq
Definition mfe.cxx:62
DWORD actual_millitime
Definition mfe.cxx:38
void mfe_get_args(int *argc, char ***argv)
Definition mfe.cxx:2431
DWORD auto_restart
Definition mfe.cxx:51
INT run_state
Definition mfe.cxx:35
BOOL debug
debug printouts
Definition mfe.cxx:50
INT fe_stop
Definition mfe.cxx:49
static int receive_trigger_event(EQUIPMENT *eq)
Definition mfe.cxx:1241
static INT check_user_events(void)
Definition mfe.cxx:1748
INT manual_trigger_event_id
Definition mfe.cxx:52
static INT tr_pause(INT rn, char *error)
Definition mfe.cxx:214
static INT frontend_index
Definition mfe.cxx:53
int gWriteCacheSize
Definition mfe.cxx:41
void mfe_error(const char *error)
Definition mfe.cxx:2395
#define MAX_N_THREADS
Definition mfe.cxx:33
char full_frontend_name[256]
Definition mfe.cxx:45
static INT check_polled_events(void)
Definition mfe.cxx:1524
static INT tr_start(INT rn, char *error)
Definition mfe.cxx:105
static int _readout_thread(void *param)
Definition mfe.cxx:1165
static volatile int readout_thread_active[MAX_N_THREADS]
Definition mfe.cxx:74
HNDLE hDB
main ODB handle
Definition mfe.cxx:58
void rotate_wheel(void)
Definition mfe.cxx:1482
void mfe_set_error(void(*dispatcher)(const char *))
Definition mfe.cxx:2381
static void update_odb(const EVENT_HEADER *pevent, HNDLE hKey, INT format)
Definition mfe.cxx:890
void * event_buffer
Definition mfe.cxx:65
char mfe_error_str[MFE_ERROR_SIZE][256]
Definition mfe.cxx:2377
void mfe_error_check(void)
Definition mfe.cxx:2414
BOOL lockout_readout_thread
Definition mfe.cxx:55
INT verbosity_level
Definition mfe.cxx:54
static INT register_equipment(void)
Definition mfe.cxx:296
static INT tr_stop(INT rn, char *error)
Definition mfe.cxx:153
int set_equipment_status(const char *name, const char *equipment_status, const char *status_class)
Definition mfe.cxx:863
int get_event_rbh(int i)
Definition mfe.cxx:1139
EQUIPMENT * interrupt_eq
Definition mfe.cxx:61
bool readout_enabled(void)
Definition mfe.cxx:1075
void * frag_buffer
Definition mfe.cxx:66
bool is_readout_thread_enabled()
Definition mfe.cxx:1147
void stop_readout_threads()
Definition mfe.cxx:1143
#define MFE_ERROR_SIZE
Definition mfe.cxx:2376
static void interrupt_routine(void)
Definition mfe.cxx:1092
HNDLE hClient
Definition mfe.cxx:59
char host_name[HOST_NAME_LENGTH]
Definition mfe.cxx:43
static char ** _argv
Definition mfe.cxx:2429
const char * frontend_file_name
The frontend file name, don't change it.
Definition feudp.cxx:23
BOOL equipment_common_overwrite
Definition feudp.cxx:50
INT frontend_init(void)
Frontend initialization.
const char * frontend_name
The frontend name (client name) as seen by other MIDAS clients.
Definition feudp.cxx:22
BOOL frontend_call_loop
Definition mfed.cxx:24
INT begin_of_run(__attribute__((unused)) INT rn, __attribute__((unused)) char *error)
Definition mfed.cxx:116
INT max_event_size
Definition mfed.cxx:30
INT frontend_exit()
Frontend exit.
Definition mfed.cxx:100
INT poll_event(__attribute__((unused)) INT source, __attribute__((unused)) INT count, __attribute__((unused)) BOOL test)
Definition mfed.cxx:60
INT event_buffer_size
Definition mfed.cxx:36
INT max_event_size_frag
Definition mfed.cxx:33
INT interrupt_configure(__attribute__((unused)) INT cmd, __attribute__((unused)) INT source, __attribute__((unused)) PTYPE adr)
Definition mfed.cxx:67
INT display_period
Definition mfed.cxx:27
INT end_of_run(__attribute__((unused)) INT rn, __attribute__((unused)) char *error)
Definition mfed.cxx:132
INT frontend_loop()
Frontend loop.
Definition mfed.cxx:182
#define DWORD
Definition mhdump.cxx:31
int cm_write_event_to_odb(HNDLE hDB, HNDLE hKey, const EVENT_HEADER *pevent, INT format)
Definition midas.cxx:17731
INT HNDLE
Definition midas.h:132
#define HOST_NAME_LENGTH
Definition midas.h:273
DWORD BOOL
Definition midas.h:105
#define DF_MULTITHREAD
Definition midas.h:1054
#define NET_TCP_SIZE
Definition midas.h:266
int INT
Definition midas.h:129
#define EVENTID_FRAG
Definition midas.h:907
#define EQUIPMENT_STATISTICS_STR
Definition midas.h:1143
#define DEFAULT_BUFFER_SIZE
Definition midas.h:255
#define CWORD(_i)
Definition midas.h:1623
#define TRUE
Definition midas.h:182
#define EVENTID_FRAG1
Definition midas.h:906
#define DEFAULT_ODB_SIZE
Definition midas.h:270
#define EQUIPMENT_COMMON_STR
Definition midas.h:1111
#define POINTER_T
Definition midas.h:166
INT MUTEX_T
Definition midas.h:237
unsigned int UINT32
Definition midas.h:140
#define TRANSITION_ERROR_STRING_LENGTH
Definition midas.h:280
#define NAME_LENGTH
Definition midas.h:272
#define resume_run
#define driver(name, count)
Definition midas_macro.h:80
#define display(s)
Definition midas_macro.h:25
#define name(x)
Definition midas_macro.h:24
#define pause_run
#define equipment(name, id, type, source, readon, period, readout, cd, driver)
Definition midas_macro.h:60
program test
Definition miniana.f:6
INT serial
Definition minife.c:20
INT rn
Definition mstat.cxx:30
INT j
Definition odbhist.cxx:40
INT k
Definition odbhist.cxx:40
char str[256]
Definition odbhist.cxx:33
DWORD status
Definition odbhist.cxx:39
TH1X EXPRT * h1_book(const char *name, const char *title, int bins, double min, double max)
Definition rmidas.h:24
char name[9]
Definition midas.h:1239
char ** init_str
Definition midas.h:1242
WORD type
Definition midas.h:1240
char status[256]
Definition midas.h:1104
WORD trigger_mask
Definition midas.h:1090
WORD event_id
Definition midas.h:1089
short int event_id
Definition midas.h:852
DWORD data_size
Definition midas.h:856
DWORD serial_number
Definition midas.h:854
DWORD time_stamp
Definition midas.h:855
short int trigger_mask
Definition midas.h:853
DWORD serial_number
Definition midas.h:1185
EQUIPMENT_INFO info
Definition midas.h:1172
char name[NAME_LENGTH]
Definition midas.h:1171
INT(* readout)(char *, INT)
Definition midas.h:1173
DWORD poll_count
Definition midas.h:1181
static double e(void)
Definition tinyexpr.c:136