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);
387 if (eq_info->write_cache_size == 0)
388 eq_info->write_cache_size = MIN_WRITE_CACHE_SIZE;
390 if (status != DB_SUCCESS) {
391 printf("ERROR: Cannot create equipment record \"%s\", db_set_record() status %d\n", str, status);
393 ss_sleep(3000);
394 return 0;
395 }
396 } else if (status == DB_STRUCT_MISMATCH) {
397 cm_msg(MINFO, "register_equipment", "Correcting \"%s\", db_check_record() status %d", str, status);
399 } else if (status != DB_SUCCESS) {
400 printf("ERROR: Cannot check equipment record \"%s\", db_check_record() status %d\n", str, status);
402 ss_sleep(3000);
403 exit(0);
404 }
405
406 status = db_find_key(hDB, 0, str, &hKey);
407 if (status != DB_SUCCESS) {
408 printf("ERROR: Cannot find \"%s\", db_find_key() status %d", str, status);
410 ss_sleep(3000);
411 exit(0);
412 }
413
415 if (status != DB_SUCCESS) {
416 printf("ERROR: Cannot check record \"%s\", db_check_record() status %d", str, status);
418 ss_sleep(3000);
419 exit(0);
420 }
421
422 /* set equipment Common from equipment[] list if flag is set in user frontend code */
424 // do not overwrite "enabled" and "hidden" flags, these is always defined in the ODB
427 double prev_event_limit;
428 int size;
429 size = sizeof(prev_enabled);
430 db_get_value(hDB, hKey, "Enabled", &prev_enabled, &size, TID_BOOL, FALSE);
431 size = sizeof(prev_hidden);
432 db_get_value(hDB, hKey, "Hidden", &prev_hidden, &size, TID_BOOL, FALSE);
433 size = sizeof(prev_event_limit);
434 db_get_value(hDB, hKey, "Event limit", &prev_event_limit, &size, TID_DOUBLE, FALSE);
436 if (status != DB_SUCCESS) {
437 printf("ERROR: Cannot set record \"%s\", db_set_record() status %d", str, status);
439 ss_sleep(3000);
440 exit(0);
441 }
442 eq_info->enabled = prev_enabled;
443 db_set_value(hDB, hKey, "Enabled", &prev_enabled, sizeof(prev_enabled), 1, TID_BOOL);
444 eq_info->hidden = prev_hidden;
445 db_set_value(hDB, hKey, "Hidden", &prev_hidden, sizeof(prev_hidden), 1, TID_BOOL);
446 if ((eq_info->eq_type & EQ_SLOW) == 0) {
447 eq_info->event_limit = prev_event_limit;
448 db_set_value(hDB, hKey, "Event limit", &prev_event_limit, sizeof(prev_event_limit), 1, TID_DOUBLE);
449 }
450 } else {
451 size = sizeof(EQUIPMENT_INFO);
452 status = db_get_record(hDB, hKey, eq_info, &size, 0);
453 if (status != DB_SUCCESS) {
454 printf("ERROR: Cannot get record \"%s\", db_get_record() status %d", str, status);
456 ss_sleep(3000);
457 exit(0);
458 }
459 }
460
461 /* open hot link to equipment info */
463 if (status != DB_SUCCESS) {
464 printf("ERROR: Cannot hotlink \"%s\", db_watch() status %d", str, status);
466 ss_sleep(3000);
467 exit(0);
468 }
469
470 if (equal_ustring(eq_info->format, "FIXED"))
471 equipment[idx].format = FORMAT_FIXED;
472 else /* default format is MIDAS */
473 equipment[idx].format = FORMAT_MIDAS;
474
475 size = sizeof(str);
476 status = db_get_value(hDB, hClient, "Host", str, &size, TID_STRING, FALSE);
477 assert(status == DB_SUCCESS);
478 mstrlcpy(eq_info->frontend_host, str, sizeof(eq_info->frontend_host));
479 mstrlcpy(eq_info->frontend_name, full_frontend_name, sizeof(eq_info->frontend_name));
480 mstrlcpy(eq_info->frontend_file_name, frontend_file_name, sizeof(eq_info->frontend_file_name));
481 mstrlcpy(eq_info->status, full_frontend_name, sizeof(eq_info->status));
482 mstrlcat(eq_info->status, "@", sizeof(eq_info->status));
483 mstrlcat(eq_info->status, eq_info->frontend_host, sizeof(eq_info->status));
484 mstrlcpy(eq_info->status_color, "greenLight", sizeof(eq_info->status_color));
485
486 /* update variables in ODB */
488
489 if (status != DB_SUCCESS) {
490 cm_msg(MERROR, "register_equipment", "Cannot update equipment Common, db_set_record() status %d", status);
491 return 0;
492 }
493
494 /* check for consistent common settings */
495 if ((eq_info->read_on & RO_STOPPED) &&
496 (eq_info->eq_type == EQ_POLLED ||
497 eq_info->eq_type == EQ_INTERRUPT ||
498 eq_info->eq_type == EQ_MULTITHREAD ||
499 eq_info->eq_type == EQ_USER)) {
500 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);
501 }
502
503 /*---- Create variables record ---------------------------------*/
504
505 sprintf(str, "/Equipment/%s/Variables", equipment[idx].name);
506 if (equipment[idx].event_descrip) {
507 if (equipment[idx].format == FORMAT_FIXED)
508 db_check_record(hDB, 0, str, (char *) equipment[idx].event_descrip, TRUE);
509 else {
510 /* create bank descriptions */
511 bank_list = (BANK_LIST *) equipment[idx].event_descrip;
512
513 for (; bank_list->name[0]; bank_list++) {
514 /* mabye needed later...
515 if (bank_list->output_flag == 0)
516 continue;
517 */
518
519 if (bank_list->type == TID_STRUCT) {
520 sprintf(str, "/Equipment/%s/Variables/%s", equipment[idx].name,
521 bank_list->name);
522 status = db_check_record(hDB, 0, str, strcomb1((const char **) bank_list->init_str).c_str(), TRUE);
523 if (status != DB_SUCCESS) {
524 printf("Cannot check/create record \"%s\", status = %d\n", str,
525 status);
526 ss_sleep(3000);
527 }
528 } else {
529 sprintf(str, "/Equipment/%s/Variables/%s", equipment[idx].name,
530 bank_list->name);
531 dummy = 0;
532 db_set_value(hDB, 0, str, &dummy, rpc_tid_size(bank_list->type), 1,
533 bank_list->type);
534 }
535 }
536 }
537 } else
539
540 sprintf(str, "/Equipment/%s/Variables", equipment[idx].name);
541 db_find_key(hDB, 0, str, &hKey);
542 equipment[idx].hkey_variables = hKey;
543
544 /*---- Create and initialize statistics tree -------------------*/
545
546 sprintf(str, "/Equipment/%s/Statistics", equipment[idx].name);
547
549 if (status != DB_SUCCESS) {
550 printf("Cannot create/check statistics record \'%s\', error %d\n", str, status);
551 ss_sleep(3000);
552 }
553
554 status = db_find_key(hDB, 0, str, &hKey);
555 if (status != DB_SUCCESS) {
556 printf("Cannot find statistics record \'%s\', error %d\n", str, status);
557 ss_sleep(3000);
558 }
559
560 eq_stats->events_sent = 0;
561 eq_stats->events_per_sec = 0;
562 eq_stats->kbytes_per_sec = 0;
563
564 /* open hot link to statistics tree */
566 if (status == DB_NO_ACCESS) {
567 /* record is probably still in exclusive access by dead FE, so reset it */
569 if (status != DB_SUCCESS)
570 cm_msg(MERROR, "register_equipment",
571 "Cannot change access mode for record \'%s\', error %d", str, status);
572 else
573 cm_msg(MINFO, "register_equipment", "Recovered access mode for record \'%s\'", str);
575 }
576 if (status != DB_SUCCESS) {
577 cm_msg(MERROR, "register_equipment",
578 "Cannot open statistics record \'%s\', error %d", str, status);
579 ss_sleep(3000);
580 }
581
582 /*---- open event buffer ---------------------------------------*/
583
584 /* check for fragmented event */
585 if (eq_info->eq_type & EQ_FRAGMENTED) {
586 if (frag_buffer == NULL)
588
589 if (frag_buffer == NULL) {
590 cm_msg(MERROR, "register_equipment",
591 "Not enough memory to allocate buffer for fragmented events");
592 return SS_NO_MEMORY;
593 }
594 }
595
596 if (eq_info->buffer[0]) {
597 status = bm_open_buffer(eq_info->buffer, DEFAULT_BUFFER_SIZE, &equipment[idx].buffer_handle);
598 if (status != BM_SUCCESS && status != BM_CREATED) {
599 cm_msg(MERROR, "register_equipment", "Cannot open event buffer \"%s\" size %d, bm_open_buffer() status %d", eq_info->buffer, DEFAULT_BUFFER_SIZE, status);
600 return 0;
601 }
602
603 /* set the default buffer cache size */
604 bm_set_cache_size(equipment[idx].buffer_handle, 0, eq_info->write_cache_size);
605 if (gWriteCacheSize < eq_info->write_cache_size)
606 gWriteCacheSize = eq_info->write_cache_size;
607 } else
608 equipment[idx].buffer_handle = 0;
609 }
610
611 // check for inconsistent write cache size
612 for (idx = 0; equipment[idx].name[0]; idx++) {
613 if (equipment[idx].info.buffer[0]) {
614 int j;
615 for (j = 0; j < idx; j++) {
616 if (equipment[idx].buffer_handle == equipment[j].buffer_handle) {
617 if (equipment[idx].info.write_cache_size != equipment[j].info.write_cache_size) {
618 cm_msg(MERROR, "register_equipment", "Write cache size mismatch for buffer \"%s\": equipment \"%s\" asked for %d, while eqiupment \"%s\" asked for %d", equipment[idx].info.buffer, equipment[idx].name, equipment[idx].info.write_cache_size, equipment[j].name, equipment[j].info.write_cache_size);
619 }
620 }
621 }
622 }
623 }
624
625 n_events = (int *) calloc(sizeof(int), idx);
626
627 return SUCCESS;
628}
629
630/*------------------------------------------------------------------*/
631
633 INT idx, i, j, k, n;
634 double count;
635 char str[256];
636 DWORD start_time, delta_time;
639
640 /* scan EQUIPMENT table from user frontend */
641 for (idx = 0; equipment[idx].name[0]; idx++) {
642 eq_info = &equipment[idx].info;
643
644 /*---- initialize interrupt events -----------------------------*/
645
646 if (eq_info->eq_type & EQ_INTERRUPT) {
647 /* install interrupt for interrupt events */
648
649 for (i = 0; equipment[i].name[0]; i++)
650 if (equipment[i].info.eq_type & EQ_POLLED) {
652 cm_msg(MINFO, "initialize_equipment",
653 "Interrupt readout cannot be combined with polled readout");
654 }
655
657 if (eq_info->enabled) {
659
660 /* create ring buffer for inter-thread data transfer */
662
663 /* establish interrupt handler */
666 } else {
667 equipment[idx].status = FE_ERR_DISABLED;
668 cm_msg(MINFO, "initialize_equipment",
669 "Equipment %s disabled in frontend",
671 }
672 }
673 }
674
675 /*---- evaluate polling count ----------------------------------*/
676
677 if (eq_info->eq_type & (EQ_POLLED | EQ_MULTITHREAD)) {
678 if (eq_info->eq_type & EQ_INTERRUPT) {
679 if (eq_info->eq_type & EQ_POLLED)
680 cm_msg(MERROR, "register_equipment",
681 "Equipment \"%s\" cannot be of type EQ_INTERRUPT and EQ_POLLED at the same time",
683 else
684 cm_msg(MERROR, "register_equipment",
685 "Equipment \"%s\" cannot be of type EQ_INTERRUPT and EQ_MULTITHREAD at the same time",
687 return 0;
688 }
689
690 if (polled_eq) {
691 equipment[idx].status = FE_ERR_DISABLED;
692 cm_msg(MINFO, "initialize_equipment",
693 "Defined more than one polled equipment \'%s\' in frontend \'%s\'", equipment[idx].name, frontend_name);
694 } else
696
697 if (display_period)
698 printf("\nCalibrating");
699
700 count = 1;
701 do {
702 if (display_period)
703 printf(".");
704
705 start_time = ss_millitime();
706
708
709 delta_time = ss_millitime() - start_time;
710
711 if (count == 1 && delta_time > eq_info->period * 1.2) {
712 cm_msg(MERROR, "register_equipment", "Polling routine with count=1 takes %d ms", delta_time);
713 ss_sleep(3000);
714 break;
715 }
716
717 if (delta_time > 0)
718 count = count * eq_info->period / delta_time;
719 else
720 count *= 100;
721
722 // avoid overflows
723 if (count > 2147483647.0) {
724 count = 2147483647.0;
725 break;
726 }
727
728 } while (delta_time > eq_info->period * 1.2 || delta_time < eq_info->period * 0.8);
729
730 equipment[idx].poll_count = (INT) count;
731 }
732
733 /*---- initialize multithread events -------------------------*/
734
735 if (eq_info->eq_type & EQ_MULTITHREAD) {
736 /* install interrupt for interrupt events */
737
738 for (i = 0; equipment[i].name[0]; i++)
739 if (equipment[i].info.eq_type & EQ_POLLED) {
740 equipment[idx].status = FE_ERR_DISABLED;
741 cm_msg(MINFO, "initialize_equipment",
742 "Multi-threaded readout cannot be combined with polled readout for equipment \'%s\'", equipment[i].name);
743 }
744
746 if (eq_info->enabled) {
747 if (multithread_eq) {
748 equipment[idx].status = FE_ERR_DISABLED;
749 cm_msg(MINFO, "initialize_equipment",
750 "Defined more than one equipment with multi-threaded readout for equipment \'%s\'", equipment[i].name);
751 } else {
753
754 /* create ring buffer for inter-thread data transfer */
756
757 /* create hardware reading thread */
760 }
761 } else {
762 equipment[idx].status = FE_ERR_DISABLED;
763 cm_msg(MINFO, "initialize_equipment",
764 "Equipment %s disabled in frontend",
766 }
767 }
768 }
769
770 /*---- initialize user events -------------------------------*/
771
772 if (eq_info->eq_type & EQ_USER) {
774 if (!eq_info->enabled) {
775 equipment[idx].status = FE_ERR_DISABLED;
776 cm_msg(MINFO, "initialize_equipment",
777 "Equipment %s disabled in frontend",
779 }
780 }
781 }
782
783 /*---- initialize slow control equipment ---------------------*/
784
785 if (eq_info->eq_type & EQ_SLOW) {
786
787 set_equipment_status(equipment[idx].name, "Initializing...", "yellowLight");
788
789 if (equipment[idx].driver == nullptr) {
790 cm_msg(MERROR, "initialize_equipment", "Found slow control equipment \"%s\" with no device driver list, aborting",
792 return FE_ERR_DRIVER;
793 }
794
795 /* resolve duplicate device names */
796 for (i = 0; equipment[idx].driver[i].name[0]; i++) {
797 equipment[idx].driver[i].pequipment_name = new std::string(equipment[idx].name);
798
799 for (j = i + 1; equipment[idx].driver[j].name[0]; j++)
802 strcpy(str, equipment[idx].driver[i].name);
803 for (k = 0, n = 0; equipment[idx].driver[k].name[0]; k++)
805 //sprintf(equipment[idx].driver[k].name, "%s_%d", str, n++);
808 char tmp[256];
809 sprintf(tmp, "%d", n++);
811 }
812
813 break;
814 }
815 }
816
817 /* loop over equipment list and call class driver's init method */
818 if (eq_info->enabled) {
819 equipment[idx].status = equipment[idx].cd(CMD_INIT, &equipment[idx]);
820
822 strcpy(str, "Ok");
823 else if (equipment[idx].status == FE_ERR_HW)
824 strcpy(str, "Hardware error");
825 else if (equipment[idx].status == FE_ERR_ODB)
826 strcpy(str, "ODB error");
827 else if (equipment[idx].status == FE_ERR_DRIVER)
828 strcpy(str, "Driver error");
830 strcpy(str, "Partially disabled");
831 else
832 strcpy(str, "Error");
833
835 set_equipment_status(equipment[idx].name, str, "greenLight");
837 set_equipment_status(equipment[idx].name, str, "yellowGreenLight");
838 cm_msg(MINFO, "initialize_equipment", "Equipment %s partially disabled", equipment[idx].name);
839 } else {
841 cm_msg(MERROR, "initialize_equipment", "Equipment %s disabled because of %s", equipment[idx].name, str);
842 }
843
844 } else {
845 equipment[idx].status = FE_ERR_DISABLED;
846 set_equipment_status(equipment[idx].name, "Disabled", "yellowLight");
847 }
848
849 /* remember that we have slowcontrol equipment (needed later for scheduler) */
851
852 /* let user read error messages */
854 ss_sleep(3000);
855 }
856
857 /*---- register callback for manual triggered events -----------*/
858 if (eq_info->eq_type & EQ_MANUAL_TRIG) {
859 if (!manual_trig_flag)
861
863 }
864 }
865
866 /* start threads after all equipment has been initialized */
867 for (idx = 0; equipment[idx].name[0]; idx++) {
868 eq_info = &equipment[idx].info;
869
870 if (eq_info->eq_type & EQ_SLOW) {
872 equipment[idx].cd(CMD_START, &equipment[idx]); /* start threads for this equipment */
873 }
874 }
875
876 if (slowcont_eq)
877 cm_msg(MINFO, "initialize_equipment", "Slow control equipment initialized");
878
879 return SUCCESS;
880}
881
882/*------------------------------------------------------------------*/
883
884int set_equipment_status(const char *name, const char *equipment_status, const char *status_class) {
885 int status, idx;
886 char str[256];
887 HNDLE hKey;
888
889 for (idx = 0; equipment[idx].name[0]; idx++)
891 break;
892
894 sprintf(str, "/Equipment/%s/Common", name);
895 db_find_key(hDB, 0, str, &hKey);
896 assert(hKey);
897
898 mstrlcpy(str, equipment_status, sizeof(str));
899 status = db_set_value(hDB, hKey, "Status", str, 256, 1, TID_STRING);
900 assert(status == DB_SUCCESS);
901 mstrlcpy(str, status_class, sizeof(str));
902 status = db_set_value(hDB, hKey, "Status color", str, 32, 1, TID_STRING);
903 assert(status == DB_SUCCESS);
904 }
905
906 return SUCCESS;
907}
908
909/*------------------------------------------------------------------*/
910
911static void update_odb(const EVENT_HEADER *pevent, HNDLE hKey, INT format) {
912 cm_write_event_to_odb(hDB, hKey, pevent, format);
913}
914
915/*------------------------------------------------------------------*/
916
919 EVENT_HEADER *pevent, *pfragment;
920 char *pdata;
921 unsigned char *pd;
922 INT i, status;
923 DWORD sent, size;
924
925 eq_info = &equipment[idx].info;
926
927 /* check for fragmented event */
928 if (eq_info->eq_type & EQ_FRAGMENTED)
929 pevent = (EVENT_HEADER *) frag_buffer;
930 else
931 pevent = (EVENT_HEADER *) event_buffer;
932
933 /* compose MIDAS event header */
934 pevent->event_id = eq_info->event_id;
935 pevent->trigger_mask = eq_info->trigger_mask;
936 pevent->data_size = (INT) manual_trig;
937 pevent->time_stamp = ss_time();
938 pevent->serial_number = equipment[idx].serial_number++;
939
940 equipment[idx].last_called = ss_millitime();
941
942 /* call user readout routine */
943 *((EQUIPMENT **) (pevent + 1)) = &equipment[idx];
944 pevent->data_size = equipment[idx].readout((char *) (pevent + 1), 0);
945
946 /* send event */
947 if (pevent->data_size) {
948 if (eq_info->eq_type & EQ_FRAGMENTED) {
949 /* fragment event */
950 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size_frag) {
951 cm_msg(MERROR, "send_event",
952 "Event size %ld larger than maximum size %d for frag. ev.",
953 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
955 return SS_NO_MEMORY;
956 }
957
958 /* compose fragments */
959 pfragment = (EVENT_HEADER *) event_buffer;
960
961 /* compose MIDAS event header */
962 memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
963 pfragment->event_id |= EVENTID_FRAG1;
964
965 /* store total event size */
966 pd = (unsigned char *) (pfragment + 1);
967 size = pevent->data_size;
968 for (i = 0; i < 4; i++) {
969 pd[i] = (unsigned char) (size & 0xFF); /* little endian, please! */
970 size >>= 8;
971 }
972
973 pfragment->data_size = sizeof(DWORD);
974
975 pdata = (char *) (pevent + 1);
976
977 for (i = 0, sent = 0; sent < pevent->data_size; i++) {
978 if (i > 0) {
979 pfragment = (EVENT_HEADER *) event_buffer;
980
981 /* compose MIDAS event header */
982 memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
983 pfragment->event_id |= EVENTID_FRAG;
984
985 /* copy portion of event */
986 size = pevent->data_size - sent;
987 if (size > max_event_size - sizeof(EVENT_HEADER))
988 size = max_event_size - sizeof(EVENT_HEADER);
989
990 memcpy(pfragment + 1, pdata, size);
991 pfragment->data_size = size;
992 sent += size;
993 pdata += size;
994 }
995
996 /* send event to buffer */
997 if (equipment[idx].buffer_handle) {
998 status = rpc_send_event(equipment[idx].buffer_handle, pfragment,
999 pfragment->data_size + sizeof(EVENT_HEADER), BM_WAIT, rpc_mode);
1000 if (status != RPC_SUCCESS) {
1001 cm_msg(MERROR, "send_event", "rpc_send_event(BM_WAIT) error %d", status);
1002 return status;
1003 }
1004
1005 /* flush events from buffer */
1007 }
1008 }
1009
1010 if (equipment[idx].buffer_handle) {
1011 /* flush buffer cache on server side */
1012 status = bm_flush_cache(equipment[idx].buffer_handle, BM_WAIT);
1013 if (status != BM_SUCCESS) {
1014 cm_msg(MERROR, "send_event", "bm_flush_cache(BM_WAIT) error %d", status);
1015 return status;
1016 }
1017 }
1018 } else {
1019 /* send un-fragmented event */
1020
1021 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
1022 cm_msg(MERROR, "send_event", "Event size %ld larger than maximum size %d",
1023 (long) (pevent->data_size + sizeof(EVENT_HEADER)), max_event_size);
1024 return SS_NO_MEMORY;
1025 }
1026
1027 /* send event to buffer */
1028 if (equipment[idx].buffer_handle) {
1029 status = rpc_send_event(equipment[idx].buffer_handle, pevent,
1030 pevent->data_size + sizeof(EVENT_HEADER), BM_WAIT, rpc_mode);
1031 if (status != BM_SUCCESS) {
1032 cm_msg(MERROR, "send_event", "bm_send_event(BM_WAIT) error %d", status);
1033 return status;
1034 }
1036 status = bm_flush_cache(equipment[idx].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 /* send event to ODB if RO_ODB flag is set */
1044 if (eq_info->read_on & RO_ODB) {
1045 update_odb(pevent, equipment[idx].hkey_variables, equipment[idx].format);
1046 equipment[idx].odb_out++;
1047 }
1048 }
1049
1050 equipment[idx].bytes_sent += pevent->data_size + sizeof(EVENT_HEADER);
1051 equipment[idx].events_sent++;
1052 } else
1053 equipment[idx].serial_number--;
1054
1055 for (i = 0; equipment[i].name[0]; i++)
1056 if (equipment[i].buffer_handle) {
1057 status = bm_flush_cache(equipment[i].buffer_handle, BM_WAIT);
1058 if (status != BM_SUCCESS) {
1059 cm_msg(MERROR, "send_event", "bm_flush_cache(BM_WAIT) error %d", status);
1060 return status;
1061 }
1062 }
1063
1064 return CM_SUCCESS;
1065}
1066
1067/*------------------------------------------------------------------*/
1068
1071 INT i;
1072
1073 for (i = 0; equipment[i].name[0]; i++) {
1074 eq_info = &equipment[i].info;
1075
1076 if (!eq_info->enabled || equipment[i].status != FE_SUCCESS)
1077 continue;
1078
1079 if (transition == TR_START && (eq_info->read_on & RO_BOR) == 0)
1080 continue;
1081 if (transition == TR_STOP && (eq_info->read_on & RO_EOR) == 0)
1082 continue;
1083 if (transition == TR_PAUSE && (eq_info->read_on & RO_PAUSE) == 0)
1084 continue;
1085 if (transition == TR_RESUME && (eq_info->read_on & RO_RESUME) == 0)
1086 continue;
1087
1088 send_event(i, FALSE);
1089 }
1090}
1091
1092/*------------------------------------------------------------------*/
1093
1094static std::atomic<bool> _readout_enabled_flag(false);
1095
1097 return _readout_enabled_flag;
1098}
1099
1102
1103 if (interrupt_eq) {
1104 if (flag)
1106 else
1108 }
1109}
1110
1111/*------------------------------------------------------------------*/
1112
1113static void interrupt_routine(void) {
1114 int status;
1115 EVENT_HEADER *pevent;
1116 void *p;
1117
1118 /* get pointer for upcoming event.
1119 This is a blocking call if no space available */
1120 status = rb_get_wp(get_event_rbh(0), &p, 100000);
1121
1122 if (status == DB_SUCCESS) {
1123 pevent = (EVENT_HEADER *) p;
1124
1125 /* compose MIDAS event header */
1128 pevent->data_size = 0;
1129 pevent->time_stamp = actual_time;
1131
1132 /* call user readout routine */
1133 pevent->data_size = interrupt_eq->readout((char *) (pevent + 1), 0);
1134
1135 /* send event */
1136 if (pevent->data_size) {
1137
1138 /* put event into ring buffer */
1139 rb_increment_wp(get_event_rbh(0), sizeof(EVENT_HEADER) + pevent->data_size);
1140
1141 } else
1143 }
1144}
1145
1146/*------------------------------------------------------------------*/
1147
1148/* routines to be called from user code */
1149
1151 int status;
1152
1153 assert(i < MAX_N_THREADS);
1154 assert(rbh[i] == 0);
1156 assert(status == DB_SUCCESS);
1157 return rbh[i];
1158}
1159
1161 return rbh[i];
1162}
1163
1165 _stop_all_threads = true;
1166}
1167
1171
1173 int i;
1174 for (i = 0; i < MAX_N_THREADS; i++)
1176 return TRUE;
1177 return FALSE;
1178}
1179
1183
1184/*------------------------------------------------------------------*/
1185
1186static int _readout_thread(void *param) {
1187 int status, source;
1188 EVENT_HEADER *pevent;
1189 void *p;
1190
1191 /* indicate activity to framework */
1193
1194 p = param; /* avoid compiler warning */
1195 while (!_stop_all_threads) {
1196 /* obtain buffer space */
1197
1198 status = rb_get_wp(get_event_rbh(0), &p, 0);
1200 break;
1201 if (status == DB_TIMEOUT) {
1202 // printf("readout_thread: Ring buffer is full, waiting for space!\n");
1203 ss_sleep(10);
1204 continue;
1205 }
1206 if (status != DB_SUCCESS)
1207 break;
1208
1209 if (readout_enabled()) {
1210
1211 /* check for new event */
1213
1214 if (source > 0) {
1215
1217 break;
1218
1219 pevent = (EVENT_HEADER *) p;
1220 /* put source at beginning of event, will be overwritten by
1221 user readout code, just a special feature used by some
1222 multi-source applications */
1223 *(INT *) (pevent + 1) = source;
1224
1225 /* compose MIDAS event header */
1228 pevent->data_size = 0;
1229 pevent->time_stamp = actual_time;
1231
1232 /* call user readout routine */
1233 pevent->data_size = multithread_eq->readout((char *) (pevent + 1), 0);
1234
1235 /* check event size */
1236 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
1237 cm_msg(MERROR, "readout_thread",
1238 "Event size %ld larger than maximum size %d",
1239 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1241 assert(FALSE);
1242 }
1243
1244 if (pevent->data_size > 0) {
1245 /* put event into ring buffer */
1246 rb_increment_wp(get_event_rbh(0), sizeof(EVENT_HEADER) + pevent->data_size);
1247 } else
1249 }
1250
1251 } else // readout_enabled
1252 ss_sleep(10);
1253 }
1254
1256
1257 return 0;
1258}
1259
1260/*-- Receive event from readout thread or interrupt routine --------*/
1261
1263 int index, status;
1264 EVENT_HEADER *prb = NULL, *pevent;
1265 void *p;
1266 static unsigned int last_event_time = 0;
1267 static unsigned int last_error = 0;
1268 unsigned int last_serial = 0;
1269
1270 unsigned int serial = eq->events_collected;
1271 if (serial == 0)
1272 last_serial = 0; // BOR
1273
1274 // search all ring buffers for next event
1275 status = 0;
1276 for (index = 0; get_event_rbh(index); index++) {
1277 status = rb_get_rp(get_event_rbh(index), &p, 10);
1278 prb = (EVENT_HEADER *) p;
1279 if (status == DB_SUCCESS)
1280 if (prb->serial_number > last_serial)
1281 last_serial = prb->serial_number;
1282 if (status == DB_SUCCESS && prb->serial_number == serial)
1283 break;
1284 }
1285
1286 if (get_event_rbh(index) == 0) {
1287 if (serial > 0 && last_serial > serial &&
1288 last_event_time > 0 && ss_millitime() > last_event_time + 5000) {
1289 if (ss_time() - last_error > 30) {
1290 last_error = ss_time();
1291 cm_msg(MERROR, "receive_trigger_event",
1292 "Event collector: waiting for event serial %d since %1.1lf seconds, received already serial %d",
1294 }
1295 }
1296 return 0;
1297 }
1298
1300 pevent = prb;
1301
1302 /* send event */
1303 if (pevent->data_size) {
1304 if (eq->buffer_handle) {
1305
1306 /* save event in temporary buffer to push it to the ODB later */
1307 if (eq->info.read_on & RO_ODB)
1308 memcpy(event_buffer, pevent, pevent->data_size + sizeof(EVENT_HEADER));
1309
1310 /* send first event to ODB if logger writes in root format */
1311 if (pevent->serial_number == 0)
1312 if (logger_root())
1313 update_odb(pevent, eq->hkey_variables, eq->format);
1314
1315 status = rpc_send_event(eq->buffer_handle, pevent,
1316 pevent->data_size + sizeof(EVENT_HEADER),
1317 BM_WAIT, rpc_mode);
1318
1319 if (status != SUCCESS) {
1320 cm_msg(MERROR, "receive_trigger_event", "rpc_send_event error %d", status);
1321 return -1;
1322 }
1323
1324 eq->bytes_sent += pevent->data_size + sizeof(EVENT_HEADER);
1325
1326 if (eq->info.num_subevents)
1327 eq->events_sent += eq->subevent_number;
1328 else
1329 eq->events_sent++;
1330
1331 eq->events_collected++;
1332
1333 rotate_wheel();
1334 }
1335 }
1336
1337 rb_increment_rp(get_event_rbh(index), sizeof(EVENT_HEADER) + prb->data_size);
1338 return prb->data_size;
1339}
1340
1341/*------------------------------------------------------------------*/
1342
1343static int flush_user_events() {
1344 int index, status;
1345 EVENT_HEADER *pevent;
1346 void *p;
1347
1348 for (int idx = 0; equipment[idx].name[0]; idx++) {
1350
1351 if (eq->info.eq_type == EQ_USER) {
1352 for (index = 0; get_event_rbh(index); index++) {
1353 do {
1354 status = rb_get_rp(get_event_rbh(index), &p, 10);
1355 pevent = (EVENT_HEADER *) p;
1356 if (status == DB_SUCCESS) {
1358 }
1359 } while (status == DB_SUCCESS);
1360 }
1361 }
1362 }
1363
1364 return FE_SUCCESS;
1365}
1366
1367/*------------------------------------------------------------------*/
1368
1369static int message_print(const char *msg) {
1370 char str[160];
1371
1372 memset(str, ' ', 159);
1373 str[159] = 0;
1374
1375 if (msg[0] == '[')
1376 msg = strchr(msg, ']') + 2;
1377
1378 memcpy(str, msg, strlen(msg));
1379 ss_printf(0, 20, str);
1380
1381 return 0;
1382}
1383
1384/*------------------------------------------------------------------*/
1385
1387 INT i, status;
1389 char str[30];
1390
1391 if (bInit) {
1393
1394 if (host_name[0])
1395 strcpy(str, host_name);
1396 else
1397 strcpy(str, "<local>");
1398
1399 ss_printf(0, 0, "%s connected to %s. Press \"!\" to exit", full_frontend_name, str);
1400 ss_printf(0, 1,
1401 "================================================================================");
1402 ss_printf(0, 2, "Run status: %s",
1403 run_state == STATE_STOPPED ? "Stopped" : run_state == STATE_RUNNING ? "Running"
1404 : "Paused");
1405 ss_printf(25, 2, "Run number %d ", run_number);
1406 ss_printf(0, 3,
1407 "================================================================================");
1408 ss_printf(0, 4,
1409 "Equipment Status Events Events/sec Rate[B/s] ODB->FE FE->ODB");
1410 ss_printf(0, 5,
1411 "--------------------------------------------------------------------------------");
1412 for (i = 0; equipment[i].name[0]; i++)
1413 ss_printf(0, i + 6, "%s", equipment[i].name);
1414 }
1415
1416 /* display time */
1417 time(&full_time);
1418 char ctimebuf[32];
1420 mstrlcpy(str, ctimebuf + 11, sizeof(str));
1421 str[8] = 0;
1422 ss_printf(72, 0, "%s", str);
1423
1424 for (i = 0; equipment[i].name[0]; i++) {
1425 status = equipment[i].status;
1426
1427 if ((status == 0 || status == FE_SUCCESS) && equipment[i].info.enabled)
1428 ss_printf(14, i + 6, "OK ");
1429 else if (!equipment[i].info.enabled)
1430 ss_printf(14, i + 6, "Disabled ");
1431 else if (status == FE_ERR_ODB)
1432 ss_printf(14, i + 6, "ODB Error");
1433 else if (status == FE_ERR_HW)
1434 ss_printf(14, i + 6, "HW Error ");
1435 else if (status == FE_ERR_DISABLED)
1436 ss_printf(14, i + 6, "Disabled ");
1437 else if (status == FE_ERR_DRIVER)
1438 ss_printf(14, i + 6, "Driver err");
1439 else
1440 ss_printf(14, i + 6, "Unknown ");
1441
1442 if (equipment[i].stats.events_sent > 1E9)
1443 ss_printf(25, i + 6, "%1.3lfG ", equipment[i].stats.events_sent / 1E9);
1444 else if (equipment[i].stats.events_sent > 1E6)
1445 ss_printf(25, i + 6, "%1.3lfM ", equipment[i].stats.events_sent / 1E6);
1446 else
1447 ss_printf(25, i + 6, "%1.0lf ", equipment[i].stats.events_sent);
1448
1449 if (equipment[i].stats.events_per_sec > 1E6)
1450 ss_printf(36, i + 6, "%1.3lfM ", equipment[i].stats.events_per_sec / 1E6);
1451 else if (equipment[i].stats.events_per_sec > 1E3)
1452 ss_printf(36, i + 6, "%1.3lfk ", equipment[i].stats.events_per_sec / 1E3);
1453 else
1454 ss_printf(36, i + 6, "%1.1lf ", equipment[i].stats.events_per_sec);
1455
1456 if (equipment[i].stats.kbytes_per_sec > 1E3)
1457 ss_printf(47, i + 6, "%1.3lfM ", equipment[i].stats.kbytes_per_sec / 1E3);
1458 else if (equipment[i].stats.kbytes_per_sec < 1E3)
1459 ss_printf(47, i + 6, "%1.1lf ", equipment[i].stats.kbytes_per_sec * 1E3);
1460 else
1461 ss_printf(47, i + 6, "%1.3lfk ", equipment[i].stats.kbytes_per_sec);
1462
1463 ss_printf(58, i + 6, "%ld ", equipment[i].odb_in);
1464 ss_printf(69, i + 6, "%ld ", equipment[i].odb_out);
1465 }
1466
1467 /* go to next line */
1468 ss_printf(0, i + 6, "");
1469}
1470
1471/*------------------------------------------------------------------*/
1472
1474 INT i;
1476 char str[30];
1477
1478 /* display time */
1479 time(&full_time);
1480 char ctimebuf[32];
1482 mstrlcpy(str, ctimebuf + 11, sizeof(str));
1483 str[8] = 0;
1484 printf("%s ", str);
1485
1486 for (i = 0; equipment[i].name[0]; i++) {
1487 printf(" %s:", equipment[i].name);
1488
1489 if (equipment[i].stats.events_per_sec > 1E6)
1490 printf("%6.3lfM", equipment[i].stats.events_per_sec / 1E6);
1491 else if (equipment[i].stats.events_per_sec > 1E3)
1492 printf("%6.3lfk", equipment[i].stats.events_per_sec / 1E3);
1493 else
1494 printf("%6.1lf ", equipment[i].stats.events_per_sec);
1495 }
1496
1497 /* go to next line */
1498 printf("\n");
1499}
1500
1501/*------------------------------------------------------------------*/
1502
1503void rotate_wheel(void) {
1504 static DWORD last_wheel = 0, wheel_index = 0;
1505 static char wheel_char[] = {'-', '\\', '|', '/'};
1506
1507 if (display_period && !mfe_debug) {
1508 if (ss_millitime() - last_wheel > 300) {
1510 ss_printf(79, 2, "%c", wheel_char[wheel_index]);
1511 wheel_index = (wheel_index + 1) % 4;
1512 }
1513 }
1514}
1515
1516/*------------------------------------------------------------------*/
1517
1519/* check if logger uses ROOT format */
1520{
1521 int size, i, status;
1522 char str[80];
1524
1525 if (db_find_key(hDB, 0, "/Logger/Channels", &hKeyRoot) == DB_SUCCESS) {
1526 for (i = 0;; i++) {
1529 break;
1530
1531 strcpy(str, "MIDAS");
1532 size = sizeof(str);
1533 db_get_value(hDB, hKey, "Settings/Format", str, &size, TID_STRING, TRUE);
1534
1535 if (equal_ustring(str, "ROOT"))
1536 return TRUE;
1537 }
1538 }
1539
1540 return FALSE;
1541}
1542
1543/*------------------------------------------------------------------*/
1544
1547 EQUIPMENT *eq;
1548 EVENT_HEADER *pevent, *pfragment;
1549 DWORD readout_start, sent, size;
1550 INT i, idx, source, events_sent, status;
1551 char *pdata;
1552 unsigned char *pd;
1553
1554 events_sent = 0;
1556
1557 /*---- loop over equipment table -------------------------------*/
1558 for (idx = 0;; idx++) {
1559 eq = &equipment[idx];
1560 eq_info = &eq->info;
1561
1562 /* check if end of equipment list */
1563 if (!eq->name[0])
1564 break;
1565
1566 if (!eq_info->enabled)
1567 continue;
1568
1569 if (eq->status != FE_SUCCESS)
1570 continue;
1571
1572 if ((eq_info->eq_type & EQ_POLLED) == 0)
1573 continue;
1574
1575 /*---- check polled events ----*/
1577 pevent = NULL;
1578
1579 while ((source = poll_event(eq_info->source, eq->poll_count, FALSE)) > 0) {
1580
1581 if (eq_info->eq_type & EQ_FRAGMENTED)
1582 pevent = (EVENT_HEADER *) frag_buffer;
1583 else
1584 pevent = (EVENT_HEADER *) event_buffer;
1585
1586 /* compose MIDAS event header */
1587 pevent->event_id = eq_info->event_id;
1588 pevent->trigger_mask = eq_info->trigger_mask;
1589 pevent->data_size = 0;
1590 pevent->time_stamp = actual_time;
1591 pevent->serial_number = eq->serial_number;
1592
1593 /* put source at beginning of event, will be overwritten by
1594 user readout code, just a special feature used by some
1595 multi-source applications */
1596 *(INT *) (pevent + 1) = source;
1597
1598 if (eq->info.num_subevents) {
1599 eq->subevent_number = 0;
1600 do {
1601 *(INT *) ((char *) (pevent + 1) + pevent->data_size) = source;
1602
1603 /* call user readout routine for subevent indicating offset */
1604 size = eq->readout((char *) (pevent + 1), pevent->data_size);
1605 pevent->data_size += size;
1606 if (size > 0) {
1607 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
1608 cm_msg(MERROR, "check_polled_events",
1609 "Event size %ld larger than maximum size %d",
1610 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1612 }
1613
1614 eq->subevent_number++;
1615 eq->serial_number++;
1616 }
1617
1618 /* wait for next event */
1619 do {
1620 source = poll_event(eq_info->source, eq->poll_count, FALSE);
1621
1622 if (source == FALSE) {
1624
1625 /* repeat no more than period */
1626 if (actual_millitime - readout_start > (DWORD) eq_info->period)
1627 break;
1628 }
1629 } while (source == FALSE);
1630
1631 } while (eq->subevent_number < eq->info.num_subevents && source);
1632
1633 /* notify readout routine about end of super-event */
1634 pevent->data_size = eq->readout((char *) (pevent + 1), -1);
1635 } else {
1636 /* call user readout routine indicating event source */
1637 pevent->data_size = eq->readout((char *) (pevent + 1), 0);
1638
1639 /* check event size */
1640 if (eq_info->eq_type & EQ_FRAGMENTED) {
1641 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size_frag) {
1642 cm_msg(MERROR, "check_polled_events",
1643 "Event size %ld larger than maximum size %d for frag. ev.",
1644 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1646 assert(FALSE);
1647 }
1648 } else {
1649 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
1650 cm_msg(MERROR, "check_polled_events",
1651 "Event size %ld larger than maximum size %d",
1652 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1654 assert(FALSE);
1655 }
1656 }
1657
1658 /* increment serial number if event read out sucessfully */
1659 if (pevent->data_size)
1660 eq->serial_number++;
1661 }
1662
1663 /* send event */
1664 if (pevent->data_size) {
1665
1666 /* check for fragmented event */
1667 if (eq_info->eq_type & EQ_FRAGMENTED) {
1668 /* compose fragments */
1669 pfragment = (EVENT_HEADER *) event_buffer;
1670
1671 /* compose MIDAS event header */
1672 memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
1673 pfragment->event_id |= EVENTID_FRAG1;
1674
1675 /* store total event size */
1676 pd = (unsigned char *) (pfragment + 1);
1677 size = pevent->data_size;
1678 for (i = 0; i < 4; i++) {
1679 pd[i] = (unsigned char) (size & 0xFF); /* little endian, please! */
1680 size >>= 8;
1681 }
1682
1683 pfragment->data_size = sizeof(DWORD);
1684
1685 pdata = (char *) (pevent + 1);
1686
1687 for (i = 0, sent = 0; sent < pevent->data_size; i++) {
1688 if (i > 0) {
1689 pfragment = (EVENT_HEADER *) event_buffer;
1690
1691 /* compose MIDAS event header */
1692 memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
1693 pfragment->event_id |= EVENTID_FRAG;
1694
1695 /* copy portion of event */
1696 size = pevent->data_size - sent;
1697 if (size > max_event_size - sizeof(EVENT_HEADER))
1698 size = max_event_size - sizeof(EVENT_HEADER);
1699
1700 memcpy(pfragment + 1, pdata, size);
1701 pfragment->data_size = size;
1702 sent += size;
1703 pdata += size;
1704 }
1705
1706 /* send event to buffer */
1707 if (equipment[idx].buffer_handle) {
1708 status = rpc_send_event(equipment[idx].buffer_handle, pfragment,
1709 pfragment->data_size + sizeof(EVENT_HEADER), BM_WAIT, rpc_mode);
1710 if (status != RPC_SUCCESS) {
1711 cm_msg(MERROR, "check_polled_events", "rpc_send_event(BM_WAIT) error %d", status);
1712 return status;
1713 }
1714
1715 /* flush events from buffer */
1717 }
1718 }
1719
1720 } else { /*-------------------*/
1721
1722 /* send unfragmented event */
1723
1724 /* send first event to ODB if logger writes in root format */
1725 if (pevent->serial_number == 0)
1726 if (logger_root())
1727 update_odb(pevent, eq->hkey_variables, eq->format);
1728
1729 status = rpc_send_event(eq->buffer_handle, pevent,
1730 pevent->data_size + sizeof(EVENT_HEADER),
1731 BM_WAIT, rpc_mode);
1732
1733 if (status != SUCCESS) {
1734 cm_msg(MERROR, "check_polled_events", "rpc_send_event error %d", status);
1735 break;
1736 }
1737 }
1738
1739 eq->bytes_sent += pevent->data_size + sizeof(EVENT_HEADER);
1740
1741 if (eq->info.num_subevents) {
1742 eq->events_sent += eq->subevent_number;
1743 events_sent += eq->subevent_number;
1744 } else {
1745 eq->events_sent++;
1746 events_sent++;
1747 }
1748
1749 rotate_wheel();
1750 }
1751
1753
1754 /* repeat no more than period */
1755 if (actual_millitime - readout_start > (DWORD) eq_info->period)
1756 break;
1757
1758 /* quit if event limit is reached */
1759 if (eq_info->event_limit > 0 && eq->stats.events_sent + eq->events_sent >= eq_info->event_limit)
1760 break;
1761 }
1762 }
1763
1764 return events_sent;
1765}
1766
1767/*------------------------------------------------------------------*/
1768
1771 EQUIPMENT *eq;
1772 DWORD size;
1773 INT idx, events_sent;
1774
1775 events_sent = 0;
1776
1777 /*---- loop over equipment table -------------------------------*/
1778 for (idx = 0;; idx++) {
1779 eq = &equipment[idx];
1780 eq_info = &eq->info;
1781
1782 /* check if end of equipment list */
1783 if (!eq->name[0])
1784 break;
1785
1786 if (!eq_info->enabled)
1787 continue;
1788
1789 if (eq->status != FE_SUCCESS)
1790 continue;
1791
1792 if ((eq_info->eq_type & (EQ_INTERRUPT | EQ_MULTITHREAD | EQ_USER)) == 0)
1793 continue;
1794
1795 do {
1796 size = receive_trigger_event(eq);
1797 if (size > 0)
1798 events_sent++;
1799 } while (size > 0);
1800 }
1801
1802 return events_sent;
1803}
1804
1805/*------------------------------------------------------------------*/
1806
1807static INT scheduler() {
1809 EQUIPMENT *eq;
1810 EVENT_HEADER *pevent, *pfragment;
1812 readout_start, sent, size, last_time_rate = 0;
1813 INT i, j, idx, status = 0, ch, source, state, old_flag;
1814 char *pdata;
1815 unsigned char *pd;
1817
1818 INT opt_max = 0, opt_index = 0, opt_tcp_size = 128, opt_cnt = 0;
1819 INT err;
1820
1821#ifdef OS_VXWORKS
1823#ifdef PPCxxx
1825#endif
1826#endif
1827
1828 /*----------------- MAIN equipment loop ------------------------------*/
1829
1831
1832 do {
1834 actual_time = ss_time();
1835
1836 /*---- loop over equipment table -------------------------------*/
1837 for (idx = 0;; idx++) {
1838 eq = &equipment[idx];
1839 eq_info = &eq->info;
1840
1841 /* check if end of equipment list */
1842 if (!eq->name[0])
1843 break;
1844
1845 if (!eq_info->enabled)
1846 continue;
1847
1848 if (eq->status != FE_SUCCESS && eq->status != FE_PARTIALLY_DISABLED)
1849 continue;
1850
1851 /*---- call idle routine for slow control equipment ----*/
1852 if ((eq_info->eq_type & EQ_SLOW) && (eq->status == FE_SUCCESS || eq->status == FE_PARTIALLY_DISABLED)) {
1853 if (eq_info->history > 0) {
1854 if (actual_millitime - eq->last_idle >= (DWORD) eq_info->history) {
1855 eq->cd(CMD_IDLE, eq);
1856 eq->last_idle = actual_millitime;
1857 }
1858 } else
1859 eq->cd(CMD_IDLE, eq);
1860 }
1861
1862 if (run_state == STATE_STOPPED && (eq_info->read_on & RO_STOPPED) == 0)
1863 continue;
1864 if (run_state == STATE_PAUSED && (eq_info->read_on & RO_PAUSED) == 0)
1865 continue;
1866 if (run_state == STATE_RUNNING && (eq_info->read_on & RO_RUNNING) == 0)
1867 continue;
1868
1869 /*---- check periodic events ----*/
1870 if ((eq_info->eq_type & EQ_PERIODIC) || (eq_info->eq_type & EQ_SLOW)) {
1871 if (eq_info->period == 0)
1872 continue;
1873
1874 /* check if period over */
1875 if (actual_millitime - eq->last_called >= (DWORD) eq_info->period) {
1876 /* disable interrupts or readout thread during this event */
1880
1881 /* readout and send event */
1883
1884 if (status != CM_SUCCESS) {
1885 cm_msg(MERROR, "scheduler", "send_event error %d", status);
1886 goto net_error;
1887 }
1888
1889 /* re-enable the interrupt or readout thread after readout */
1890 if (old_flag)
1892 }
1893 }
1894
1895 /*---- check polled events ----*/
1896 if (eq_info->eq_type & EQ_POLLED) {
1898 pevent = NULL;
1899
1900 while ((source = poll_event(eq_info->source, eq->poll_count, FALSE)) > 0) {
1901
1902 if (eq_info->eq_type & EQ_FRAGMENTED)
1903 pevent = (EVENT_HEADER *) frag_buffer;
1904 else
1905 pevent = (EVENT_HEADER *) event_buffer;
1906
1907 /* compose MIDAS event header */
1908 pevent->event_id = eq_info->event_id;
1909 pevent->trigger_mask = eq_info->trigger_mask;
1910 pevent->data_size = 0;
1911 pevent->time_stamp = actual_time;
1912 pevent->serial_number = eq->serial_number;
1913
1914 /* put source at beginning of event, will be overwritten by
1915 user readout code, just a special feature used by some
1916 multi-source applications */
1917 *(INT *) (pevent + 1) = source;
1918
1919 if (eq->info.num_subevents) {
1920 eq->subevent_number = 0;
1921 do {
1922 *(INT *) ((char *) (pevent + 1) + pevent->data_size) = source;
1923
1924 /* call user readout routine for subevent indicating offset */
1925 size = eq->readout((char *) (pevent + 1), pevent->data_size);
1926 pevent->data_size += size;
1927 if (size > 0) {
1928 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
1929 cm_msg(MERROR, "scheduler",
1930 "Event size %ld larger than maximum size %d",
1931 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1933 }
1934
1935 eq->subevent_number++;
1936 eq->serial_number++;
1937 }
1938
1939 /* wait for next event */
1940 do {
1941 source = poll_event(eq_info->source, eq->poll_count, FALSE);
1942
1943 if (source == FALSE) {
1945
1946 /* repeat no more than period */
1947 if (actual_millitime - readout_start > (DWORD) eq_info->period)
1948 break;
1949 }
1950 } while (source == FALSE);
1951
1952 } while (eq->subevent_number < eq->info.num_subevents && source);
1953
1954 /* notify readout routine about end of super-event */
1955 pevent->data_size = eq->readout((char *) (pevent + 1), -1);
1956 } else {
1957 /* call user readout routine indicating event source */
1958 pevent->data_size = eq->readout((char *) (pevent + 1), 0);
1959
1960 /* check event size */
1961 if (eq_info->eq_type & EQ_FRAGMENTED) {
1962 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size_frag) {
1963 cm_msg(MERROR, "send_event",
1964 "Event size %ld larger than maximum size %d for frag. ev.",
1965 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1967 pevent->data_size = 0;
1968 }
1969 } else {
1970 if (pevent->data_size + sizeof(EVENT_HEADER) > (DWORD) max_event_size) {
1971 cm_msg(MERROR, "scheduler",
1972 "Event size %ld larger than maximum size %d",
1973 (long) (pevent->data_size + sizeof(EVENT_HEADER)),
1975 pevent->data_size = 0;
1976 }
1977 }
1978
1979 /* increment serial number if event read out sucessfully */
1980 if (pevent->data_size)
1981 eq->serial_number++;
1982 }
1983
1984 /* send event */
1985 if (pevent->data_size) {
1986
1987 /* check for fragmented event */
1988 if (eq_info->eq_type & EQ_FRAGMENTED) {
1989 /* compose fragments */
1990 pfragment = (EVENT_HEADER *) event_buffer;
1991
1992 /* compose MIDAS event header */
1993 memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
1994 pfragment->event_id |= EVENTID_FRAG1;
1995
1996 /* store total event size */
1997 pd = (unsigned char *) (pfragment + 1);
1998 size = pevent->data_size;
1999 for (i = 0; i < 4; i++) {
2000 pd[i] = (unsigned char) (size & 0xFF); /* little endian, please! */
2001 size >>= 8;
2002 }
2003
2004 pfragment->data_size = sizeof(DWORD);
2005
2006 pdata = (char *) (pevent + 1);
2007
2008 for (i = 0, sent = 0; sent < pevent->data_size; i++) {
2009 if (i > 0) {
2010 pfragment = (EVENT_HEADER *) event_buffer;
2011
2012 /* compose MIDAS event header */
2013 memcpy(pfragment, pevent, sizeof(EVENT_HEADER));
2014 pfragment->event_id |= EVENTID_FRAG;
2015
2016 /* copy portion of event */
2017 size = pevent->data_size - sent;
2018 if (size > max_event_size - sizeof(EVENT_HEADER))
2019 size = max_event_size - sizeof(EVENT_HEADER);
2020
2021 memcpy(pfragment + 1, pdata, size);
2022 pfragment->data_size = size;
2023 sent += size;
2024 pdata += size;
2025 }
2026
2027 /* send event to buffer */
2028 if (equipment[idx].buffer_handle) {
2029 status = rpc_send_event(equipment[idx].buffer_handle, pfragment,
2030 pfragment->data_size + sizeof(EVENT_HEADER), BM_WAIT, rpc_mode);
2031 if (status != RPC_SUCCESS) {
2032 cm_msg(MERROR, "scheduler", "rpc_send_event(BM_WAIT) error %d", status);
2033 return status;
2034 }
2035
2036 /* flush events from buffer */
2038 }
2039 }
2040
2041 } else { /*-------------------*/
2042
2043 /* send unfragmented event */
2044
2045 /* send first event to ODB if logger writes in root format */
2046 if (pevent->serial_number == 0)
2047 if (logger_root())
2048 update_odb(pevent, eq->hkey_variables, eq->format);
2049
2050 status = rpc_send_event(eq->buffer_handle, pevent,
2051 pevent->data_size + sizeof(EVENT_HEADER),
2052 BM_WAIT, rpc_mode);
2053
2054 if (status != SUCCESS) {
2055 cm_msg(MERROR, "scheduler", "rpc_send_event error %d", status);
2056 goto net_error;
2057 }
2058 }
2059
2060 eq->bytes_sent += pevent->data_size + sizeof(EVENT_HEADER);
2061
2062 if (eq->info.num_subevents)
2063 eq->events_sent += eq->subevent_number;
2064 else
2065 eq->events_sent++;
2066
2067 rotate_wheel();
2068 }
2069
2071
2072 /* send event to ODB */
2073 if (pevent->data_size && (eq_info->read_on & RO_ODB)) {
2074 if (actual_millitime - eq->last_called > ODB_UPDATE_TIME) {
2075 eq->last_called = actual_millitime;
2076 update_odb(pevent, eq->hkey_variables, eq->format);
2077 eq->odb_out++;
2078 }
2079 }
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 }
2090
2091 /*---- send interrupt events ----*/
2092 if (eq_info->eq_type & (EQ_INTERRUPT | EQ_MULTITHREAD | EQ_USER)) {
2094
2095 do {
2096 size = receive_trigger_event(eq);
2097 if ((int) size == -1)
2098 goto net_error;
2099
2101
2102 /* repeat no more than period */
2103 if (actual_millitime - readout_start > (DWORD) eq_info->period)
2104 break;
2105
2106 /* quit if event limit is reached */
2107 if (eq_info->event_limit > 0 && eq->stats.events_sent + eq->events_sent >= eq_info->event_limit)
2108 break;
2109
2110 } while (size > 0);
2111
2112 /* send event to ODB */
2113 pevent = (EVENT_HEADER *) event_buffer;
2114 if (size > 0 && pevent->data_size && ((eq_info->read_on & RO_ODB) || eq_info->history)) {
2115 if (actual_millitime - eq->last_called > ODB_UPDATE_TIME && pevent != NULL) {
2116 eq->last_called = actual_millitime;
2117 update_odb(pevent, eq->hkey_variables, eq->format);
2118 eq->odb_out++;
2119 }
2120 }
2121 }
2122
2123 /*---- check if event limit is reached ----*/
2124 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) {
2125 /* stop run */
2127 if (cm_transition(TR_STOP, 0, str, sizeof(str), TR_SYNC, FALSE) != CM_SUCCESS)
2128 cm_msg(MERROR, "scheduler", "cannot stop run: %s", str);
2129
2130 /* check if auto-restart, main loop will take care of it */
2131 flag = FALSE;
2132 size = sizeof(flag);
2133 db_get_value(hDB, 0, "/Logger/Auto restart", &flag, (INT *) &size, TID_BOOL, TRUE);
2134
2135 if (flag) {
2136 UINT32 delay = 20;
2137 size = sizeof(delay);
2138 db_get_value(hDB, 0, "/Logger/Auto restart delay", &delay, (INT *) &size, TID_UINT32, TRUE);
2139 auto_restart = ss_time() + delay;
2140 }
2141
2142 /* update event display correctly */
2144 }
2145 }
2146
2147 /*---- check for error messages periodically -------------------*/
2149
2150 /*---- call frontend_loop periodically -------------------------*/
2151 if (frontend_call_loop) {
2153 if (status == RPC_SHUTDOWN || status == SS_ABORT) {
2155 break;
2156 }
2157 }
2158
2159 /*---- check for deferred transitions --------------------------*/
2161
2162 /*---- check for manual triggered events -----------------------*/
2167
2168 /* readout and send event */
2170 for (i = 0; equipment[i].name[0]; i++)
2171 if (equipment[i].info.event_id == manual_trigger_event_id) {
2172 status = send_event(i, TRUE);
2173 break;
2174 }
2175
2177
2178 if (status != CM_SUCCESS) {
2179 cm_msg(MERROR, "scheduler", "send_event error %d", status);
2180 goto net_error;
2181 }
2182
2183 /* re-enable the interrupt after periodic */
2184 if (old_flag)
2186 }
2187
2188 int overflow = 0;
2189
2190 for (i = 0; equipment[i].name[0]; i++) {
2191 if (equipment[i].bytes_sent > 0xDFFFFFFF)
2192 overflow = (int) equipment[i].bytes_sent;
2193 }
2194
2195 /*---- calculate rates and update status page periodically -----*/
2199
2200 for (i = 0; equipment[i].name[0]; i++) {
2201 eq = &equipment[i];
2202 eq->stats.events_sent += eq->events_sent;
2203 n_events[i] += (int) eq->events_sent;
2204 eq->events_sent = 0;
2205 }
2206
2207 /* calculate rates after requested period */
2208 if (overflow || (actual_millitime - last_time_rate > (DWORD) get_rate_period())) {
2210 for (i = 0; equipment[i].name[0]; i++) {
2211 eq = &equipment[i];
2212 double e = n_events[i] / ((actual_millitime - last_time_rate) / 1000.0);
2213 eq->stats.events_per_sec = ((int)(e * 100 + 0.5)) / 100.0;
2214
2215 e = eq->bytes_sent / 1000.0 / ((actual_millitime - last_time_rate) / 1000.0);
2216 eq->stats.kbytes_per_sec = ((int)(e * 1000 + 0.5)) / 1000.0;
2217
2218 if ((INT) eq->bytes_sent > max_bytes_per_sec)
2219 max_bytes_per_sec = (INT) eq->bytes_sent;
2220
2221 eq->bytes_sent = 0;
2222 n_events[i] = 0;
2223 }
2224
2226
2228 }
2229
2230 /* tcp buffer size evaluation */
2231 if (optimize) {
2233 ss_printf(0, opt_index, "%6d : %5.1lf %5.1lf", opt_tcp_size,
2234 opt_max / 1000.0, max_bytes_per_sec / 1000.0);
2235 if (++opt_cnt == 10) {
2236 opt_cnt = 0;
2237 opt_max = 0;
2238 opt_index++;
2239 opt_tcp_size = 1 << (opt_index + 7);
2241 if (1 << (opt_index + 7) > 0x8000) {
2242 opt_index = 0;
2243 opt_tcp_size = 1 << 7;
2245 }
2246 }
2247 }
2248
2249 /* propagate changes in equipment to ODB */
2251
2252 if (display_period && !mfe_debug) {
2253 display(FALSE);
2254
2255 /* check keyboard */
2256 ch = 0;
2257 status = 0;
2258 while (ss_kbhit()) {
2259 ch = ss_getchar(0);
2260 if (ch == -1)
2261 ch = getchar();
2262
2263 if (ch == '!')
2265 }
2266
2267 if (ch > 0)
2268 display(TRUE);
2269 if (status == RPC_SHUTDOWN)
2270 break;
2271 }
2272
2273 if (display_period && mfe_debug) {
2275 }
2276
2278 }
2279
2280 /*---- check to flush cache ------------------------------------*/
2281 if (actual_millitime - last_time_flush > 1000) {
2283
2284 /* if cache on server is not filled in one second at current
2285 data rate, flush it now to make events available to consumers */
2286
2287 //printf("mfe: max_bytes_per_sec %d, gWriteCacheSize %d\n", max_bytes_per_sec, gWriteCacheSize);
2288
2293
2294 for (i = 0; equipment[i].name[0]; i++) {
2295 if (equipment[i].buffer_handle) {
2296 /* if the same buffer is open multiple times, only flush it once */
2298 for (j = 0; j < i; j++)
2299 if (equipment[i].buffer_handle == equipment[j].buffer_handle) {
2300 buffer_done = TRUE;
2301 break;
2302 }
2303
2304 //printf("mfe: eq %d, buffer %d, done %d\n", i, equipment[i].buffer_handle, buffer_done);
2305
2306 if (!buffer_done) {
2308 if (rpc_is_remote()) {
2310 } else {
2311 err = bm_flush_cache(equipment[i].buffer_handle, BM_NO_WAIT);
2312 }
2313 if ((err != BM_SUCCESS) && (err != BM_ASYNC_RETURN)) {
2314 cm_msg(MERROR, "scheduler", "bm_flush_cache(BM_NO_WAIT) returned status %d", err);
2315 return err;
2316 }
2317 }
2318 }
2319 }
2320
2321 if (old_flag)
2323 }
2324 }
2325
2326 /*---- check for auto restart --------------------------------*/
2327 if (auto_restart > 0 && ss_time() > auto_restart) {
2328 /* check if really stopped */
2329 size = sizeof(state);
2330 status = db_get_value(hDB, 0, "Runinfo/State", &state, (INT *) &size, TID_INT, TRUE);
2331 if (status != DB_SUCCESS)
2332 cm_msg(MERROR, "scheduler", "cannot get Runinfo/State in database");
2333
2334 if (state == STATE_STOPPED) {
2335 auto_restart = 0;
2336 size = sizeof(run_number);
2337 status =
2338 db_get_value(hDB, 0, "/Runinfo/Run number", &run_number, (INT *) &size, TID_INT,
2339 TRUE);
2340 assert(status == SUCCESS);
2341
2342 if (run_number <= 0) {
2343 cm_msg(MERROR, "main", "aborting on attempt to use invalid run number %d",
2344 run_number);
2345 abort();
2346 }
2347
2348 cm_msg(MTALK, "main", "starting new run");
2350 if (status != CM_SUCCESS)
2351 cm_msg(MERROR, "main", "cannot restart run");
2352 }
2353 }
2354
2355 /*---- check network messages ----------------------------------*/
2357
2358 /* yield 10 ms if no polled equipment present */
2360 status = cm_yield(10);
2361 else {
2362 /* only call yield once every 10ms when running */
2364 status = cm_yield(0);
2366 } else
2368 }
2369 } else
2370 /* when run is stopped or interrupts used,
2371 call yield with 100ms timeout */
2372 status = cm_yield(100);
2373
2374 /* exit for VxWorks */
2375 if (fe_stop)
2377
2378 /* exit if CTRL-C pressed */
2379 if (cm_is_ctrlc_pressed())
2381
2382 } while (status != RPC_SHUTDOWN && status != SS_ABORT);
2383
2384net_error:
2385
2386 return status;
2387}
2388
2389/*------------------------------------------------------------------*/
2390
2394
2395/*------------------------------------------------------------------*/
2396
2397void (*mfe_error_dispatcher)(const char *) = NULL;
2398
2399#define MFE_ERROR_SIZE 10
2403
2404void mfe_set_error(void (*dispatcher)(const char *)) {
2405 int status;
2406
2407 mfe_error_dispatcher = dispatcher;
2409 memset(mfe_error_str, 0, sizeof(mfe_error_str));
2410
2411 if (mfe_mutex == NULL) {
2413 if (status != SS_SUCCESS && status != SS_CREATED)
2414 cm_msg(MERROR, "mfe_set_error", "Cannot create mutex\n");
2415 }
2416}
2417
2418void mfe_error(const char *error)
2419/* central error dispatcher routine which can be called by any device
2420 or class driver */
2421{
2422 if (mfe_mutex == NULL) {
2424 if (status != SS_SUCCESS && status != SS_CREATED) {
2425 cm_msg(MERROR, "mfe_error", "Cannot create mutex\n");
2426 return;
2427 }
2428 }
2429
2430 /* put error into FIFO */
2432 mstrlcpy(mfe_error_str[mfe_error_w], error, 256);
2435}
2436
2448
2449/*------------------------------------------------------------------*/
2450
2451static int _argc = 0;
2452static char **_argv = NULL;
2453
2454void mfe_get_args(int *argc, char ***argv) {
2455 *argc = _argc;
2456 *argv = _argv;
2457}
2458
2459/*------------------------------------------------------------------*/
2460
2461#ifdef OS_VXWORKS
2462int mfe(char *ahost_name, char *aexp_name, BOOL adebug)
2463#else
2464int main(int argc, char *argv[])
2465#endif
2466{
2467 INT status, i, j;
2469
2470 host_name[0] = 0;
2471 exp_name[0] = 0;
2472 daemon_flag = 0;
2473
2474 setbuf(stdout, 0);
2475 setbuf(stderr, 0);
2476
2477#ifdef SIGPIPE
2479#endif
2480
2481#ifdef OS_VXWORKS
2482 if (ahost_name)
2483 strcpy(host_name, ahost_name);
2484 if (aexp_name)
2485 strcpy(exp_name, aexp_name);
2486 mfe_debug = adebug;
2487#else
2488
2489 /* get default from environment */
2491
2492 /* store arguments for user use */
2493 _argc = argc;
2494 _argv = (char **) malloc(sizeof(char *) * argc);
2495 for (i = 0; i < argc; i++) {
2496 _argv[i] = argv[i];
2497 }
2498
2499 /* parse command line parameters */
2500 for (i = 1; i < argc; i++) {
2501 if (argv[i][0] == '-' && argv[i][1] == 'd')
2502 mfe_debug = TRUE;
2503 else if (argv[i][0] == '-' && argv[i][1] == 'D')
2504 daemon_flag = 1;
2505 else if (argv[i][0] == '-' && argv[i][1] == 'O')
2506 daemon_flag = 2;
2507 else if (argv[i][1] == 'v') {
2508 if (i < argc - 1 && atoi(argv[i + 1]) > 0)
2509 verbosity_level = atoi(argv[++i]);
2510 else
2511 verbosity_level = 1;
2512 } else if (argv[i][0] == '-') {
2513 if (i + 1 >= argc || argv[i + 1][0] == '-')
2514 goto usage;
2515 if (argv[i][1] == 'e')
2516 strcpy(exp_name, argv[++i]);
2517 else if (argv[i][1] == 'h')
2518 strcpy(host_name, argv[++i]);
2519 else if (argv[i][1] == 'i')
2520 frontend_index = atoi(argv[++i]);
2521 else if (argv[i][1] == '-') {
2522 usage:
2523 printf("usage: frontend [-h Hostname] [-e Experiment] [-d] [-D] [-O] [-v <n>] [-i <n>]\n");
2524 printf(" [-d] Used to debug the frontend\n");
2525 printf(" [-D] Become a daemon\n");
2526 printf(" [-O] Become a daemon but keep stdout\n");
2527 printf(" [-v <n>] Set verbosity level\n");
2528 printf(" [-i <n>] Set frontend index (used for event building)\n");
2529 return 0;
2530 }
2531 }
2532 }
2533#endif
2534
2535 /* check event and buffer sizes */
2537 cm_msg(MERROR, "mfe_main", "event_buffer_size %d too small for max. event size %d\n", event_buffer_size,
2539 ss_sleep(5000);
2540 return 1;
2541 }
2542
2543 int max_allowed_buffer_size = 1024 * 1024 * 1024;// 1 GB
2544
2545 // Check buffer size. If this value is too large, the end-of-run
2546 // might take quite long to drain a full buffer
2548 cm_msg(MERROR, "mfe_main", "event_buffer_size %d MB exceeds maximum allowed size of %d MB\n",
2549 event_buffer_size / 1024 / 1024, max_allowed_buffer_size / 1024 / 1024);
2550 ss_sleep(5000);
2551 return 1;
2552 }
2553
2554#ifdef OS_VXWORKS
2555 /* override event_buffer_size in case of VxWorks
2556 take remaining free memory and use 20% of it for rb_ */
2557 event_buffer_size = 2 * 10 * (max_event_size + sizeof(EVENT_HEADER) + sizeof(INT));
2558 if (event_buffer_size > memFindMax()) {
2559 cm_msg(MERROR, "mainFE", "Not enough mem space for event size");
2560 return 0;
2561 }
2562 /* takes overall 20% of the available memory resource for rb_() */
2563 event_buffer_size = 0.2 * memFindMax();
2564#endif
2565
2566 /* retrieve frontend index from environment if defined */
2567 if (getenv("MIDAS_FRONTEND_INDEX"))
2568 frontend_index = atoi(getenv("MIDAS_FRONTEND_INDEX"));
2569
2570 /* add frontend index to frontend name if present */
2572 if (frontend_index >= 0)
2574
2575 /* inform user of settings */
2576 printf("Frontend name : %s\n", full_frontend_name);
2577 printf("Event buffer size : %d\n", event_buffer_size);
2578 printf("User max event size : %d\n", max_event_size);
2579 if (max_event_size_frag > 0)
2580 printf("User max frag. size : %d\n", max_event_size_frag);
2581 printf("# of events per buffer : %d\n\n", event_buffer_size / max_event_size);
2582
2583 if (daemon_flag) {
2584 printf("\nBecoming a daemon...\n");
2586 }
2587
2588 /* set default rate period */
2589 set_rate_period(3000);
2590
2591 /* now connect to server */
2592 if (host_name[0]) {
2593 if (exp_name[0])
2594 printf("Connect to experiment %s on host %s...\n", exp_name, host_name);
2595 else
2596 printf("Connect to experiment on host %s...\n", host_name);
2597 } else if (exp_name[0])
2598 printf("Connect to experiment %s...\n", exp_name);
2599 else
2600 printf("Connect to experiment...\n");
2601
2604 if (status != CM_SUCCESS) {
2605 cm_msg(MERROR, "mfe_main", "Cannot connect to experiment \'%s\' on host \'%s\', status %d", exp_name, host_name,
2606 status);
2607 /* let user read message before window might close */
2608 ss_sleep(5000);
2609 return 1;
2610 }
2611
2612 printf("OK\n");
2613
2614 /* allocate buffer space */
2616 if (event_buffer == NULL) {
2617 cm_msg(MERROR, "mfe_main", "mfe: Cannot allocate event buffer of max_event_size %d\n", max_event_size);
2618 return 1;
2619 }
2620
2621 cm_msg(MINFO, "mfe_main", "Frontend \"%s\" started", full_frontend_name);
2622
2623 /* remove any dead frontend */
2625
2626 /* shutdown previous frontend */
2628 if (status == CM_SUCCESS) {
2629 cm_msg(MINFO, "mfe_main", "Previous frontend \"%s\" stopped", full_frontend_name);
2630
2631 /* let user read message */
2632 ss_sleep(3000);
2633
2634 // set full name again, because previously we could have a "1" added to our name
2637 nullptr, DEFAULT_FE_TIMEOUT);
2638 }
2639
2640 /* register transition callbacks */
2645 printf("Failed to start local RPC server");
2647
2648 /* let user read message before window might close */
2649 ss_sleep(5000);
2650 return 1;
2651 }
2653
2655 /* set time from server */
2656#ifdef OS_VXWORKS
2658#endif
2659
2660 /* turn off watchdog if in debug mode */
2661 if (mfe_debug)
2663
2665
2666 /* reqister equipment in ODB */
2667 if (register_equipment() != SUCCESS) {
2668 printf("\n");
2670
2671 /* let user read message before window might close */
2672 ss_sleep(5000);
2673 return 1;
2674 }
2675
2676 /* call user init function */
2677 printf("Init hardware...\n");
2678 if (frontend_init() != SUCCESS) {
2679 printf("\n");
2681 return 1;
2682 }
2683
2684 /* initialize all equipment */
2686 if (status != SUCCESS) {
2687 printf("\n");
2688 cm_msg(MERROR, "mfe_main", "Error status %d received from initialize_equipment, aborting", status);
2690
2691 /* let user read message before window might close */
2692 ss_sleep(5000);
2693 return 1;
2694 }
2695
2696 printf("OK\n");
2697
2698 /* switch on interrupts or readout thread if running */
2699 if (run_state == STATE_RUNNING)
2701
2702 if (!mfe_debug) {
2703 /* initialize ss_getchar */
2704 ss_getchar(0);
2705
2706 /* initialize screen display */
2707 if (display_period) {
2708 ss_sleep(500);
2709 display(TRUE);
2710 }
2711 }
2712
2713 /* set own message print function */
2714 if (display_period && !mfe_debug)
2716
2717 /* call main scheduler loop */
2718 status = scheduler();
2719
2720 /* reset terminal */
2722
2723 if (display_period && !mfe_debug) {
2725 ss_printf(0, 0, "");
2726 }
2727
2728 /* stop readout thread */
2731 while (is_readout_thread_active()) {
2733 ss_sleep(100);
2734 }
2735
2736 /* switch off interrupts and detach */
2737 if (interrupt_eq) {
2740 }
2741
2742 /* call user exit function */
2743 frontend_exit();
2744
2745 /* close slow control drivers */
2746 for (i = 0; equipment[i].name[0]; i++)
2747 if ((equipment[i].info.eq_type & EQ_SLOW) && (equipment[i].status == FE_SUCCESS || equipment[i].status == FE_PARTIALLY_DISABLED)) {
2748
2749 for (j = 0; equipment[i].driver[j].name[0]; j++)
2750 if (equipment[i].driver[j].flags & DF_MULTITHREAD)
2751 break;
2752
2753 /* stop all threads if multithreaded */
2755 equipment[i].cd(CMD_STOP, &equipment[i]); /* stop all threads */
2756 }
2757 for (i = 0; equipment[i].name[0]; i++)
2758 if ((equipment[i].info.eq_type & EQ_SLOW) && (equipment[i].status == FE_SUCCESS || equipment[i].status == FE_PARTIALLY_DISABLED))
2759 equipment[i].cd(CMD_EXIT, &equipment[i]); /* close physical connections */
2760
2761 free(n_events);
2762
2763 if (cm_is_ctrlc_pressed()) {
2764 cm_msg(MINFO, "mfe_main", "Frontend \"%s\" stopped via Ctrl-C", full_frontend_name);
2765 } else if (status == RPC_SHUTDOWN) {
2766 cm_msg(MINFO, "mfe_main", "Frontend \"%s\" stopped via network command", full_frontend_name);
2767 } else if (status != RPC_SHUTDOWN) {
2768 cm_msg(MINFO, "mfe_main", "Frontend \"%s\" stopped because of network error", full_frontend_name);
2769 } else
2770 cm_msg(MINFO, "mfe_main", "Frontend \"%s\" stopped", full_frontend_name);
2771
2772 /* close network connection to server */
2774
2775 return 0;
2776}
2777
2778#ifdef LINK_TEST
2779char *frontend_name;
2780char *frontend_file_name;
2783int max_event_size;
2785int display_period;
2787int frontend_init() { return 0; };
2788int frontend_exit() { return 0; };
2789int begin_of_run(int runno, char *errstr) { return 0; };
2790int end_of_run(int runno, char *errstr) { return 0; };
2791int pause_run(int runno, char *errstr) { return 0; };
2792int resume_run(int runno, char *errstr) { return 0; };
2793int interrupt_configure(INT cmd, INT source, POINTER_T adr) { return 0; };
2794int frontend_loop() { return 0; };
2795int poll_event(INT source, INT count, BOOL test) { return 0; };
2796#endif
2797/* emacs
2798 * Local Variables:
2799 * tab-width: 8
2800 * c-basic-offset: 3
2801 * indent-tabs-mode: nil
2802 * End:
2803 */
#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:6717
INT bm_set_cache_size(INT buffer_handle, size_t read_size, size_t write_size)
Definition midas.cxx:8140
INT bm_flush_cache(int buffer_handle, int timeout_msec)
Definition midas.cxx:10207
INT cm_register_transition(INT transition, INT(*func)(INT, char *), INT sequence_number)
Definition midas.cxx:3593
INT cm_shutdown(const char *name, BOOL bUnique)
Definition midas.cxx:7400
INT cm_yield(INT millisec)
Definition midas.cxx:5642
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3011
INT cm_start_watchdog_thread()
Definition midas.cxx:7355
INT cm_set_client_run_state(INT state)
Definition midas.cxx:3783
INT cm_transition(INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
Definition midas.cxx:5286
INT cm_register_function(INT id, INT(*func)(INT, void **))
Definition midas.cxx:5790
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:7610
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:3889
BOOL cm_is_ctrlc_pressed()
Definition midas.cxx:5452
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:5706
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:7503
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:7299
void ss_printf(INT x, INT y, const char *format,...)
Definition system.cxx:7382
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:13777
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:11805
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:12972
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:13813
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:13441
INT db_set_record(HNDLE hDB, HNDLE hKey, void *data, INT buf_size, INT align)
Definition odb.cxx:12291
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:12800
int rb_get_rp(int handle, void **p, int millisec)
Definition midas.cxx:17568
int rb_get_wp(int handle, void **p, int millisec)
Definition midas.cxx:17427
int rb_increment_rp(int handle, int size)
Definition midas.cxx:17630
int rb_set_nonblocking()
Definition midas.cxx:17295
int rb_increment_wp(int handle, int size)
Definition midas.cxx:17502
int rb_create(int size, int max_event_size, int *handle)
Definition midas.cxx:17336
bool rpc_is_remote(void)
Definition midas.cxx:12761
INT rpc_get_hw_type()
Definition midas.cxx:12834
INT rpc_call(DWORD routine_id,...)
Definition midas.cxx:13663
INT rpc_flush_event()
Definition midas.cxx:14038
INT rpc_send_event(INT buffer_handle, const EVENT_HEADER *pevent, int unused, INT async_flag, INT mode)
Definition midas.cxx:13901
INT rpc_set_opt_tcp_size(INT tcp_size)
Definition midas.cxx:13864
#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:11757
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:2391
static int _argc
Definition mfe.cxx:2451
#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:1343
int mfe_error_w
Definition mfe.cxx:2401
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:1518
INT rpc_mode
Definition mfe.cxx:27
static INT scheduler()
Definition mfe.cxx:1807
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:1100
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:1369
#define ODB_UPDATE_TIME
Definition mfe.cxx:29
static void send_all_periodic_events(INT transition)
Definition mfe.cxx:1069
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:917
void display_inline()
Definition mfe.cxx:1473
static INT initialize_equipment(void)
Definition mfe.cxx:632
DWORD rate_period
Definition mfe.cxx:39
void signal_readout_thread_active(int index, int flag)
Definition mfe.cxx:1180
int create_event_rb(int i)
Definition mfe.cxx:1150
int is_readout_thread_active()
Definition mfe.cxx:1172
DWORD actual_time
Definition mfe.cxx:37
MUTEX_T * mfe_mutex
Definition mfe.cxx:2402
void(* mfe_error_dispatcher)(const char *)
Definition mfe.cxx:2397
EQUIPMENT * polled_eq
Definition mfe.cxx:63
int mfe_error_r
Definition mfe.cxx:2401
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:2454
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:1262
static INT check_user_events(void)
Definition mfe.cxx:1769
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:2418
#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:1545
static INT tr_start(INT rn, char *error)
Definition mfe.cxx:105
static int _readout_thread(void *param)
Definition mfe.cxx:1186
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:1503
void mfe_set_error(void(*dispatcher)(const char *))
Definition mfe.cxx:2404
static void update_odb(const EVENT_HEADER *pevent, HNDLE hKey, INT format)
Definition mfe.cxx:911
void * event_buffer
Definition mfe.cxx:65
char mfe_error_str[MFE_ERROR_SIZE][256]
Definition mfe.cxx:2400
void mfe_error_check(void)
Definition mfe.cxx:2437
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:884
int get_event_rbh(int i)
Definition mfe.cxx:1160
EQUIPMENT * interrupt_eq
Definition mfe.cxx:61
bool readout_enabled(void)
Definition mfe.cxx:1096
void * frag_buffer
Definition mfe.cxx:66
bool is_readout_thread_enabled()
Definition mfe.cxx:1168
void stop_readout_threads()
Definition mfe.cxx:1164
#define MFE_ERROR_SIZE
Definition mfe.cxx:2399
static void interrupt_routine(void)
Definition mfe.cxx:1113
HNDLE hClient
Definition mfe.cxx:59
char host_name[HOST_NAME_LENGTH]
Definition mfe.cxx:43
static char ** _argv
Definition mfe.cxx:2452
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:96
INT max_event_size
Definition mfed.cxx:30
INT frontend_exit()
Frontend exit.
Definition mfed.cxx:80
INT poll_event(__attribute__((unused)) INT source, __attribute__((unused)) INT count, __attribute__((unused)) BOOL test)
Definition mfed.cxx:59
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:66
INT display_period
Definition mfed.cxx:27
INT end_of_run(__attribute__((unused)) INT rn, __attribute__((unused)) char *error)
Definition mfed.cxx:112
INT frontend_loop()
Frontend loop.
Definition mfed.cxx:162
#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:17723
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 MIN_WRITE_CACHE_SIZE
Definition midas.h:257
#define EVENTID_FRAG
Definition midas.h:907
#define EQUIPMENT_STATISTICS_STR
Definition midas.h:1145
#define DEFAULT_BUFFER_SIZE
Definition midas.h:255
#define CWORD(_i)
Definition midas.h:1625
#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:1112
#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:1241
char ** init_str
Definition midas.h:1244
WORD type
Definition midas.h:1242
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:1187
EQUIPMENT_INFO info
Definition midas.h:1174
char name[NAME_LENGTH]
Definition midas.h:1173
INT(* readout)(char *, INT)
Definition midas.h:1175
DWORD poll_count
Definition midas.h:1183
static double e(void)
Definition tinyexpr.c:136