MIDAS
Loading...
Searching...
No Matches
tmfe.cxx
Go to the documentation of this file.
1/********************************************************************\
2
3 Name: tmfe.cxx
4 Created by: Konstantin Olchanski - TRIUMF
5
6 Contents: C++ MIDAS frontend
7
8\********************************************************************/
9
10#undef NDEBUG // midas required assert() to be always enabled
11
12#include <stdio.h>
13#include <stdarg.h>
14#include <assert.h>
15#include <signal.h> // signal()
16#include <sys/time.h> // gettimeofday()
17
18#include "tmfe.h"
19
20#include "midas.h"
21#include "msystem.h"
22#include "mrpc.h"
23#include "mstrlcpy.h"
24
26// error handling
28
30{
31 return TMFeResult(0, message);
32}
33
35{
37}
38
40// TMFE singleton class
42
43
44TMFE::TMFE() // ctor
45{
46 if (gfVerbose)
47 printf("TMFE::ctor!\n");
48}
49
50TMFE::~TMFE() // dtor
51{
52 if (gfVerbose)
53 printf("TMFE::dtor!\n");
54 assert(!"TMFE::~TMFE(): destruction of the TMFE singleton is not permitted!");
55}
56
58{
59 if (!gfMFE)
60 gfMFE = new TMFE();
61
62 return gfMFE;
63}
64
65TMFeResult TMFE::Connect(const char* progname, const char* hostname, const char* exptname)
66{
67 if (progname)
69
70 if (fProgramName.empty()) {
71 return TMFeErrorMessage("TMFE::Connect: frontend program name is not set");
72 }
73
75
76 int status;
77
78 std::string env_hostname;
79 std::string env_exptname;
80
81 /* get default from environment */
83
84 if (status != CM_SUCCESS) {
85 return TMFeMidasError("Cannot connect to MIDAS", "cm_get_environment", status);
86 }
87
88 if (hostname && hostname[0]) {
89 fMserverHostname = hostname;
90 } else {
92 }
93
94 if (exptname && exptname[0]) {
96 } else {
98 }
99
100 if (gfVerbose) {
101 printf("TMFE::Connect: Program \"%s\" connecting to experiment \"%s\" on host \"%s\"\n", fProgramName.c_str(), fExptname.c_str(), fMserverHostname.c_str());
102 }
103
105 //int watchdog = 60*1000;
106
108
109 if (status == CM_UNDEF_EXP) {
110 return TMFeMidasError(msprintf("Cannot connect to MIDAS, experiment \"%s\" is not defined", fExptname.c_str()), "cm_connect_experiment1", status);
111 } else if (status != CM_SUCCESS) {
112 return TMFeMidasError("Cannot connect to MIDAS", "cm_connect_experiment1", status);
113 }
114
116 if (status != CM_SUCCESS) {
117 return TMFeMidasError("Cannot connect to MIDAS", "cm_get_experiment_database", status);
118 }
119
121
122 int run_state = 0;
123
124 fOdbRoot->RI("Runinfo/state", &run_state);
125 fOdbRoot->RI("Runinfo/run number", &fRunNumber);
126
127 if (run_state == STATE_RUNNING) {
128 fStateRunning = true;
129 } else if (run_state == STATE_PAUSED) {
130 fStateRunning = true;
131 } else {
132 fStateRunning = false;
133 }
134
135 RegisterRPCs();
136
137 if (gfVerbose) {
138 printf("TMFE::Connect: Program \"%s\" connected to experiment \"%s\" on host \"%s\"\n", fProgramName.c_str(), fExptname.c_str(), fMserverHostname.c_str());
139 }
140
141 return TMFeOk();
142}
143
145{
146 if (sec == 0) {
147 cm_set_watchdog_params(false, 0);
148 } else {
149 cm_set_watchdog_params(true, sec*1000);
150 }
151 return TMFeOk();
152}
153
155{
156 if (gfVerbose)
157 printf("TMFE::Disconnect: Disconnecting from experiment \"%s\" on host \"%s\"\n", fExptname.c_str(), fMserverHostname.c_str());
160 if (gfVerbose)
161 printf("TMFE::Disconnect: Disconnected from experiment \"%s\" on host \"%s\"\n", fExptname.c_str(), fMserverHostname.c_str());
162 return TMFeOk();
163}
164
166// event buffer functions
168
170{
171 assert(mfe != NULL);
172 fMfe = mfe;
173};
174
176{
177 CloseBuffer();
178
179 // poison all pointers
180 fMfe = NULL;
181};
182
184{
185 if (fBufHandle) {
186 return TMFeErrorMessage(msprintf("Event buffer \"%s\" is already open", fBufName.c_str()));
187 }
188
190
191 if (bufsize == 0)
193
195
196 if (status != BM_SUCCESS && status != BM_CREATED) {
197 return TMFeMidasError(msprintf("Cannot open event buffer \"%s\"", fBufName.c_str()), "bm_open_buffer", status);
198 }
199
200 fBufSize = 0;
202
203 uint32_t buf_size = 0;
205
206 fMfe->fOdbRoot->RU32("Experiment/MAX_EVENT_SIZE", &max_event_size);
207 fMfe->fOdbRoot->RU32((std::string("Experiment/Buffer Sizes/") + bufname).c_str(), &buf_size);
208
209 if (buf_size > 0) {
210 // limit event size to half the buffer size, so we can buffer two events
211 uint32_t xmax_event_size = buf_size / 2;
212 // add extra margin
213 if (xmax_event_size > 1024)
214 xmax_event_size -= 1024;
217 }
218
219 fBufSize = buf_size;
221
222 if (fBufSize == 0) {
223 return TMFeErrorMessage(msprintf("Cannot get buffer size for event buffer \"%s\"", fBufName.c_str()));
224 }
225
226 if (fBufMaxEventSize == 0) {
227 return TMFeErrorMessage(msprintf("Cannot get MAX_EVENT_SIZE for event buffer \"%s\"", fBufName.c_str()));
228 }
229
230 printf("TMEventBuffer::OpenBuffer: Buffer \"%s\" size %d, max event size %d\n", fBufName.c_str(), (int)fBufSize, (int)fBufMaxEventSize);
231
232 return TMFeOk();
233}
234
236{
237 if (!fBufHandle)
238 return TMFeOk();
239
240 fBufRequests.clear(); // no need to cancel individual requests, they are gone after we close the buffer
241
243
244 if (status != BM_SUCCESS) {
245 fBufHandle = 0;
246 return TMFeMidasError(msprintf("Cannot close event buffer \"%s\"", fBufName.c_str()), "bm_close_buffer", status);
247 }
248
249 fBufHandle = 0;
250 fBufSize = 0;
254
255 return TMFeOk();
256}
257
258TMFeResult TMEventBuffer::SetCacheSize(size_t read_cache_size, size_t write_cache_size)
259{
260 int status = bm_set_cache_size(fBufHandle, read_cache_size, write_cache_size);
261
262 if (status != BM_SUCCESS) {
263 return TMFeMidasError(msprintf("Cannot set event buffer \"%s\" cache sizes: read %d, write %d", fBufName.c_str(), (int)read_cache_size, (int)write_cache_size), "bm_set_cache_size", status);
264 }
265
266 fBufReadCacheSize = read_cache_size;
267 fBufWriteCacheSize = write_cache_size;
268
269 return TMFeOk();
270}
271
273{
274 if (!fBufHandle) {
275 return TMFeErrorMessage(msprintf("AddRequest: Error: Event buffer \"%s\" is not open", fBufName.c_str()));
276 }
277
278 int sampling_type = 0;
279
280 if (strcmp(sampling_type_string, "GET_ALL")==0) {
281 sampling_type = GET_ALL;
282 } else if (strcmp(sampling_type_string, "GET_NONBLOCKING")==0) {
283 sampling_type = GET_NONBLOCKING;
284 } else if (strcmp(sampling_type_string, "GET_RECENT")==0) {
285 sampling_type = GET_RECENT;
286 } else {
287 sampling_type = GET_ALL;
288 }
289
290 int request_id = 0;
291
292 int status = bm_request_event(fBufHandle, event_id, trigger_mask, sampling_type, &request_id, NULL);
293
294 if (status != BM_SUCCESS) {
295 return TMFeMidasError(msprintf("Cannot make event request on buffer \"%s\"", fBufName.c_str()), "bm_request_event", status);
296 }
297
298 fBufRequests.push_back(request_id);
299
300 return TMFeOk();
301}
302
304{
305 if (!fBufHandle) {
306 return TMFeErrorMessage(msprintf("ReceiveEvent: Error: Event buffer \"%s\" is not open", fBufName.c_str()));
307 }
308
309 assert(e != NULL);
310
311 e->resize(0);
312
314
315 if (status == BM_ASYNC_RETURN) {
316 return TMFeOk();
317 }
318
319 if (status != BM_SUCCESS) {
320 return TMFeMidasError(msprintf("Cannot receive event on buffer \"%s\"", fBufName.c_str()), "bm_receive_event", status);
321 }
322
323 return TMFeOk();
324}
325
327{
328 const EVENT_HEADER *pevent = (const EVENT_HEADER*)e;
329 const size_t event_size = sizeof(EVENT_HEADER) + pevent->data_size;
330 //const size_t total_size = ALIGN8(event_size);
331 return SendEvent(1, &e, &event_size);
332}
333
334TMFeResult TMEventBuffer::SendEvent(const std::vector<char>& e)
335{
336 const EVENT_HEADER *pevent = (const EVENT_HEADER*)e.data();
337 const size_t event_size = sizeof(EVENT_HEADER) + pevent->data_size;
338 //const size_t total_size = ALIGN8(event_size);
339 if (e.size() != event_size) {
340 return TMFeErrorMessage(msprintf("Cannot send event, size mismatch: vector size %d, data_size %d, event_size %d", (int)e.size(), (int)pevent->data_size, (int)event_size).c_str());
341 }
342
343 return SendEvent(1, (char**)&pevent, &event_size);
344}
345
346TMFeResult TMEventBuffer::SendEvent(const std::vector<std::vector<char>>& e)
347{
348 int sg_n = e.size();
349 const char* sg_ptr[sg_n];
350 size_t sg_len[sg_n];
351 for (int i=0; i<sg_n; i++) {
352 sg_ptr[i] = e[i].data();
353 sg_len[i] = e[i].size();
354 }
355 return SendEvent(sg_n, sg_ptr, sg_len);
356}
357
358TMFeResult TMEventBuffer::SendEvent(int sg_n, const char* const sg_ptr[], const size_t sg_len[])
359{
361
362 if (status == BM_CORRUPTED) {
363 fMfe->Msg(MERROR, "TMEventBuffer::SendEvent", "Cannot send event to buffer \"%s\": bm_send_event() returned %d, event buffer is corrupted, shutting down the frontend", fBufName.c_str(), status);
364 fMfe->fShutdownRequested = true;
365 return TMFeMidasError("Cannot send event, event buffer is corrupted, shutting down the frontend", "bm_send_event", status);
366 } else if (status != BM_SUCCESS) {
367 fMfe->Msg(MERROR, "TMEventBuffer::SendEvent", "Cannot send event to buffer \"%s\": bm_send_event() returned %d", fBufName.c_str(), status);
368 return TMFeMidasError("Cannot send event", "bm_send_event", status);
369 }
370
371 return TMFeOk();
372}
373
375{
376 if (!fBufHandle)
377 return TMFeOk();
378
379 int flag = BM_NO_WAIT;
380 if (wait)
381 flag = BM_WAIT;
382
383 /* flush of event socket in no-wait mode does nothing */
384 if (wait && rpc_is_remote()) {
385 int status = bm_flush_cache(0, flag);
386
387 //printf("bm_flush_cache(0,%d) status %d\n", flag, status);
388
389 if (status == BM_SUCCESS) {
390 // nothing
391 } else if (status == BM_ASYNC_RETURN) {
392 // nothing
393 } else {
394 return TMFeMidasError("Cannot flush mserver event socket", "bm_flush_cache", status);
395 }
396 }
397
399
400 //printf("bm_flush_cache(%d,%d) status %d\n", fBufHandle, flag, status);
401
402 if (status == BM_SUCCESS) {
403 // nothing
404 } else if (status == BM_ASYNC_RETURN) {
405 // nothing
406 } else {
407 return TMFeMidasError(msprintf("Cannot flush event buffer \"%s\"", fBufName.c_str()).c_str(), "bm_flush_cache", status);
408 }
409
410 return TMFeOk();
411}
412
414{
415 assert(pbuf != NULL);
416 assert(bufname != NULL);
417
418 std::lock_guard<std::mutex> guard(fEventBuffersMutex);
419
420 for (auto b : fEventBuffers) {
421 if (!b)
422 continue;
423
424 if (b->fBufName == bufname) {
425 *pbuf = b;
426 if (bufsize != 0 && bufsize > b->fBufSize) {
427 Msg(MERROR, "TMFE::EventBufferOpen", "Event buffer \"%s\" size %d is smaller than requested size %d", b->fBufName.c_str(), (int)b->fBufSize, (int)bufsize);
428 }
429 return TMFeOk();
430 }
431 }
432
433 TMEventBuffer *b = new TMEventBuffer(this);
434
435 fEventBuffers.push_back(b);
436
437 *pbuf = b;
438
440
441 if (r.error_flag) {
442 return r;
443 }
444
445 return TMFeOk();
446}
447
449{
450 int flag = BM_NO_WAIT;
451 if (wait)
452 flag = BM_WAIT;
453
454 /* flush of event socket in no-wait mode does nothing */
455 if (wait && rpc_is_remote()) {
456 int status = bm_flush_cache(0, flag);
457
458 //printf("bm_flush_cache(0,%d) status %d\n", flag, status);
459
460 if (status == BM_SUCCESS) {
461 // nothing
462 } else if (status == BM_ASYNC_RETURN) {
463 // nothing
464 } else {
465 return TMFeMidasError("Cannot flush mserver event socket", "bm_flush_cache", status);
466 }
467 }
468
469 std::lock_guard<std::mutex> guard(fEventBuffersMutex);
470
471 for (auto b : fEventBuffers) {
472 if (!b)
473 continue;
474
475 TMFeResult r = b->FlushCache(wait);
476
477 if (r.error_flag)
478 return r;
479 }
480
481 return TMFeOk();
482}
483
485{
486 std::lock_guard<std::mutex> guard(fEventBuffersMutex);
487
488 for (auto b : fEventBuffers) {
489 if (!b)
490 continue;
491 TMFeResult r = b->CloseBuffer();
492 if (r.error_flag)
493 return r;
494
495 delete b;
496 }
497
498 fEventBuffers.clear();
499
500 return TMFeOk();
501}
502
504// equipment functions
506
508{
509 double now = TMFE::GetTime();
510
511 double next_periodic = now + 60;
512
513 int n = fFeEquipments.size();
514 for (int i=0; i<n; i++) {
516 if (!eq)
517 continue;
518 if (!eq->fEqConfEnabled)
519 continue;
520 if (!eq->fEqConfEnablePeriodic)
521 continue;
522 double period = eq->fEqConfPeriodMilliSec/1000.0;
523 if (period <= 0)
524 continue;
525 if (eq->fEqPeriodicNextCallTime == 0)
526 eq->fEqPeriodicNextCallTime = now + 0.5; // we are off by 0.5 sec with updating of statistics
527 //printf("periodic[%d] period %f, last call %f, next call %f (%f)\n", i, period, eq->fEqPeriodicLastCallTime, eq->fEqPeriodicNextCallTime, now - eq->fEqPeriodicNextCallTime);
528 if (now >= eq->fEqPeriodicNextCallTime) {
529 eq->fEqPeriodicNextCallTime += period;
530
531 if (eq->fEqPeriodicNextCallTime < now) {
532 if (TMFE::gfVerbose)
533 printf("TMFE::EquipmentPeriodicTasks: periodic equipment \"%s\" skipped some beats!\n", eq->fEqName.c_str());
534 fMfe->Msg(MERROR, "TMFE::EquipmentPeriodicTasks", "Equipment \"%s\" skipped some beats!", eq->fEqName.c_str());
535 while (eq->fEqPeriodicNextCallTime < now) {
536 eq->fEqPeriodicNextCallTime += period;
537 }
538 }
539
540 if (fMfe->fStateRunning || !eq->fEqConfReadOnlyWhenRunning) {
541 eq->fEqPeriodicLastCallTime = now;
542 //printf("handler %d eq [%s] call HandlePeriodic()\n", i, h->fEq->fName.c_str());
543 eq->HandlePeriodic();
544 }
545
546 now = TMFE::GetTime();
547 }
548
549 if (eq->fEqPeriodicNextCallTime < next_periodic)
550 next_periodic = eq->fEqPeriodicNextCallTime;
551 }
552
553 now = TMFE::GetTime();
554
555 // update statistics
556 for (auto eq : fFeEquipments) {
557 if (!eq)
558 continue;
559 if (!eq->fEqConfEnabled)
560 continue;
561 double next = eq->fEqStatNextWrite; // NOTE: this is not thread-safe, possible torn read of "double"
562 if (now > next) {
563 eq->EqWriteStatistics();
564 next = eq->fEqStatNextWrite; // NOTE: this is not thread-safe, possible torn read of "double"
565 }
566 if (next < next_periodic)
567 next_periodic = next;
568 }
569
570 now = TMFE::GetTime();
571
572 // flush write cache
578 }
579
580 return next_periodic;
581}
582
584{
585 //printf("poll %f next %f diff %f\n", TMFE::GetTime(), next_periodic_time, next_periodic_time - TMFE::GetTime());
586
587 double poll_sleep_sec = 9999.0;
588 while (!fMfe->fShutdownRequested) {
589 bool poll_again = false;
590 // NOTE: ok to use range-based for() loop, there will be a crash if HandlePoll() or HandlePollRead() modify fEquipments, so they should not do that. K.O.
591 for (auto eq : fFeEquipments) {
592 if (!eq)
593 continue;
594 if (!eq->fEqConfEnabled)
595 continue;
596 if (eq->fEqConfEnablePoll && !eq->fEqPollThreadRunning && !eq->fEqPollThreadStarting) {
597 if (fMfe->fStateRunning || !eq->fEqConfReadOnlyWhenRunning) {
598 if (eq->fEqConfPollSleepSec < poll_sleep_sec)
599 poll_sleep_sec = eq->fEqConfPollSleepSec;
600 bool poll = eq->HandlePoll();
601 if (poll) {
602 poll_again = true;
603 eq->HandlePollRead();
604 }
605 }
606 }
607 }
608 if (!poll_again)
609 break;
610
611 if (next_periodic_time) {
612 // stop polling if we need to run periodic activity
613 double now = TMFE::TMFE::GetTime();
614 if (now >= next_periodic_time)
615 break;
616 }
617 }
618 return poll_sleep_sec;
619}
620
622{
623 if (TMFE::gfVerbose)
624 printf("TMFeEquipment::EqPollThread: equipment \"%s\" poll thread started\n", fEqName.c_str());
625
627
630 bool poll = HandlePoll();
631 if (poll) {
633 } else {
634 if (fEqConfPollSleepSec > 0) {
636 }
637 }
638 } else {
639 TMFE::Sleep(0.1);
640 }
641 }
642 if (TMFE::gfVerbose)
643 printf("TMFeEquipment::EqPollThread: equipment \"%s\" poll thread stopped\n", fEqName.c_str());
644
645 fEqPollThreadRunning = false;
646}
647
649{
650 // NOTE: this is thread safe
651
652 std::lock_guard<std::mutex> guard(fEqMutex);
653
655 fMfe->Msg(MERROR, "TMFeEquipment::EqStartPollThread", "Equipment \"%s\": poll thread is already running", fEqName.c_str());
656 return;
657 }
658
661
662 fEqPollThread = new std::thread(&TMFeEquipment::EqPollThread, this);
663}
664
666{
667 // NOTE: this is thread safe
668 fEqPollThreadStarting = false;
670 for (int i=0; i<100; i++) {
672 std::lock_guard<std::mutex> guard(fEqMutex);
673 if (fEqPollThread) {
674 fEqPollThread->join();
675 delete fEqPollThread;
677 }
678 return;
679 }
680 TMFE::Sleep(0.1);
681 }
683 fMfe->Msg(MERROR, "TMFeEquipment::EqStopPollThread", "Equipment \"%s\": timeout waiting for shutdown of poll thread", fEqName.c_str());
684 }
685}
686
688{
690
691 int status = cm_transition(TR_STOP, 0, str, sizeof(str), TR_SYNC, FALSE);
692 if (status != CM_SUCCESS) {
693 Msg(MERROR, "TMFE::StopRun", "Cannot stop run, error: %s", str);
694 fRunStopRequested = false;
695 return;
696 }
697
698 fRunStopRequested = false;
699
700 bool logger_auto_restart = false;
701 fOdbRoot->RB("Logger/Auto restart", &logger_auto_restart);
702
704 fOdbRoot->RI("Logger/Auto restart delay", &logger_auto_restart_delay);
705
707 Msg(MINFO, "TMFE::StopRun", "Run will restart after %d seconds", logger_auto_restart_delay);
709 } else {
710 fRunStartTime = 0;
711 }
712}
713
715{
716 fRunStartTime = 0;
717
718 /* check if really stopped */
719 int run_state = 0;
720 fOdbRoot->RI("Runinfo/State", &run_state);
721
722 if (run_state != STATE_STOPPED) {
723 Msg(MERROR, "TMFE::StartRun", "Run start requested, but run is already in progress");
724 return;
725 }
726
727 bool logger_auto_restart = false;
728 fOdbRoot->RB("Logger/Auto restart", &logger_auto_restart);
729
730 if (!logger_auto_restart) {
731 Msg(MERROR, "TMFE::StartRun", "Run start requested, but logger/auto restart is off");
732 return;
733 }
734
735 Msg(MTALK, "TMFE::StartRun", "Starting new run");
736
738
739 int status = cm_transition(TR_START, 0, str, sizeof(str), TR_SYNC, FALSE);
740 if (status != CM_SUCCESS) {
741 Msg(MERROR, "TMFE::StartRun", "Cannot restart run, error: %s", str);
742 }
743}
744
746{
747 assert(sleep_sec >= 0);
748 bool debug = false;
749 double now = TMFE::GetTime();
750 double sleep_start = now;
751 double sleep_end = now + sleep_sec;
752 int count_yield_loops = 0;
753
754 while (!fMfe->fShutdownRequested) {
755 double next_periodic_time = 0;
756 double poll_sleep = 1.0;
757
761 } else {
763 }
764
765 if (fMfe->fRunStopRequested) {
766 fMfe->StopRun();
767 continue;
768 }
769
770 now = TMFE::GetTime();
771
773 fMfe->StartRun();
774 continue;
775 }
776
777 double sleep_time = sleep_end - now;
778
781 }
782
783 int s = 0;
784 if (sleep_time > 0)
785 s = 1 + sleep_time*1000.0;
786
787 if (poll_sleep*1000.0 < s) {
788 s = 0;
789 }
790
791 if (debug) {
792 printf("now %.6f, sleep_end %.6f, next_periodic %.6f, sleep_time %.6f, cm_yield(%d), poll period %.6f\n", now, sleep_end, next_periodic_time, sleep_time, s, poll_sleep);
793 }
794
795 int status = cm_yield(s);
796
797 if (status == RPC_SHUTDOWN || status == SS_ABORT) {
798 fMfe->fShutdownRequested = true;
799 if (TMFE::gfVerbose) {
800 fprintf(stderr, "TMFE::PollMidas: cm_yield(%d) status %d, shutdown requested...\n", s, status);
801 }
802 }
803
804 now = TMFE::GetTime();
805 double sleep_more = sleep_end - now;
806 if (sleep_more <= 0)
807 break;
808
810
811 if (poll_sleep < sleep_more) {
813 }
814 }
815
816 if (debug) {
817 printf("TMFE::PollMidas: sleep %.1f msec, actual %.1f msec, %d loops\n", sleep_sec * 1000.0, (now - sleep_start) * 1000.0, count_yield_loops);
818 }
819}
820
822{
823 double now = GetTime();
824 //double sleep_start = now;
825 double sleep_end = now + sleep_sec;
826
827 while (!fShutdownRequested) {
828 now = GetTime();
829
830 double sleep_time = sleep_end - now;
831 int s = 0;
832 if (sleep_time > 0)
833 s = 1 + sleep_time*1000.0;
834
835 //printf("TMFE::Yield: now %f, sleep_end %f, s %d\n", now, sleep_end, s);
836
837 int status = cm_yield(s);
838
839 if (status == RPC_SHUTDOWN || status == SS_ABORT) {
840 fShutdownRequested = true;
841 fprintf(stderr, "TMFE::Yield: cm_yield(%d) status %d, shutdown requested...\n", s, status);
842 }
843
844 now = GetTime();
845 if (now >= sleep_end)
846 break;
847 }
848
849 //printf("TMFE::Yield: sleep_sec %.6f, actual %.6f sec\n", sleep_sec, now - sleep_start);
850}
851
856
858{
859 if (TMFE::gfVerbose)
860 printf("TMFE::RpcThread: RPC thread started\n");
861
862 int msec = 1000;
863
864 fRpcThreadRunning = true;
866
868
869 int status = cm_yield(msec);
870
871 if (status == RPC_SHUTDOWN || status == SS_ABORT) {
872 fShutdownRequested = true;
873 if (TMFE::gfVerbose)
874 printf("TMFE::RpcThread: cm_yield(%d) status %d, shutdown requested...\n", msec, status);
875 }
876 }
878 if (TMFE::gfVerbose)
879 printf("TMFE::RpcThread: RPC thread stopped\n");
880 fRpcThreadRunning = false;
881}
882
884{
885 if (TMFE::gfVerbose)
886 printf("TMFE::PeriodicThread: periodic thread started\n");
887
891 double now = TMFE::GetTime();
892 double sleep = next_periodic_time - now;
893 //printf("TMFrontend::FePeriodicThread: now %.6f next %.6f, sleep %.6f\n", now, next_periodic_time, sleep);
894 if (sleep >= 1.0)
895 sleep = 1.0;
897 }
898 if (TMFE::gfVerbose)
899 printf("TMFE::PeriodicThread: periodic thread stopped\n");
901}
902
904{
905 // NOTE: this is thread safe
906
907 std::lock_guard<std::mutex> guard(fMutex);
908
910 if (gfVerbose)
911 printf("TMFE::StartRpcThread: RPC thread already running\n");
912 return;
913 }
914
915 fRpcThreadStarting = true;
916 fRpcThread = new std::thread(&TMFE::RpcThread, this);
917}
918
920{
921 // NOTE: this is thread safe
922
923 std::lock_guard<std::mutex> guard(fFeMutex);
924
926 if (TMFE::gfVerbose)
927 printf("TMFE::StartPeriodicThread: periodic thread already running\n");
928 return;
929 }
930
932 fFePeriodicThread = new std::thread(&TMFrontend::FePeriodicThread, this);
933}
934
936{
937 // NOTE: this is thread safe
938
939 fRpcThreadStarting = false;
941
942 for (int i=0; i<60; i++) {
943 if (!fRpcThreadRunning) {
944 std::lock_guard<std::mutex> guard(fMutex);
945 if (fRpcThread) {
946 fRpcThread->join();
947 delete fRpcThread;
949 if (gfVerbose)
950 printf("TMFE::StopRpcThread: RPC thread stopped\n");
951 }
952 return;
953 }
954 if (i>5) {
955 fprintf(stderr, "TMFE::StopRpcThread: waiting for RPC thread to stop\n");
956 }
957 ::sleep(1);
958 }
959
960 fprintf(stderr, "TMFE::StopRpcThread: timeout waiting for RPC thread to stop\n");
961}
962
964{
965 // NOTE: this is thread safe
966
969
970 for (int i=0; i<60; i++) {
972 std::lock_guard<std::mutex> guard(fFeMutex);
973 if (fFePeriodicThread) {
974 fFePeriodicThread->join();
975 delete fFePeriodicThread;
977 if (TMFE::gfVerbose)
978 printf("TMFE::StopPeriodicThread: periodic thread stopped\n");
979 }
980 return;
981 }
982 if (i>5) {
983 fprintf(stderr, "TMFE::StopPeriodicThread: waiting for periodic thread to stop\n");
984 }
985 ::sleep(1);
986 }
987
988 fprintf(stderr, "TMFE::StopPeriodicThread: timeout waiting for periodic thread to stop\n");
989}
990
991void TMFE::Msg(int message_type, const char *filename, int line, const char *routine, const char *format, ...)
992{
993 char message[1024];
994 //printf("format [%s]\n", format);
995 va_list ap;
996 va_start(ap, format);
997 vsnprintf(message, sizeof(message)-1, format, ap);
998 va_end(ap);
999 //printf("message [%s]\n", message);
1000 cm_msg(message_type, filename, line, routine, "%s", message);
1002}
1003
1004void TMFE::Msg(int message_type, const char *filename, int line, const char *routine, const std::string& message)
1005{
1006 //printf("message [%s]\n", message.c_str());
1007 cm_msg(message_type, filename, line, routine, "%s", message.c_str());
1009}
1010
1012{
1013 struct timeval tv;
1014 gettimeofday(&tv, NULL);
1015 return tv.tv_sec*1.0 + tv.tv_usec/1000000.0;
1016}
1017
1018#if 1
1020{
1021 if (time_sec < 0) {
1022 TMFE::Instance()->Msg(MERROR, "TMFE::Sleep", "TMFE::Sleep() called with negative sleep time: %f", time_sec);
1023 return;
1024 }
1025
1026 if (time_sec == 0) {
1027 TMFE::Instance()->Msg(MERROR, "TMFE::Sleep", "TMFE::Sleep() called with zero sleep time");
1028 return;
1029 }
1030
1031 if (time_sec > 1.01) {
1032 // break long sleep into short sleeps
1033
1034 double t0 = TMFE::GetTime();
1035 double tend = t0 + time_sec;
1036
1037 while (1) {
1038 double now = TMFE::GetTime();
1039 if (now >= tend) {
1040 //printf("t0 %f, tend %f, now %f, done!\n", t0, tend, now);
1041 return;
1042 }
1043
1044 double tsleep = tend - now;
1045
1046 //printf("t0 %f, tend %f, now %f, tsleep %f!\n", t0, tend, now, tsleep);
1047
1048 if (tsleep > 1.0)
1049 tsleep = 1.0;
1050
1052 }
1053
1054 return;
1055 }
1056
1057 int status;
1058 struct timeval timeout;
1059
1060 timeout.tv_sec = time_sec;
1061 timeout.tv_usec = (time_sec-timeout.tv_sec)*1000000.0;
1062
1063 while (1) {
1064 status = select(0, NULL, NULL, NULL, &timeout);
1065#ifdef EINVAL
1066 if (status < 0 && errno == EINVAL) {
1067 // #warning HERE EINVAL!
1068 TMFE::Instance()->Msg(MERROR, "TMFE::Sleep", "TMFE::Sleep() called with invalid sleep time: %f, tv_sec: %lld, tv_usec: %lld", time_sec, (long long int)timeout.tv_sec, (long long int)timeout.tv_usec);
1069 return;
1070 }
1071#endif
1072#ifdef EINTR
1073 if (status < 0 && errno == EINTR) {
1074 // #warning HERE EINTR!
1075 // NOTE1: on linux, "timeout" is modified by the kernel to subtract time already slept, we do not need to adjust it while handling EINTR.
1076 // NOTE2: on macos and other BSD-based systems, "timeout" value is not changed, and for accurate sleeping we should modify here, to account for time already slept, but we do not.
1077 // NOTE3: see "man select" on Linux and Macos.
1078 // NOTE4: MIDAS no longer uses SIGALRM to run cm_watchdog() and MIDAS applications do nto use signals.
1079 // NOTE4: so in theory, we do not have to worry about EINTR interrupting our sleep. K.O. Dec-2024
1080 // TMFE::Instance()->Msg(MERROR, "TMFE::Sleep", "TMFE::Sleep() EINTR, sleep time: %f, tv_sec: %lld, tv_usec: %lld", time_sec, (long long int)timeout.tv_sec, (long long int)timeout.tv_usec);
1081 continue;
1082 }
1083#endif
1084 break;
1085 }
1086
1087 if (status < 0) {
1088 TMFE::Instance()->Msg(MERROR, "TMFE::Sleep", "select() returned %d, errno %d (%s)", status, errno, strerror(errno));
1089 }
1090}
1091#endif
1092
1093#if 0
1094void TMFE::Sleep(double time)
1095{
1096 struct timespec rqtp;
1097 struct timespec rmtp;
1098
1099 rqtp.tv_sec = time;
1100 rqtp.tv_nsec = (time-rqtp.tv_sec)*1000000000.0;
1101
1102 int status = nanosleep(&rqtp, &rmtp);
1103
1104 //#ifdef EINTR
1105 //if (status < 0 && errno == EINTR) {
1106 // return 0; // watchdog interrupt, try again
1107 //}
1108 //#endif
1109
1110 if (status < 0) {
1111 TMFE::Instance()->Msg(MERROR, "TMFE::Sleep", "nanosleep() returned %d, errno %d (%s)", status, errno, strerror(errno));
1112 }
1113}
1114#endif
1115
1116#if 0
1117void TMFE::Sleep(double time)
1118{
1119 struct timespec rqtp;
1120 struct timespec rmtp;
1121
1122 rqtp.tv_sec = time;
1123 rqtp.tv_nsec = (time-rqtp.tv_sec)*1000000000.0;
1124
1125 //int status = clock_nanosleep(CLOCK_REALTIME, 0, &rqtp, &rmtp);
1127
1128 //#ifdef EINTR
1129 //if (status < 0 && errno == EINTR) {
1130 // return 0; // watchdog interrupt, try again
1131 //}
1132 //#endif
1133
1134 if (status < 0) {
1135 TMFE::Instance()->Msg(MERROR, "TMFE::Sleep", "nanosleep() returned %d, errno %d (%s)", status, errno, strerror(errno));
1136 }
1137}
1138#endif
1139
1140std::string TMFE::GetThreadId()
1141{
1142 return ss_tid_to_string(ss_gettid());
1143}
1144
1146{
1147 const char* cmd = CSTRING(0);
1148 const char* args = CSTRING(1);
1149 char* return_buf = CSTRING(2);
1150 int return_max_length = CINT(3);
1151
1152 if (TMFE::gfVerbose)
1153 printf("TMFE::rpc_callback: index %d, max_length %d, cmd [%s], args [%s]\n", index, return_max_length, cmd, args);
1154
1155 TMFE* mfe = TMFE::Instance();
1156
1157 // NOTE: cannot use range-based for() loop, it uses an iterator and will crash if HandleRpc() modifies fEquipments. K.O.
1158 for (unsigned i=0; i<mfe->fRpcHandlers.size(); i++) {
1159 TMFeRpcHandlerInterface* h = mfe->fRpcHandlers[i];
1160 if (!h)
1161 continue;
1162 std::string result = "";
1163 TMFeResult r = h->HandleRpc(cmd, args, result);
1164 if (result.length() > 0) {
1165 //printf("Handler reply [%s]\n", C(r));
1166 mstrlcpy(return_buf, result.c_str(), return_max_length);
1167 return RPC_SUCCESS;
1168 }
1169 }
1170
1171 return_buf[0] = 0;
1172 return RPC_SUCCESS;
1173}
1174
1176{
1177 const char* cmd = CSTRING(0);
1178 const char* args = CSTRING(1);
1179 char* return_buf = CSTRING(2);
1180 size_t return_max_length = CINT(3);
1181
1182 if (TMFE::gfVerbose)
1183 printf("TMFE::binary_rpc_callback: index %d, max_length %zu, cmd [%s], args [%s]\n", index, return_max_length, cmd, args);
1184
1185 TMFE* mfe = TMFE::Instance();
1186
1187 // NOTE: cannot use range-based for() loop, it uses an iterator and will crash if HandleRpc() modifies fEquipments. K.O.
1188 for (unsigned i=0; i<mfe->fRpcHandlers.size(); i++) {
1189 TMFeRpcHandlerInterface* h = mfe->fRpcHandlers[i];
1190 if (!h)
1191 continue;
1192 std::vector<char> result;
1193 TMFeResult r = h->HandleBinaryRpc(cmd, args, result);
1194 if (result.size() > 0) {
1195 if (result.size() > return_max_length) {
1196 TMFE::Instance()->Msg(MERROR, "TMFE::binary_rpc_callback", "RPC handler returned too much data, %zu bytes truncated to %zu bytes", result.size(), return_max_length);
1197 result.resize(return_max_length);
1198 }
1199 //printf("Handler reply [%s]\n", C(r));
1200 assert(result.size() <= return_max_length);
1201 memcpy(return_buf, result.data(), result.size());
1202 CINT(3) = result.size();
1203 return RPC_SUCCESS;
1204 }
1205 }
1206
1207 CINT(3) = 0;
1208 return_buf[0] = 0;
1209 return RPC_SUCCESS;
1210}
1211
1213{
1214public:
1216
1217public:
1219 {
1220 if (TMFE::gfVerbose)
1221 printf("TMFrontendRpcHelper::ctor!\n");
1222
1223 fFe = fe;
1224 }
1225
1226 virtual ~TMFrontendRpcHelper() // dtor
1227 {
1228 if (TMFE::gfVerbose)
1229 printf("TMFrontendRpcHelper::dtor!\n");
1230
1231 // poison pointers
1232 fFe = NULL;
1233 }
1234
1236 {
1237 if (TMFE::gfVerbose)
1238 printf("TMFrontendRpcHelper::HandleBeginRun!\n");
1239
1240 for (unsigned i=0; i<fFe->fFeEquipments.size(); i++) {
1242 if (!eq)
1243 continue;
1244 if (!eq->fEqConfEnabled)
1245 continue;
1246 eq->EqZeroStatistics();
1247 eq->EqWriteStatistics();
1248 }
1249 return TMFeOk();
1250 }
1251
1253 {
1254 if (TMFE::gfVerbose)
1255 printf("TMFrontendRpcHelper::HandleEndRun!\n");
1256
1257 for (unsigned i=0; i<fFe->fFeEquipments.size(); i++) {
1259 if (!eq)
1260 continue;
1261 if (!eq->fEqConfEnabled)
1262 continue;
1263 eq->EqWriteStatistics();
1264 }
1265
1267
1268 if (r.error_flag)
1269 return r;
1270
1271 return TMFeOk();
1272 }
1273};
1274
1275static INT tr_start(INT run_number, char *errstr)
1276{
1277 if (TMFE::gfVerbose)
1278 printf("TMFE::tr_start!\n");
1279
1280 TMFE* mfe = TMFE::Instance();
1281
1282 mfe->fRunNumber = run_number;
1283 mfe->fStateRunning = true;
1284
1285 TMFeResult result;
1286
1287 // NOTE: cannot use range-based for() loop, it uses an iterator and will crash if HandleBeginRun() modifies fEquipments. K.O.
1288 for (unsigned i=0; i<mfe->fRpcHandlers.size(); i++) {
1289 TMFeRpcHandlerInterface* h = mfe->fRpcHandlers[i];
1290 if (!h)
1291 continue;
1292 result = h->HandleBeginRun(run_number);
1293 if (result.error_flag) {
1294 // error handling in this function matches general transition error handling:
1295 // on run start, the first user handler to return an error code
1296 // will abort the transition. This leaves everything in an
1297 // inconsistent state: frontends called before the abort
1298 // think the run is running, which it does not. They should register
1299 // a handler for the "start abort" transition. This transition calls
1300 // all already started frontends so they can cleanup their state. K.O.
1301 //
1302 break;
1303 }
1304 }
1305
1306 if (result.error_flag) {
1307 mstrlcpy(errstr, result.error_message.c_str(), TRANSITION_ERROR_STRING_LENGTH);
1308 return FE_ERR_DRIVER;
1309 }
1310
1311 return SUCCESS;
1312}
1313
1314static INT tr_stop(INT run_number, char *errstr)
1315{
1316 if (TMFE::gfVerbose)
1317 printf("TMFE::tr_stop!\n");
1318
1319 TMFeResult result;
1320
1321 TMFE* mfe = TMFE::Instance();
1322
1323 // NOTE: cannot use range-based for() loop, it uses an iterator and will crash if HandleEndRun() modifies fEquipments. K.O.
1324 // NOTE: we need to stop thing in reverse order, otherwise TMFrontend code
1325 // does not work right - TMFrontend is registered first, and (correctly) runs
1326 // first at begin of run (to clear statistics, etc). But at the end of run
1327 // it needs to run last, to update the statistics, etc. after all the equipments
1328 // have done their end of run things and are finished. K.O.
1329 for (int i = (int)mfe->fRpcHandlers.size() - 1; i >= 0; i--) {
1330 TMFeRpcHandlerInterface* h = mfe->fRpcHandlers[i];
1331 if (!h)
1332 continue;
1334 if (xresult.error_flag) {
1335 // error handling in this function matches general transition error handling:
1336 // the "run stop" transition is always sucessful, the run always stops.
1337 // if some frontend returns an error, this error is remembered and is returned
1338 // as the transition over all status. K.O.
1339 result = xresult;
1340 }
1341 }
1342
1343 mfe->fStateRunning = false;
1344
1345 if (result.error_flag) {
1346 mstrlcpy(errstr, result.error_message.c_str(), TRANSITION_ERROR_STRING_LENGTH);
1347 return FE_ERR_DRIVER;
1348 }
1349
1350 return SUCCESS;
1351}
1352
1353static INT tr_pause(INT run_number, char *errstr)
1354{
1355 cm_msg(MINFO, "tr_pause", "tr_pause");
1356
1357 TMFeResult result;
1358
1359 TMFE* mfe = TMFE::Instance();
1360
1361 // NOTE: cannot use range-based for() loop, it uses an iterator and will crash if HandlePauseRun() modifies fEquipments. K.O.
1362 // NOTE: tr_pause runs in reverse order to match tr_stop. K.O.
1363 for (int i = (int)mfe->fRpcHandlers.size() - 1; i >= 0; i--) {
1364 TMFeRpcHandlerInterface* h = mfe->fRpcHandlers[i];
1365 if (!h)
1366 continue;
1367 result = h->HandlePauseRun(run_number);
1368 if (result.error_flag) {
1369 // error handling in this function matches general transition error handling:
1370 // logic is same as "start run"
1371 break;
1372 }
1373 }
1374
1375 if (result.error_flag) {
1376 mstrlcpy(errstr, result.error_message.c_str(), TRANSITION_ERROR_STRING_LENGTH);
1377 return FE_ERR_DRIVER;
1378 }
1379
1380 return SUCCESS;
1381}
1382
1383static INT tr_resume(INT run_number, char *errstr)
1384{
1385 if (TMFE::gfVerbose)
1386 printf("TMFE::tr_resume!\n");
1387
1388 TMFeResult result;
1389
1390 TMFE* mfe = TMFE::Instance();
1391
1392 mfe->fRunNumber = run_number;
1393 mfe->fStateRunning = true;
1394
1395 // NOTE: cannot use range-based for() loop, it uses an iterator and will crash if HandleResumeRun() modifies fEquipments. K.O.
1396 for (unsigned i=0; i<mfe->fRpcHandlers.size(); i++) {
1397 TMFeRpcHandlerInterface* h = mfe->fRpcHandlers[i];
1398 if (!h)
1399 continue;
1400 result = h->HandleResumeRun(run_number);
1401 if (result.error_flag) {
1402 // error handling in this function matches general transition error handling:
1403 // logic is same as "start run"
1404 break;
1405 }
1406 }
1407
1408 if (result.error_flag) {
1409 mstrlcpy(errstr, result.error_message.c_str(), TRANSITION_ERROR_STRING_LENGTH);
1410 return FE_ERR_DRIVER;
1411 }
1412
1413 return SUCCESS;
1414}
1415
1416static INT tr_startabort(INT run_number, char *errstr)
1417{
1418 if (TMFE::gfVerbose)
1419 printf("TMFE::tr_startabort!\n");
1420
1421 TMFeResult result;
1422
1423 TMFE* mfe = TMFE::Instance();
1424
1425 // NOTE: cannot use range-based for() loop, it uses an iterator and will crash if HandleStartAbortRun() modifies fEquipments. K.O.
1426 for (unsigned i=0; i<mfe->fRpcHandlers.size(); i++) {
1427 TMFeRpcHandlerInterface* h = mfe->fRpcHandlers[i];
1428 if (!h)
1429 continue;
1430 result = h->HandleStartAbortRun(run_number);
1431 if (result.error_flag) {
1432 // error handling in this function matches general transition error handling:
1433 // logic is same as "start run"
1434 break;
1435 }
1436 }
1437
1438 mfe->fStateRunning = false;
1439
1440 if (result.error_flag) {
1441 mstrlcpy(errstr, result.error_message.c_str(), TRANSITION_ERROR_STRING_LENGTH);
1442 return FE_ERR_DRIVER;
1443 }
1444
1445 return SUCCESS;
1446}
1447
1452
1457
1462
1467
1472
1481
1486
1491
1496
1501
1506
1511
1525
1527{
1528 fRpcHandlers.push_back(h);
1529}
1530
1532{
1533 for (unsigned i=0; i<fRpcHandlers.size(); i++) {
1534 if (fRpcHandlers[i] == h) {
1535 fRpcHandlers[i] = NULL;
1536 }
1537 }
1538}
1539
1541{
1542 fMfe = TMFE::Instance();
1543}
1544
1546{
1547 if (fFeRpcHelper) {
1549 delete fFeRpcHelper;
1551 }
1552 // poison all pointers
1553 fMfe = NULL;
1554}
1555
1556TMFeResult TMFrontend::FeInitEquipments(const std::vector<std::string>& args)
1557{
1558 // NOTE: cannot use range-based for() loop, it uses an iterator and will crash if HandleInit() modifies fEquipments. K.O.
1559 for (unsigned i=0; i<fFeEquipments.size(); i++) {
1560 if (!fFeEquipments[i])
1561 continue;
1562 if (!fFeEquipments[i]->fEqConfEnabled)
1563 continue;
1564 TMFeResult r = fFeEquipments[i]->EqInit(args);
1565 if (r.error_flag)
1566 return r;
1567 }
1568 return TMFeOk();
1569}
1570
1572{
1573 // NOTE: should not use range-based for() loop, it uses an iterator and it not thread-safe. K.O.
1574 for (unsigned i=0; i<fFeEquipments.size(); i++) {
1575 if (!fFeEquipments[i])
1576 continue;
1577 fFeEquipments[i]->EqStopPollThread();
1578 }
1579}
1580
1582{
1583 // NOTE: this is thread-safe: we do not modify the fEquipments object. K.O.
1584 // NOTE: this is not thread-safe, we will race against ourselves and do multiple delete of fEquipents[i]. K.O.
1585
1586 // NOTE: should not use range-based for() loop, it uses an iterator and it not thread-safe. K.O.
1587 for (unsigned i=0; i<fFeEquipments.size(); i++) {
1588 if (!fFeEquipments[i])
1589 continue;
1590 //printf("delete equipment [%s]\n", fFeEquipments[i]->fEqName.c_str());
1592 delete fFeEquipments[i];
1593 fFeEquipments[i] = NULL;
1594 }
1595
1598}
1599
1601{
1602 // NOTE: not thread-safe, we modify the fEquipments object. K.O.
1603
1604 // NOTE: should not use range-based for() loop, it uses an iterator and it not thread-safe. K.O.
1605 for (unsigned i=0; i<fFeEquipments.size(); i++) {
1606 if (!fFeEquipments[i])
1607 continue;
1608 if (fFeEquipments[i] == eq) {
1609 fprintf(stderr, "TMFE::AddEquipment: Fatal error: Equipment \"%s\" is already registered, bye...\n", fFeEquipments[i]->fEqName.c_str());
1610 fMfe->Disconnect();
1611 exit(1);
1612 //return TMFeErrorMessage(msprintf("TMFE::AddEquipment: Equipment \"%s\" is already registered", fFeEquipments[i]->fEqName.c_str()));
1613 }
1614 if (fFeEquipments[i]->fEqName == eq->fEqName) {
1615 fprintf(stderr, "TMFE::AddEquipment: Fatal error: Duplicate equipment name \"%s\", bye...\n", eq->fEqName.c_str());
1616 fMfe->Disconnect();
1617 exit(1);
1618 //return TMFeErrorMessage(std::string("TMFE::AddEquipment: Duplicate equipment name \"") + eq->fEqName + "\"");
1619 }
1620 }
1621
1622 eq->fFe = this;
1623
1624 // NOTE: fEquipments must be protected again multithreaded access here. K.O.
1625 fFeEquipments.push_back(eq);
1626
1627 return TMFeOk();
1628}
1629
1631{
1632 // NOTE: this is thread-safe, we do not modify the fEquipments object. K.O.
1633
1634 // NOTE: should not use range-based for() loop, it uses an iterator and it not thread-safe. K.O.
1635 for (unsigned i=0; i<fFeEquipments.size(); i++) {
1636 if (!fFeEquipments[i])
1637 continue;
1638 if (fFeEquipments[i] == eq) {
1639 fFeEquipments[i] = NULL;
1640 return TMFeOk();
1641 }
1642 }
1643
1644 return TMFeErrorMessage(msprintf("TMFE::RemoveEquipment: Cannot find equipment \"%s\"", eq->fEqName.c_str()));
1645}
1646
1648{
1649 assert(program_name != NULL);
1651}
1652
1653TMFeEquipment::TMFeEquipment(const char* eqname, const char* eqfilename) // ctor
1654{
1655 assert(eqname != NULL);
1656 assert(eqfilename != NULL);
1657
1658 if (TMFE::gfVerbose)
1659 printf("TMFeEquipment::ctor: equipment name [%s] file [%s]\n", eqname, eqfilename);
1660
1661 fMfe = TMFE::Instance();
1662 fEqName = eqname;
1665}
1666
1668{
1669 if (TMFE::gfVerbose)
1670 printf("TMFeEquipment::dtor: equipment name [%s]\n", fEqName.c_str());
1671
1673
1674 // free data and poison pointers
1675 if (fOdbEq) {
1676 delete fOdbEq;
1677 fOdbEq = NULL;
1678 }
1679 if (fOdbEqCommon) {
1680 delete fOdbEqCommon;
1682 }
1683 if (fOdbEqSettings) {
1684 delete fOdbEqSettings;
1686 }
1687 if (fOdbEqVariables) {
1688 delete fOdbEqVariables;
1690 }
1691 if (fOdbEqStatistics) {
1692 delete fOdbEqStatistics;
1694 }
1695 fMfe = NULL;
1696 fFe = NULL;
1698}
1699
1700TMFeResult TMFeEquipment::EqInit(const std::vector<std::string>& args)
1701{
1702 TMFeResult r;
1703
1704 r = EqPreInit();
1705 if (r.error_flag)
1706 return r;
1707
1708 r = HandleInit(args);
1709 if (r.error_flag)
1710 return r;
1711
1712 r = EqPostInit();
1713 if (r.error_flag)
1714 return r;
1715
1716 return TMFeOk();
1717}
1718
1720{
1721 if (TMFE::gfVerbose)
1722 printf("TMFeEquipment::EqReadCommon: for [%s]\n", fEqName.c_str());
1723
1724 // list of ODB Common entries always read
1725
1726 fOdbEqCommon->RB("Enabled", &fEqConfEnabled, true);
1727 fOdbEqCommon->RD("Event limit", &fEqConfEventLimit, true);
1728
1730 // list of ODB Common entries read if we want to control equipment from ODB
1731
1732 fOdbEqCommon->RU16("Event ID", &fEqConfEventID, true);
1733 fOdbEqCommon->RU16("Trigger mask", &fEqConfTriggerMask, true);
1734 fOdbEqCommon->RS("Buffer", &fEqConfBuffer, true, NAME_LENGTH);
1735 fOdbEqCommon->RI("Type", &fEqConfType, true);
1736 fOdbEqCommon->RI("Source", &fEqConfSource, true);
1737 fOdbEqCommon->RS("Format", &fEqConfFormat, true, 8);
1738 fOdbEqCommon->RI("Read on", &fEqConfReadOn, true);
1739 fOdbEqCommon->RI("Period", &fEqConfPeriodMilliSec, true);
1740 fOdbEqCommon->RU32("Num subevents", &fEqConfNumSubEvents, true);
1741 fOdbEqCommon->RI("Log history", &fEqConfLogHistory, true);
1742 fOdbEqCommon->RB("Hidden", &fEqConfHidden, true);
1743 fOdbEqCommon->RI("Write cache size", &fEqConfWriteCacheSize, true);
1744
1745 // decode data from ODB Common
1746
1749 }
1750
1751 // list of ODB Common entries we read and write back to ODB, but do not actually use.
1752
1753 //fOdbEqCommon->RS("Frontend host", &fEqConfFrontendHost, true, NAME_LENGTH);
1754 //fOdbEqCommon->RS("Frontend name", &fEqConfFrontendName, true, NAME_LENGTH);
1755 //fOdbEqCommon->RS("Frontend file name", &fEqConfFrontendFileName, true, 256);
1756 //fOdbEqCommon->RS("Status", &fEqConfStatus, true, 256);
1757 //fOdbEqCommon->RS("Status color", &fEqConfStatusColor, true, NAME_LENGTH);
1758
1759 return TMFeOk();
1760}
1761
1763{
1764 if (TMFE::gfVerbose)
1765 printf("TMFeEquipment::EqWriteCommon: for [%s]\n", fEqName.c_str());
1766
1767 // encode data for ODB Common
1768
1769 fEqConfReadOn = 0;
1772 else
1776
1777 // write to ODB
1778
1779 fOdbEqCommon->WU16("Event ID", fEqConfEventID);
1780 fOdbEqCommon->WU16("Trigger mask", fEqConfTriggerMask);
1781 fOdbEqCommon->WS("Buffer", fEqConfBuffer.c_str(), NAME_LENGTH);
1782 fOdbEqCommon->WI("Type", fEqConfType);
1783 fOdbEqCommon->WI("Source", fEqConfSource);
1784 fOdbEqCommon->WS("Format", fEqConfFormat.c_str(), 8);
1785 fOdbEqCommon->WB("Enabled", fEqConfEnabled);
1786 fOdbEqCommon->WI("Read on", fEqConfReadOn);
1787 fOdbEqCommon->WI("Period", fEqConfPeriodMilliSec);
1788 fOdbEqCommon->WD("Event limit", fEqConfEventLimit);
1789 fOdbEqCommon->WU32("Num subevents", fEqConfNumSubEvents);
1790 fOdbEqCommon->WI("Log history", fEqConfLogHistory);
1791 fOdbEqCommon->WS("Frontend host", fMfe->fHostname.c_str(), NAME_LENGTH);
1792 fOdbEqCommon->WS("Frontend name", fMfe->fProgramName.c_str(), NAME_LENGTH);
1793 fOdbEqCommon->WS("Frontend file name", fEqFilename.c_str(), 256);
1794 if (create) {
1795 fOdbEqCommon->WS("Status", "", 256);
1796 fOdbEqCommon->WS("Status color", "", NAME_LENGTH);
1797 }
1798 fOdbEqCommon->WB("Hidden", fEqConfHidden);
1799 fOdbEqCommon->WI("Write cache size", fEqConfWriteCacheSize);
1800 return TMFeOk();
1801}
1802
1804{
1805 if (TMFE::gfVerbose)
1806 printf("TMFeEquipment::PreInit: for [%s]\n", fEqName.c_str());
1807
1808 //
1809 // Apply frontend index
1810 //
1811
1812 if (fEqName.find("%") != std::string::npos) {
1813 fEqName = msprintf(fEqName.c_str(), fFe->fFeIndex);
1814 }
1815
1816 if (fEqConfBuffer.find("%") != std::string::npos) {
1818 }
1819
1820 //
1821 // create ODB /eq/name/common
1822 //
1823
1824 fOdbEq = fMfe->fOdbRoot->Chdir((std::string("Equipment/") + fEqName).c_str(), true);
1825 fOdbEqCommon = fOdbEq->Chdir("Common", false);
1826 if (!fOdbEqCommon) {
1827 if (TMFE::gfVerbose)
1828 printf("TMFeEquipment::PreInit: creating ODB common\n");
1829 fOdbEqCommon = fOdbEq->Chdir("Common", true);
1830 EqWriteCommon(true);
1831 }
1832 fOdbEqSettings = fOdbEq->Chdir("Settings", true);
1833 fOdbEqVariables = fOdbEq->Chdir("Variables", true);
1834 fOdbEqStatistics = fOdbEq->Chdir("Statistics", true);
1835
1837
1838 if (r.error_flag)
1839 return r;
1840
1841 if (rpc_is_remote()) {
1842 EqSetStatus((fMfe->fProgramName + "@" + fMfe->fHostname).c_str(), "greenLight");
1843 } else {
1844 EqSetStatus(fMfe->fProgramName.c_str(), "greenLight");
1845 }
1846
1849
1850 return TMFeOk();
1851}
1852
1854{
1855 if (TMFE::gfVerbose)
1856 printf("TMFeEquipment::EqPostInit: for [%s]\n", fEqName.c_str());
1857
1858 if (!fEqConfEnabled) {
1859 EqSetStatus("Disabled", "yellowLight");
1860 }
1861
1862 // open event buffer
1863
1865 fMfe->fOdbRoot->RU32("Experiment/MAX_EVENT_SIZE", &odb_max_event_size, true);
1866
1867 if (fEqConfMaxEventSize == 0) {
1870 fMfe->Msg(MERROR, "TMFeEquipment::EqPostInit", "Equipment \"%s\" requested event size %d is bigger than ODB MAX_EVENT_SIZE %d", fEqName.c_str(), (int)fEqConfMaxEventSize, odb_max_event_size);
1872 }
1873
1874 if (!fEqConfBuffer.empty()) {
1876
1877 if (r.error_flag)
1878 return r;
1879
1880 assert(fEqEventBuffer != NULL);
1881
1883 fMfe->Msg(MERROR, "TMFeEquipment::EqPostInit", "Equipment \"%s\" requested event size %d is bigger than event buffer \"%s\" max event size %d", fEqName.c_str(), (int)fEqConfMaxEventSize, fEqEventBuffer->fBufName.c_str(), (int)fEqEventBuffer->fBufMaxEventSize);
1885 }
1886
1887 if (fEqConfWriteCacheSize > 0) {
1890
1891 if (r.error_flag)
1892 return r;
1894 fMfe->Msg(MERROR, "TMFeEquipment::EqPostInit", "Equipment \"%s\" requested write cache size %d for buffer \"%s\" is smaller then already set write cache size %d, ignoring it", fEqName.c_str(), (int)fEqConfWriteCacheSize, fEqEventBuffer->fBufName.c_str(), (int)fEqEventBuffer->fBufWriteCacheSize);
1896 // do nothing
1897 } else {
1898 fMfe->Msg(MERROR, "TMFeEquipment::EqPostInit", "Equipment \"%s\" requested write cache size %d for buffer \"%s\" is different from already set write cache size %d", fEqName.c_str(), (int)fEqConfWriteCacheSize, fEqEventBuffer->fBufName.c_str(), (int)fEqEventBuffer->fBufWriteCacheSize);
1899
1901
1902 if (r.error_flag)
1903 return r;
1904 }
1905 }
1906 }
1907
1908 if (TMFE::gfVerbose)
1909 printf("TMFeEquipment::EqPostInit: Equipment \"%s\", max event size: %d\n", fEqName.c_str(), (int)fEqConfMaxEventSize);
1910
1911 // update ODB common
1912
1914
1915 if (r.error_flag)
1916 return r;
1917
1919 fMfe->AddRpcHandler(this);
1920 }
1921
1922 return TMFeOk();
1923};
1924
1926{
1927 fEqMutex.lock();
1928
1929 if (TMFE::gfVerbose)
1930 printf("TMFeEquipment::EqZeroStatistics: zero statistics for [%s]\n", fEqName.c_str());
1931
1932 double now = TMFE::GetTime();
1933
1934 fEqStatEvents = 0;
1935 fEqStatBytes = 0;
1936 fEqStatEpS = 0;
1937 fEqStatKBpS = 0;
1938
1941 fEqStatLastBytes = 0;
1942
1943 fEqStatNextWrite = now; // force immediate update
1944
1945 fEqMutex.unlock();
1946
1947 return TMFeOk();
1948}
1949
1951{
1952 fEqMutex.lock();
1953
1954 if (TMFE::gfVerbose)
1955 printf("TMFeEquipment::EqWriteStatistics: write statistics for [%s]\n", fEqName.c_str());
1956
1957 double now = TMFE::GetTime();
1958 double elapsed = now - fEqStatLastTime;
1959
1960 if (elapsed > 0.9 || fEqStatLastTime == 0) {
1963
1967 }
1968
1969 //printf("TMFeEquipment::EqWriteStatistics: write statistics for [%s], now %f, elapsed %f, sent %f, eps %f, kps %f\n", fEqName.c_str(), now, elapsed, fEqStatEvents, fEqStatEpS, fEqStatKBpS);
1970
1971 fOdbEqStatistics->WD("Events sent", fEqStatEvents);
1972 fOdbEqStatistics->WD("Events per sec.", fEqStatEpS);
1973 fOdbEqStatistics->WD("kBytes per sec.", fEqStatKBpS);
1974
1976
1978 // avoid creep of NextWrite: we start it at
1979 // time of initialization, then increment it strictly
1980 // by the period value, regardless of when it is actually
1981 // written to ODB (actual period is longer than requested
1982 // period because we only over-sleep, never under-sleep). K.O.
1983 while (fEqStatNextWrite <= now) {
1985 }
1986 } else {
1988 }
1989
1990 fEqMutex.unlock();
1991
1992 return TMFeOk();
1993}
1994
1995TMFeResult TMFeEquipment::ComposeEvent(char* event, size_t size) const
1996{
1997 EVENT_HEADER* pevent = (EVENT_HEADER*)event;
1998 pevent->event_id = fEqConfEventID;
2000 pevent->serial_number = fEqSerial;
2001 pevent->time_stamp = TMFE::GetTime();
2002 pevent->data_size = 0;
2003 return TMFeOk();
2004}
2005
2007{
2008 std::lock_guard<std::mutex> guard(fEqMutex);
2009
2010 fEqSerial++;
2011
2012 EVENT_HEADER* pevent = (EVENT_HEADER*)event;
2013 pevent->data_size = BkSize(event);
2014
2015 if (fEqEventBuffer != NULL) {
2017
2018 if (r.error_flag)
2019 return r;
2020 }
2021
2022 fEqStatEvents += 1;
2023 fEqStatBytes += sizeof(EVENT_HEADER) + pevent->data_size;
2024
2027 if (r.error_flag)
2028 return r;
2029 }
2030
2031 if (fMfe->fStateRunning) {
2032 if (fEqConfEventLimit > 0) {
2034 if (!fMfe->fRunStopRequested) {
2035 fMfe->Msg(MINFO, "TMFeEquipment::EqSendEvent", "Equipment \"%s\" sent %.0f events out of %.0f requested, run will stop now", fEqName.c_str(), fEqStatEvents, fEqConfEventLimit);
2036 }
2037 fMfe->fRunStopRequested = true;
2038 }
2039 }
2040 }
2041
2042 return TMFeOk();
2043}
2044
2045TMFeResult TMFeEquipment::EqSendEvent(const std::vector<char>& event, bool write_to_odb)
2046{
2047 std::lock_guard<std::mutex> guard(fEqMutex);
2048
2049 fEqSerial++;
2050
2051 if (fEqEventBuffer == NULL) {
2052 return TMFeOk();
2053 }
2054
2056
2057 if (r.error_flag)
2058 return r;
2059
2060 fEqStatEvents += 1;
2061 fEqStatBytes += event.size();
2062
2064 TMFeResult r = EqWriteEventToOdb_locked(event.data());
2065 if (r.error_flag)
2066 return r;
2067 }
2068
2069 if (fMfe->fStateRunning) {
2070 if (fEqConfEventLimit > 0) {
2072 if (!fMfe->fRunStopRequested) {
2073 fMfe->Msg(MINFO, "TMFeEquipment::EqSendEvent", "Equipment \"%s\" sent %.0f events out of %.0f requested, run will stop now", fEqName.c_str(), fEqStatEvents, fEqConfEventLimit);
2074 }
2075 fMfe->fRunStopRequested = true;
2076 }
2077 }
2078 }
2079
2080 return TMFeOk();
2081}
2082
2083TMFeResult TMFeEquipment::EqSendEvent(const std::vector<std::vector<char>>& event, bool write_to_odb)
2084{
2085 std::lock_guard<std::mutex> guard(fEqMutex);
2086
2087 fEqSerial++;
2088
2089 if (fEqEventBuffer == NULL) {
2090 return TMFeOk();
2091 }
2092
2094
2095 if (r.error_flag)
2096 return r;
2097
2098 fEqStatEvents += 1;
2099 for (auto v: event) {
2100 fEqStatBytes += v.size();
2101 }
2102
2103 //if (fEqConfWriteEventsToOdb && write_to_odb) {
2104 // TMFeResult r = EqWriteEventToOdb_locked(event.data());
2105 // if (r.error_flag)
2106 // return r;
2107 //}
2108
2109 if (fMfe->fStateRunning) {
2110 if (fEqConfEventLimit > 0) {
2112 if (!fMfe->fRunStopRequested) {
2113 fMfe->Msg(MINFO, "TMFeEquipment::EqSendEvent", "Equipment \"%s\" sent %.0f events out of %.0f requested, run will stop now", fEqName.c_str(), fEqStatEvents, fEqConfEventLimit);
2114 }
2115 fMfe->fRunStopRequested = true;
2116 }
2117 }
2118 }
2119
2120 return TMFeOk();
2121}
2122
2123TMFeResult TMFeEquipment::EqSendEvent(int sg_n, const char* sg_ptr[], const size_t sg_len[], bool write_to_odb)
2124{
2125 std::lock_guard<std::mutex> guard(fEqMutex);
2126
2127 fEqSerial++;
2128
2129 if (fEqEventBuffer == NULL) {
2130 return TMFeOk();
2131 }
2132
2134
2135 if (r.error_flag)
2136 return r;
2137
2138 fEqStatEvents += 1;
2139 for (int i=0; i<sg_n; i++) {
2140 fEqStatBytes += sg_len[i];
2141 }
2142
2143 //if (fEqConfWriteEventsToOdb && write_to_odb) {
2144 // TMFeResult r = EqWriteEventToOdb_locked(event.data());
2145 // if (r.error_flag)
2146 // return r;
2147 //}
2148
2149 if (fMfe->fStateRunning) {
2150 if (fEqConfEventLimit > 0) {
2152 if (!fMfe->fRunStopRequested) {
2153 fMfe->Msg(MINFO, "TMFeEquipment::EqSendEvent", "Equipment \"%s\" sent %.0f events out of %.0f requested, run will stop now", fEqName.c_str(), fEqStatEvents, fEqConfEventLimit);
2154 }
2155 fMfe->fRunStopRequested = true;
2156 }
2157 }
2158 }
2159
2160 return TMFeOk();
2161}
2162
2164{
2165 std::lock_guard<std::mutex> guard(fEqMutex);
2166 return EqWriteEventToOdb_locked(event);
2167}
2168
2170{
2171 std::string path = "";
2172 path += "/Equipment/";
2173 path += fEqName;
2174 path += "/Variables";
2175
2176 HNDLE hKeyVar = 0;
2177
2178 int status = db_find_key(fMfe->fDB, 0, path.c_str(), &hKeyVar);
2179 if (status != DB_SUCCESS) {
2180 return TMFeMidasError(msprintf("Cannot find \"%s\" in ODB", path.c_str()), "db_find_key", status);
2181 }
2182
2183 status = cm_write_event_to_odb(fMfe->fDB, hKeyVar, (const EVENT_HEADER*) event, FORMAT_MIDAS);
2184 if (status != SUCCESS) {
2185 return TMFeMidasError("Cannot write event to ODB", "cm_write_event_to_odb", status);
2186 }
2187 return TMFeOk();
2188}
2189
2190int TMFeEquipment::BkSize(const char* event) const
2191{
2192 return bk_size(event + sizeof(EVENT_HEADER));
2193}
2194
2195TMFeResult TMFeEquipment::BkInit(char* event, size_t size) const
2196{
2197 bk_init32a(event + sizeof(EVENT_HEADER));
2198 return TMFeOk();
2199}
2200
2201void* TMFeEquipment::BkOpen(char* event, const char* name, int tid) const
2202{
2203 void* ptr;
2204 bk_create(event + sizeof(EVENT_HEADER), name, tid, &ptr);
2205 return ptr;
2206}
2207
2208TMFeResult TMFeEquipment::BkClose(char* event, void* ptr) const
2209{
2210 bk_close(event + sizeof(EVENT_HEADER), ptr);
2211 ((EVENT_HEADER*)event)->data_size = BkSize(event);
2212 return TMFeOk();
2213}
2214
2216{
2217 if (eq_status) {
2218 fOdbEqCommon->WS("Status", eq_status, 256);
2219 }
2220
2221 if (eq_color) {
2222 fOdbEqCommon->WS("Status color", eq_color, NAME_LENGTH);
2223 }
2224
2225 return TMFeOk();
2226}
2227
2228TMFeResult TMFE::TriggerAlarm(const char* name, const char* message, const char* aclass)
2229{
2231
2232 if (status) {
2233 return TMFeMidasError("Cannot trigger alarm", "al_trigger_alarm", status);
2234 }
2235
2236 return TMFeOk();
2237}
2238
2240{
2241 int status = al_reset_alarm(name);
2242
2243 if (status) {
2244 return TMFeMidasError("Cannot reset alarm", "al_reset_alarm", status);
2245 }
2246
2247 return TMFeOk();
2248}
2249
2251{
2252 fprintf(stderr, "\n");
2253 fprintf(stderr, "Usage: %s args... [-- equipment args...]\n", argv0);
2254 fprintf(stderr, "\n");
2255 fprintf(stderr, " --help -- print this help message\n");
2256 fprintf(stderr, " -h -- print this help message\n");
2257 fprintf(stderr, " -v -- report all activities\n");
2258 fprintf(stderr, "\n");
2259 fprintf(stderr, " -h hostname[:tcpport] -- connect to MIDAS mserver on given host and tcp port number\n");
2260 fprintf(stderr, " -e exptname -- connect to given MIDAS experiment\n");
2261 fprintf(stderr, "\n");
2262 fprintf(stderr, " -D -- Become a daemon\n");
2263 fprintf(stderr, " -O -- Become a daemon but keep stdout for saving in a log file: frontend -O >file.log 2>&1\n");
2264 fprintf(stderr, "\n");
2265 fprintf(stderr, " -i NNN -- Set frontend index number\n");
2266 fprintf(stderr, "\n");
2267
2268 // NOTE: cannot use range-based for() loop, it uses an iterator and will crash if HandleUsage() modifies fEquipments. K.O.
2269 for (unsigned i=0; i<fFeEquipments.size(); i++) {
2270 if (!fFeEquipments[i])
2271 continue;
2272 fprintf(stderr, "Usage of equipment \"%s\":\n", fFeEquipments[i]->fEqName.c_str());
2273 fprintf(stderr, "\n");
2274 fFeEquipments[i]->HandleUsage();
2275 fprintf(stderr, "\n");
2276 }
2277}
2278
2280{
2281 std::vector<std::string> args;
2282 for (int i=0; i<argc; i++) {
2283 args.push_back(argv[i]);
2284 }
2285
2286 return FeMain(args);
2287}
2288
2289TMFeResult TMFrontend::FeInit(const std::vector<std::string> &args)
2290{
2291 setbuf(stdout, NULL);
2292 setbuf(stderr, NULL);
2293
2295
2296 std::vector<std::string> eq_args;
2297
2298 bool help = false;
2299 std::string exptname;
2300 std::string hostname;
2301 bool daemon0 = false;
2302 bool daemon1 = false;
2303
2304 for (unsigned int i=1; i<args.size(); i++) { // loop over the commandline options
2305 //printf("argv[%d] is %s\n", i, args[i].c_str());
2306 if (args[i] == "--") {
2307 // remaining arguments are passed to equipment Init()
2308 for (unsigned j=i+1; j<args.size(); j++)
2309 eq_args.push_back(args[j]);
2310 break;
2311 } else if (args[i] == "-v") {
2312 TMFE::gfVerbose = true;
2313 } else if (args[i] == "-D") {
2314 daemon0 = true;
2315 } else if (args[i] == "-O") {
2316 daemon1 = true;
2317 } else if (args[i] == "-h") {
2318 i++;
2319 if (i >= args.size()) { help = true; break; }
2320 hostname = args[i];
2321 } else if (args[i] == "-e") {
2322 i++;
2323 if (i >= args.size()) { help = true; break; }
2324 exptname = args[i];
2325 } else if (args[i] == "-i") {
2326 i++;
2327 if (i >= args.size()) { help = true; break; }
2328 fFeIndex = atoi(args[i].c_str());
2329 } else if (args[i] == "--help") {
2330 help = true;
2331 break;
2332 } else if (args[i][0] == '-') {
2333 help = true;
2334 break;
2335 } else {
2336 help = true;
2337 break;
2338 }
2339 }
2340
2341 //
2342 // daemonize...
2343 //
2344
2345 if (daemon0) {
2346 printf("Becoming a daemon...\n");
2348 } else if (daemon1) {
2349 printf("Becoming a daemon...\n");
2351 }
2352
2353 //
2354 // apply frontend index to indexed frontend
2355 //
2356
2357 if (fMfe->fProgramName.find("%") != std::string::npos) {
2359 }
2360
2361 TMFeResult r;
2362
2363 // call arguments handler before calling the usage handlers. Otherwise,
2364 // if the arguments handler creates new equipments,
2365 // we will never see their Usage(). K.O.
2367
2368 if (r.error_flag) {
2369 fprintf(stderr, "Fatal error: arguments handler error: %s, bye.\n", r.error_message.c_str());
2370 fMfe->Disconnect();
2371 exit(1);
2372 }
2373
2374 if (help) {
2375 FeUsage(args[0].c_str());
2376 HandleUsage();
2377 fMfe->Disconnect();
2378 exit(1);
2379 }
2380
2381 r = fMfe->Connect(NULL, hostname.c_str(), exptname.c_str());
2382
2383 if (r.error_flag) {
2384 fprintf(stderr, "Fatal error: cannot connect to MIDAS, error: %s, bye.\n", r.error_message.c_str());
2385 fMfe->Disconnect();
2386 exit(1);
2387 }
2388
2390
2391 if (r.error_flag) {
2392 fprintf(stderr, "Fatal error: frontend init error: %s, bye.\n", r.error_message.c_str());
2393 fMfe->Disconnect();
2394 exit(1);
2395 }
2396
2399
2400 //mfe->SetWatchdogSec(0);
2401 //mfe->SetTransitionSequenceStart(910);
2402 //mfe->SetTransitionSequenceStop(90);
2403 //mfe->DeregisterTransitionPause();
2404 //mfe->DeregisterTransitionResume();
2405 //mfe->RegisterTransitionStartAbort();
2406
2408
2409 if (r.error_flag) {
2410 fprintf(stderr, "Cannot initialize equipments, error message: %s, bye.\n", r.error_message.c_str());
2411 fMfe->Disconnect();
2412 exit(1);
2413 }
2414
2416
2417 if (r.error_flag) {
2418 fprintf(stderr, "Fatal error: frontend post-init error: %s, bye.\n", r.error_message.c_str());
2419 fMfe->Disconnect();
2420 exit(1);
2421 }
2422
2423 if (fMfe->fStateRunning) {
2425 fprintf(stderr, "Fatal error: Cannot start frontend, run is in progress!\n");
2426 fMfe->Disconnect();
2427 exit(1);
2428 } else if (fFeIfRunningCallBeginRun) {
2429 char errstr[TRANSITION_ERROR_STRING_LENGTH];
2430 tr_start(fMfe->fRunNumber, errstr);
2431 }
2432 }
2433
2434 return TMFeOk();
2435}
2436
2438{
2439 while (!fMfe->fShutdownRequested) {
2440 FePollMidas(0.100);
2441 }
2442}
2443
2453
2454int TMFrontend::FeMain(const std::vector<std::string> &args)
2455{
2456 TMFeResult r = FeInit(args);
2457
2458 if (r.error_flag) {
2459 fprintf(stderr, "Fatal error: frontend init error: %s, bye.\n", r.error_message.c_str());
2460 fMfe->Disconnect();
2461 exit(1);
2462 }
2463
2464 FeMainLoop();
2465 FeShutdown();
2466
2467 return 0;
2468}
2469
2470// singleton instance
2472
2473// static data members
2474bool TMFE::gfVerbose = false;
2475
2476/* emacs
2477 * Local Variables:
2478 * tab-width: 8
2479 * c-basic-offset: 3
2480 * indent-tabs-mode: nil
2481 * End:
2482 */
#define FALSE
Definition cfortran.h:309
std::vector< int > fBufRequests
Definition tmfe.h:141
std::string fBufName
Definition tmfe.h:119
TMFeResult CloseBuffer()
Definition tmfe.cxx:235
int fBufHandle
Definition tmfe.h:138
size_t fBufReadCacheSize
Definition tmfe.h:139
TMFeResult SetCacheSize(size_t read_cache_size, size_t write_cache_size)
Definition tmfe.cxx:258
TMFeResult OpenBuffer(const char *bufname, size_t bufsize=0)
Definition tmfe.cxx:183
TMFeResult AddRequest(int event_id, int trigger_mask, const char *sampling_type_string)
Definition tmfe.cxx:272
TMFeResult ReceiveEvent(std::vector< char > *e, int timeout_msec=0)
Definition tmfe.cxx:303
TMFE * fMfe
Definition tmfe.h:118
TMFeResult FlushCache(bool wait=true)
Definition tmfe.cxx:374
size_t fBufWriteCacheSize
Definition tmfe.h:140
TMEventBuffer(TMFE *mfe)
Definition tmfe.cxx:169
size_t fBufSize
Definition tmfe.h:120
TMFeResult SendEvent(const char *e)
Definition tmfe.cxx:326
size_t fBufMaxEventSize
Definition tmfe.h:121
Definition tmfe.h:381
TMFeResult TriggerAlarm(const char *name, const char *message, const char *aclass)
Definition tmfe.cxx:2228
TMFeResult EventBufferCloseAll()
Definition tmfe.cxx:484
bool fRunStopRequested
run stop was requested by equipment
Definition tmfe.h:444
std::thread * fRpcThread
Definition tmfe.h:405
void DeregisterTransitionStartAbort()
Definition tmfe.cxx:1502
std::vector< TMEventBuffer * > fEventBuffers
Definition tmfe.h:436
std::atomic_bool fRpcThreadStarting
Definition tmfe.h:406
static std::string GetThreadId()
return identification of this thread
Definition tmfe.cxx:1140
bool fStateRunning
run state is running or paused
Definition tmfe.h:402
void RegisterRPCs()
Definition tmfe.cxx:1512
void DeregisterTransitionResume()
Definition tmfe.cxx:1497
std::mutex fEventBuffersMutex
Definition tmfe.h:435
TMFE()
default constructor is private for singleton classes
Definition tmfe.cxx:44
static double GetTime()
return current time in seconds, with micro-second precision
Definition tmfe.cxx:1011
void MidasPeriodicTasks()
Definition tmfe.cxx:852
void AddRpcHandler(TMFeRpcHandlerInterface *)
Definition tmfe.cxx:1526
int fDB
ODB database handle.
Definition tmfe.h:394
virtual ~TMFE()
destructor is private for singleton classes
Definition tmfe.cxx:50
void DeregisterTransitionPause()
Definition tmfe.cxx:1492
void SetTransitionSequenceResume(int seqno)
Definition tmfe.cxx:1463
void RpcThread()
Definition tmfe.cxx:857
double fRunStartTime
start a new run at this time
Definition tmfe.h:445
static bool gfVerbose
Definition tmfe.h:424
std::string fMserverHostname
hostname where the mserver is running, blank if using shared memory
Definition tmfe.h:385
void SetTransitionSequenceStop(int seqno)
Definition tmfe.cxx:1453
void Yield(double sleep_sec)
Definition tmfe.cxx:821
void Msg(int message_type, const char *filename, int line, const char *routine, const char *format,...) MATTRPRINTF(6
Definition tmfe.cxx:991
void StartRpcThread()
Definition tmfe.cxx:903
void DeregisterTransitionStop()
Definition tmfe.cxx:1487
TMFeResult Connect(const char *progname=NULL, const char *hostname=NULL, const char *exptname=NULL)
Definition tmfe.cxx:65
std::atomic_bool fRpcThreadShutdownRequested
Definition tmfe.h:408
void StopRun()
Definition tmfe.cxx:687
void SetTransitionSequenceStartAbort(int seqno)
Definition tmfe.cxx:1468
static TMFE * Instance()
Definition tmfe.cxx:57
static void Sleep(double sleep_time_sec)
sleep, with micro-second precision
Definition tmfe.cxx:1019
static TMFE * gfMFE
Definition tmfe.h:413
void SetTransitionSequencePause(int seqno)
Definition tmfe.cxx:1458
void StartRun()
Definition tmfe.cxx:714
std::atomic_bool fShutdownRequested
shutdown was requested by Ctrl-C or by RPC command
Definition tmfe.h:398
std::atomic_bool fRpcThreadRunning
Definition tmfe.h:407
TMFeResult SetWatchdogSec(int sec)
Definition tmfe.cxx:144
void StopRpcThread()
Definition tmfe.cxx:935
void RegisterTransitionStartAbort()
Definition tmfe.cxx:1507
TMFeResult ResetAlarm(const char *name)
Definition tmfe.cxx:2239
TMFeResult EventBufferFlushCacheAll(bool wait=true)
Definition tmfe.cxx:448
std::string fHostname
hostname we are running on
Definition tmfe.h:388
MVOdb * fOdbRoot
ODB root.
Definition tmfe.h:395
TMFeResult Disconnect()
Definition tmfe.cxx:154
std::vector< TMFeRpcHandlerInterface * > fRpcHandlers
Definition tmfe.h:464
std::string fProgramName
frontend program name
Definition tmfe.h:387
std::mutex fMutex
Definition tmfe.h:391
void DeregisterTransitionStart()
Definition tmfe.cxx:1482
void RemoveRpcHandler(TMFeRpcHandlerInterface *)
Definition tmfe.cxx:1531
void DeregisterTransitions()
Definition tmfe.cxx:1473
int fRunNumber
current run number
Definition tmfe.h:401
void SetTransitionSequenceStart(int seqno)
Definition tmfe.cxx:1448
TMFeResult EventBufferOpen(TMEventBuffer **pbuf, const char *bufname, size_t bufsize=0)
Definition tmfe.cxx:413
std::string fExptname
experiment name, blank if only one experiment defined in exptab
Definition tmfe.h:384
bool fEqConfHidden
Definition tmfe.h:182
int fEqConfSource
Definition tmfe.h:175
std::mutex fEqMutex
Definition tmfe.h:204
double fEqStatKBpS
Definition tmfe.h:225
void * BkOpen(char *pevent, const char *bank_name, int bank_type) const
Definition tmfe.cxx:2201
TMFeResult EqWriteEventToOdb_locked(const char *pevent)
Definition tmfe.cxx:2169
TMFeResult BkInit(char *pevent, size_t size) const
Definition tmfe.cxx:2195
uint16_t fEqConfTriggerMask
Definition tmfe.h:172
virtual void HandlePollRead()
Definition tmfe.h:274
MVOdb * fOdbEqSettings
ODB Equipment/EQNAME/Settings.
Definition tmfe.h:213
std::atomic_bool fEqPollThreadShutdownRequested
Definition tmfe.h:243
bool fEqConfEnabled
Definition tmfe.h:170
TMFE * fMfe
Definition tmfe.h:207
int fEqConfReadOn
Definition tmfe.h:177
int fEqConfWriteCacheSize
Definition tmfe.h:186
virtual ~TMFeEquipment()
Definition tmfe.cxx:1667
TMFeResult EqSetStatus(const char *status, const char *color)
Definition tmfe.cxx:2215
double fEqStatLastTime
Definition tmfe.h:228
void EqPollThread()
Definition tmfe.cxx:621
TMFrontend * fFe
Definition tmfe.h:208
bool fEqConfWriteEventsToOdb
Definition tmfe.h:197
virtual bool HandlePoll()
Definition tmfe.h:273
TMFeResult EqWriteCommon(bool create=false)
Write TMFeEqInfo to ODB /Equipment/NAME/Common.
Definition tmfe.cxx:1762
uint16_t fEqConfEventID
Definition tmfe.h:171
TMFeResult EqReadCommon()
Read TMFeEqInfo from ODB /Equipment/NAME/Common.
Definition tmfe.cxx:1719
double fEqConfPollSleepSec
Definition tmfe.h:199
TMFeResult EqWriteStatistics()
Definition tmfe.cxx:1950
MVOdb * fOdbEqVariables
ODB Equipment/EQNAME/Variables.
Definition tmfe.h:214
int fEqConfPeriodMilliSec
Definition tmfe.h:178
double fEqStatLastWrite
Definition tmfe.h:233
TMFeResult EqInit(const std::vector< std::string > &args)
Initialize equipment.
Definition tmfe.cxx:1700
double fEqConfPeriodStatisticsSec
Definition tmfe.h:198
double fEqStatEpS
Definition tmfe.h:224
TMEventBuffer * fEqEventBuffer
Definition tmfe.h:218
void EqStartPollThread()
Definition tmfe.cxx:648
virtual TMFeResult HandleInit(const std::vector< std::string > &args)
Definition tmfe.h:258
bool fEqConfEnableRpc
Definition tmfe.h:164
TMFeResult EqZeroStatistics()
Definition tmfe.cxx:1925
double fEqStatEvents
Definition tmfe.h:222
std::thread * fEqPollThread
Definition tmfe.h:277
void EqStopPollThread()
Definition tmfe.cxx:665
double fEqStatBytes
Definition tmfe.h:223
std::atomic_bool fEqPollThreadRunning
Definition tmfe.h:242
TMFeResult EqPreInit()
Initialize equipment, before EquipmentBase::Init()
Definition tmfe.cxx:1803
uint32_t fEqConfNumSubEvents
Definition tmfe.h:180
TMFeResult BkClose(char *pevent, void *ptr) const
Definition tmfe.cxx:2208
TMFeEquipment()
Definition tmfe.h:255
std::string fEqConfFormat
Definition tmfe.h:176
int fEqConfLogHistory
Definition tmfe.h:181
double fEqStatNextWrite
Definition tmfe.h:234
double fEqConfEventLimit
Definition tmfe.h:179
TMFeResult ComposeEvent(char *pevent, size_t size) const
Definition tmfe.cxx:1995
std::string fEqName
Definition tmfe.h:159
size_t fEqConfBufferSize
Definition tmfe.h:201
int fEqSerial
Definition tmfe.h:219
double fEqStatLastEvents
Definition tmfe.h:229
int fEqConfType
Definition tmfe.h:174
MVOdb * fOdbEqCommon
ODB Equipment/EQNAME/Common.
Definition tmfe.h:212
MVOdb * fOdbEq
ODB Equipment/EQNAME.
Definition tmfe.h:211
std::atomic_bool fEqPollThreadStarting
Definition tmfe.h:241
TMFeResult EqSendEvent(const char *pevent, bool write_to_odb=true)
Definition tmfe.cxx:2006
std::string fEqFilename
Definition tmfe.h:160
bool fEqConfReadConfigFromOdb
Definition tmfe.h:168
TMFeResult EqWriteEventToOdb(const char *pevent)
Definition tmfe.cxx:2163
int BkSize(const char *pevent) const
Definition tmfe.cxx:2190
std::string fEqConfBuffer
Definition tmfe.h:173
double fEqStatLastBytes
Definition tmfe.h:230
size_t fEqConfMaxEventSize
Definition tmfe.h:200
MVOdb * fOdbEqStatistics
ODB Equipment/EQNAME/Statistics.
Definition tmfe.h:215
TMFeResult EqPostInit()
Initialize equipment, after EquipmentBase::Init()
Definition tmfe.cxx:1853
bool fEqConfReadOnlyWhenRunning
Definition tmfe.h:196
bool error_flag
Definition tmfe.h:89
std::string error_message
Definition tmfe.h:91
virtual TMFeResult HandleEndRun(int run_number)
Definition tmfe.h:148
virtual TMFeResult HandleResumeRun(int run_number)
Definition tmfe.h:150
virtual TMFeResult HandlePauseRun(int run_number)
Definition tmfe.h:149
virtual TMFeResult HandleRpc(const char *cmd, const char *args, std::string &result)
Definition tmfe.h:152
virtual TMFeResult HandleBeginRun(int run_number)
Definition tmfe.h:147
virtual TMFeResult HandleStartAbortRun(int run_number)
Definition tmfe.h:151
virtual TMFeResult HandleBinaryRpc(const char *cmd, const char *args, std::vector< char > &result)
Definition tmfe.h:153
void FeShutdown()
Definition tmfe.cxx:2444
double fFeFlushWriteCacheNextCallTime
Definition tmfe.h:376
bool fFeIfRunningCallBeginRun
Definition tmfe.h:316
std::thread * fFePeriodicThread
Definition tmfe.h:369
std::atomic_bool fFePeriodicThreadRunning
Definition tmfe.h:371
double fFeFlushWriteCachePeriodSec
Definition tmfe.h:375
void FeDeleteEquipments()
Definition tmfe.cxx:1581
void FePollMidas(double sleep_sec)
Definition tmfe.cxx:745
double FePeriodicTasks()
Definition tmfe.cxx:507
TMFE * fMfe
Definition tmfe.h:309
void FePeriodicThread()
Definition tmfe.cxx:883
virtual ~TMFrontend()
Definition tmfe.cxx:1545
int fFeIndex
Definition tmfe.h:313
TMFeResult FeInitEquipments(const std::vector< std::string > &args)
Definition tmfe.cxx:1556
std::mutex fFeMutex
Definition tmfe.h:319
void FeMainLoop()
Definition tmfe.cxx:2437
virtual void HandleFrontendExit()
Definition tmfe.h:335
void FeSetName(const char *program_name)
Definition tmfe.cxx:1647
void FeStopEquipmentPollThreads()
Definition tmfe.cxx:1571
std::vector< TMFeEquipment * > fFeEquipments
Definition tmfe.h:343
void FeUsage(const char *argv0)
Definition tmfe.cxx:2250
TMFeResult FeInit(const std::vector< std::string > &args)
Definition tmfe.cxx:2289
TMFeResult FeAddEquipment(TMFeEquipment *eq)
Definition tmfe.cxx:1600
virtual TMFeResult HandleArguments(const std::vector< std::string > &args)
Definition tmfe.h:331
std::atomic_bool fFePeriodicThreadShutdownRequested
Definition tmfe.h:372
void FeStartPeriodicThread()
Definition tmfe.cxx:919
virtual TMFeResult HandleFrontendInit(const std::vector< std::string > &args)
Definition tmfe.h:333
bool fFeIfRunningCallExit
Definition tmfe.h:315
virtual TMFeResult HandleFrontendReady(const std::vector< std::string > &args)
Definition tmfe.h:334
double FePollTasks(double next_periodic_time)
Definition tmfe.cxx:583
TMFeResult FeRemoveEquipment(TMFeEquipment *eq)
Definition tmfe.cxx:1630
void FeStopPeriodicThread()
Definition tmfe.cxx:963
int FeMain(int argc, char *argv[])
Definition tmfe.cxx:2279
TMFrontendRpcHelper * fFeRpcHelper
Definition tmfe.h:310
std::atomic_bool fFePeriodicThreadStarting
Definition tmfe.h:370
virtual void HandleUsage()
Definition tmfe.h:332
TMFeResult HandleBeginRun(int run_number)
Definition tmfe.cxx:1235
TMFrontendRpcHelper(TMFrontend *fe)
Definition tmfe.cxx:1218
TMFrontend * fFe
Definition tmfe.cxx:1215
virtual ~TMFrontendRpcHelper()
Definition tmfe.cxx:1226
TMFeResult HandleEndRun(int run_number)
Definition tmfe.cxx:1252
INT al_reset_alarm(const char *alarm_name)
Definition alarm.cxx:525
INT al_trigger_alarm(const char *alarm_name, const char *alarm_message, const char *default_class, const char *cond_str, INT type)
Definition alarm.cxx:283
void bk_init32a(void *event)
Definition midas.cxx:16482
INT bk_close(void *event, void *pdata)
Definition midas.cxx:16780
void bk_create(void *event, const char *name, WORD type, void **pdata)
Definition midas.cxx:16561
INT bk_size(const void *event)
Definition midas.cxx:16495
INT bm_open_buffer(const char *buffer_name, INT buffer_size, INT *buffer_handle)
Definition midas.cxx:6717
INT bm_receive_event_vec(INT buffer_handle, std::vector< char > *pvec, int timeout_msec)
Definition midas.cxx:10809
INT bm_request_event(HNDLE buffer_handle, short int event_id, short int trigger_mask, INT sampling_type, HNDLE *request_id, EVENT_HANDLER *func)
Definition midas.cxx:8465
INT bm_set_cache_size(INT buffer_handle, size_t read_size, size_t write_size)
Definition midas.cxx:8140
INT bm_close_buffer(INT buffer_handle)
Definition midas.cxx:7096
int bm_send_event_sg(int buffer_handle, int sg_n, const char *const sg_ptr[], const size_t sg_len[], int timeout_msec)
Definition midas.cxx:9778
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_yield(INT millisec)
Definition midas.cxx:5642
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3011
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_periodic_tasks()
Definition midas.cxx:5579
INT cm_disconnect_experiment(void)
Definition midas.cxx:2846
INT cm_get_environment(char *host_name, int host_name_size, char *exp_name, int exp_name_size)
Definition midas.cxx:2134
INT cm_deregister_transition(INT transition)
Definition midas.cxx:3669
INT cm_set_transition_sequence(INT transition, INT sequence_number)
Definition midas.cxx:3723
INT cm_set_watchdog_params(BOOL call_watchdog, DWORD timeout)
Definition midas.cxx:3283
#define CM_SUCCESS
Definition midas.h:582
#define CM_UNDEF_EXP
Definition midas.h:586
#define BM_ASYNC_RETURN
Definition midas.h:613
#define BM_SUCCESS
Definition midas.h:605
#define BM_CORRUPTED
Definition midas.h:623
#define BM_CREATED
Definition midas.h:606
#define DB_SUCCESS
Definition midas.h:631
#define SS_ABORT
Definition midas.h:677
#define RPC_SHUTDOWN
Definition midas.h:707
#define RPC_SUCCESS
Definition midas.h:698
#define FE_ERR_DRIVER
Definition midas.h:721
#define SUCCESS
Definition mcstd.h:54
#define RO_STOPPED
Definition midas.h:427
#define TR_RESUME
Definition midas.h:408
#define GET_NONBLOCKING
Definition midas.h:322
#define TR_PAUSE
Definition midas.h:407
#define GET_ALL
Definition midas.h:321
#define TR_START
Definition midas.h:405
#define RO_ODB
Definition midas.h:438
#define TR_SYNC
Definition midas.h:358
#define GET_RECENT
Definition midas.h:323
#define BM_NO_WAIT
Definition midas.h:366
#define TR_STARTABORT
Definition midas.h:409
#define STATE_STOPPED
Definition midas.h:305
#define MINFO
Definition midas.h:560
#define RO_PAUSED
Definition midas.h:428
#define STATE_PAUSED
Definition midas.h:306
#define MERROR
Definition midas.h:559
#define STATE_RUNNING
Definition midas.h:307
#define FORMAT_MIDAS
Definition midas.h:311
#define TR_STOP
Definition midas.h:406
#define BM_WAIT
Definition midas.h:365
#define RO_RUNNING
Definition midas.h:426
std::string ss_gethostname()
Definition system.cxx:5706
INT ss_suspend_set_rpc_thread(midas_thread_t thread_id)
Definition system.cxx:4002
std::string ss_tid_to_string(midas_thread_t thread_id)
Definition system.cxx:1571
INT ss_daemon_init(BOOL keep_stdout)
Definition system.cxx:2001
INT ss_suspend_exit()
Definition system.cxx:4226
midas_thread_t ss_gettid(void)
Definition system.cxx:1519
INT cm_msg_flush_buffer()
Definition midas.cxx:865
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
Definition midas.cxx:915
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4079
#define RPC_BRPC
Definition mrpc.h:131
#define RPC_JRPC
Definition mrpc.h:130
bool rpc_is_remote(void)
Definition midas.cxx:12761
INT run_number[2]
Definition mana.cxx:246
DWORD n[4]
Definition mana.cxx:247
INT index
Definition mana.cxx:271
INT tr_stop(INT rn, char *error)
Definition mana.cxx:2036
INT tr_start(INT rn, char *error)
Definition mana.cxx:2014
INT tr_pause(INT rn, char *error)
Definition mana.cxx:2065
BOOL debug
debug printouts
Definition mana.cxx:254
INT tr_resume(INT rn, char *error)
Definition mana.cxx:2078
BOOL create
Definition mchart.cxx:39
INT i
Definition mdump.cxx:32
std::vector< FMT_ID > eq
Definition mdump.cxx:55
INT run_state
Definition mfe.cxx:35
INT max_event_size
Definition mfed.cxx:30
void help()
Definition mh2sql.cxx:244
std::string msprintf(const char *format,...)
Definition midas.cxx:410
int cm_write_event_to_odb(HNDLE hDB, HNDLE hKey, const EVENT_HEADER *pevent, INT format)
Definition midas.cxx:17723
#define AT_INTERNAL
Definition midas.h:1442
INT HNDLE
Definition midas.h:132
#define CINT(_i)
Definition midas.h:1622
#define DEFAULT_WATCHDOG_TIMEOUT
Definition midas.h:290
int INT
Definition midas.h:129
#define CSTRING(_i)
Definition midas.h:1646
#define DEFAULT_MAX_EVENT_SIZE
Definition midas.h:254
#define DEFAULT_BUFFER_SIZE
Definition midas.h:255
#define TRUE
Definition midas.h:182
#define DEFAULT_ODB_SIZE
Definition midas.h:270
#define TRANSITION_ERROR_STRING_LENGTH
Definition midas.h:280
#define NAME_LENGTH
Definition midas.h:272
#define trigger_mask
#define message(type, str)
#define sleep(ms)
#define event_id
#define name(x)
Definition midas_macro.h:24
int gettimeofday(struct timeval *tp, void *tzp)
timeval tv
Definition msysmon.cxx:1095
int event_size
Definition msysmon.cxx:527
INT j
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
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
static double e(void)
Definition tinyexpr.c:136
static INT tr_resume(INT run_number, char *errstr)
Definition tmfe.cxx:1383
static INT tr_startabort(INT run_number, char *errstr)
Definition tmfe.cxx:1416
static INT binary_rpc_callback(INT index, void *prpc_param[])
Definition tmfe.cxx:1175
TMFeResult TMFeErrorMessage(const std::string &message)
Definition tmfe.cxx:29
static INT tr_start(INT run_number, char *errstr)
Definition tmfe.cxx:1275
static INT rpc_callback(INT index, void *prpc_param[])
Definition tmfe.cxx:1145
static INT tr_stop(INT run_number, char *errstr)
Definition tmfe.cxx:1314
static INT tr_pause(INT run_number, char *errstr)
Definition tmfe.cxx:1353
TMFeResult TMFeMidasError(const std::string &message, const char *midas_function_name, int midas_status)
Definition tmfe.cxx:34
TMFeResult TMFeErrorMessage(const std::string &message)
Definition tmfe.cxx:29
TMFeResult TMFeOk()
Definition tmfe.h:106
#define MERROR
Definition tmfe.h:72
TMFeResult TMFeMidasError(const std::string &message, const char *midas_function_name, int midas_status)
Definition tmfe.cxx:34
#define MINFO
Definition tmfe_rev0.h:71
#define MERROR
Definition tmfe_rev0.h:70
#define MTALK
Definition tmfe_rev0.h:75