Line data Source code
1 : /*******************************************************************\
2 :
3 : Name: fetest.cxx
4 : Created by: K.Olchanski
5 :
6 : Contents: Front end for testing MIDAS
7 :
8 : \********************************************************************/
9 :
10 : #undef NDEBUG // midas required assert() to be always enabled
11 :
12 : #include <stdio.h>
13 : #include <signal.h> // SIGPIPE
14 : #include <assert.h> // assert()
15 : #include <stdlib.h> // malloc()
16 : #include <math.h> // M_PI
17 :
18 : #include "midas.h"
19 : #include "tmfe.h"
20 :
21 : #include <string> // std::string
22 : #include <thread> // std::thread
23 : #include <atomic> // atd::atomic
24 :
25 : class EqRandom :
26 : public TMFeEquipment
27 : {
28 : public:
29 0 : EqRandom(const char* eqname, const char* eqfilename) // ctor
30 0 : : TMFeEquipment(eqname, eqfilename)
31 : {
32 0 : fEqConfEventID = 2;
33 0 : fEqConfPeriodMilliSec = 1000;
34 0 : fEqConfLogHistory = 0;
35 0 : fEqConfWriteEventsToOdb = false;
36 0 : fEqConfReadOnlyWhenRunning = true;
37 0 : }
38 :
39 0 : TMFeResult HandleInit(const std::vector<std::string>& args)
40 : {
41 0 : fEqConfReadOnlyWhenRunning = true;
42 0 : fEqConfWriteEventsToOdb = false;
43 0 : fEqConfLogHistory = 0;
44 0 : return TMFeOk();
45 : }
46 :
47 0 : void HandlePeriodic()
48 : {
49 0 : char event[fEqConfMaxEventSize];
50 :
51 0 : ComposeEvent(event, fEqConfMaxEventSize);
52 :
53 0 : char* pbh = event + sizeof(EVENT_HEADER);
54 :
55 0 : double r = drand48();
56 0 : if (r < 0.3)
57 0 : bk_init(pbh);
58 0 : else if (r < 0.6)
59 0 : bk_init32(pbh);
60 : else
61 0 : bk_init32a(pbh);
62 :
63 0 : int nbank = 0+9*drand48(); // nbank range: 0..9, see how bank names are generated: RND0..RND9
64 :
65 0 : for (int i=0; i<nbank; i++) {
66 0 : int tid = 1+(TID_LAST-1)*drand48();
67 0 : int size = 0+100*drand48();
68 :
69 : //int total = bk_size(pbh);
70 : //printf("total %d, add %d, max %d\n", total, size, (int)fMaxEventSize);
71 :
72 : char name[5];
73 0 : name[0] = 'R';
74 0 : name[1] = 'N';
75 0 : name[2] = 'D';
76 0 : name[3] = '0' + (nbank-i-1);
77 0 : name[4] = 0;
78 :
79 : char* ptr;
80 0 : bk_create(pbh, name, tid, (void**)&ptr);
81 :
82 0 : for (int j=0; j<size; j++)
83 0 : ptr[j] = (nbank-i-1);
84 :
85 0 : bk_close(pbh, ptr + size);
86 : }
87 :
88 : //printf("sending %d, max %d\n", (int)bk_size(pbh), (int)fMaxEventSize);
89 :
90 0 : EqSendEvent(event);
91 0 : }
92 :
93 : #if 0
94 : { "random" , /* equipment name */
95 : {
96 : EVID_RANDOM, (1<<EVID_RANDOM), /* event ID, trigger mask */
97 : "SYSTEM", /* event buffer */
98 : EQ_PERIODIC, /* equipment type */
99 : 0, /* event source */
100 : "MIDAS", /* format */
101 : TRUE, /* enabled */
102 : RO_RUNNING, /* Read when running */
103 : 100, /* poll every so milliseconds */
104 : 0, /* stop run after this event limit */
105 : 0, /* number of sub events */
106 : 0, /* history period */
107 : "", "", ""
108 : },
109 : read_random_event,/* readout routine */
110 : },
111 : #endif
112 :
113 : };
114 :
115 : class EqSlow :
116 : public TMFeEquipment
117 : {
118 : public:
119 0 : EqSlow(const char* eqname, const char* eqfilename) // ctor
120 0 : : TMFeEquipment(eqname, eqfilename)
121 : {
122 0 : fEqConfEventID = 3;
123 0 : fEqConfPeriodMilliSec = 1000;
124 0 : fEqConfLogHistory = 1;
125 0 : fEqConfWriteEventsToOdb = true;
126 0 : }
127 :
128 0 : TMFeResult HandleInit(const std::vector<std::string>& args)
129 : {
130 0 : fEqConfReadOnlyWhenRunning = false;
131 0 : fEqConfWriteEventsToOdb = true;
132 : //fEqConfLogHistory = 1;
133 0 : return TMFeOk();
134 : }
135 :
136 0 : void SendData(double dvalue)
137 : {
138 : char buf[1024];
139 0 : ComposeEvent(buf, sizeof(buf));
140 0 : BkInit(buf, sizeof(buf));
141 :
142 0 : double* ptr = (double*)BkOpen(buf, "data", TID_DOUBLE);
143 0 : *ptr++ = dvalue;
144 0 : BkClose(buf, ptr);
145 :
146 0 : EqSendEvent(buf);
147 0 : }
148 :
149 : //#define TEST_PERIOD 1
150 :
151 : #ifdef TEST_PERIOD
152 : double first = 0;
153 : double prev = 0;
154 : int count = 0;
155 : #endif
156 :
157 0 : void HandlePeriodic()
158 : {
159 : #ifdef TEST_PERIOD
160 : double now = TMFE::GetTime();
161 : if (first == 0)
162 : first = now;
163 : double elapsed = now - prev;
164 : double expected = first + count*fEqConfPeriodMilliSec/1000.0;
165 : printf("count %d, periodic %f, expected %f, diff %f, elapsed %f\n", count, now, expected, now-expected, elapsed);
166 : prev = now;
167 : count++;
168 :
169 : //TMFE::Sleep(2);
170 : #endif
171 :
172 : //printf("EqSlow::HandlePeriodic!\n");
173 0 : double t = TMFE::GetTime();
174 0 : double data = 100.0*sin(-M_PI/2.0+M_PI*t/60);
175 0 : SendData(data);
176 : char status_buf[256];
177 0 : sprintf(status_buf, "value %.1f", data);
178 0 : EqSetStatus(status_buf, "#00FF00");
179 0 : }
180 :
181 : #if 0
182 : { "slow" , /* equipment name */
183 : {
184 : EVID_SLOW, (1<<EVID_SLOW), /* event ID, trigger mask */
185 : "SYSTEM", /* event buffer */
186 : EQ_PERIODIC, /* equipment type */
187 : 0, /* event source */
188 : "MIDAS", /* format */
189 : TRUE, /* enabled */
190 : RO_ALWAYS, /* Read when running */
191 : 1000, /* poll every so milliseconds */
192 : 0, /* stop run after this event limit */
193 : 0, /* number of sub events */
194 : 1, /* history period */
195 : "", "", ""
196 : },
197 : read_slow_event,/* readout routine */
198 : },
199 : #endif
200 : };
201 :
202 : class EqRare :
203 : public TMFeEquipment
204 : {
205 : public:
206 0 : EqRare(const char* eqname, const char* eqfilename) // ctor
207 0 : : TMFeEquipment(eqname, eqfilename)
208 : {
209 0 : fEqConfEventID = 4;
210 0 : fEqConfPeriodMilliSec = 10000;
211 0 : fEqConfLogHistory = 0;
212 0 : fEqConfWriteEventsToOdb = false;
213 0 : fEqConfReadOnlyWhenRunning = false;
214 0 : }
215 :
216 0 : TMFeResult HandleInit(const std::vector<std::string>& args)
217 : {
218 0 : return TMFeOk();
219 : }
220 :
221 0 : void SendData(double dvalue)
222 : {
223 : char buf[1024];
224 0 : ComposeEvent(buf, sizeof(buf));
225 0 : BkInit(buf, sizeof(buf));
226 :
227 0 : double* ptr = (double*)BkOpen(buf, "rare", TID_DOUBLE);
228 0 : *ptr++ = dvalue;
229 0 : BkClose(buf, ptr);
230 :
231 0 : EqSendEvent(buf);
232 0 : }
233 :
234 0 : void HandlePeriodic()
235 : {
236 : //printf("EqSlow::HandlePeriodic!\n");
237 0 : double t = TMFE::GetTime();
238 0 : double data = 100.0*sin(-M_PI/2.0+M_PI*t/60);
239 0 : SendData(data);
240 : char status_buf[256];
241 0 : sprintf(status_buf, "value %.1f", data);
242 0 : EqSetStatus(status_buf, "#00FF00");
243 0 : }
244 : };
245 :
246 : class EqBulk :
247 : public TMFeEquipment
248 : {
249 : public: // configuration
250 : int fEventSize = 0;
251 : double fEventSleep = 1.0;
252 : std::vector<char> fEventBuffer;
253 :
254 : public: // internal state
255 : std::atomic_bool fThreadRunning{false};
256 : std::thread *fThread = NULL;
257 :
258 : public:
259 0 : EqBulk(const char* eqname, const char* eqfilename) // ctor
260 0 : : TMFeEquipment(eqname, eqfilename)
261 : {
262 0 : fEqConfPeriodMilliSec = 1000;
263 0 : fEqConfEventID = 3;
264 0 : fEqConfReadOnlyWhenRunning = true;
265 0 : }
266 :
267 0 : ~EqBulk() // dtor
268 0 : {
269 : // wait for thread to finish
270 0 : while (fThreadRunning) {
271 0 : fMfe->Sleep(0.1);
272 : }
273 :
274 0 : if (fThread) {
275 0 : fThread->join();
276 0 : delete fThread;
277 0 : fThread = NULL;
278 : }
279 0 : }
280 :
281 0 : TMFeResult HandleInit(const std::vector<std::string>& args)
282 : {
283 0 : EqSetStatus("Starting...", "white");
284 :
285 0 : fEqConfReadOnlyWhenRunning = true;
286 0 : fEqConfWriteEventsToOdb = false;
287 :
288 0 : fOdbEqSettings->RI("event_size", &fEventSize, true);
289 0 : fOdbEqSettings->RD("event_sleep_sec", &fEventSleep, true);
290 :
291 0 : printf("Event size set to %d bytes\n", fEventSize);
292 :
293 0 : fEventBuffer.resize(16+8+16+fEventSize+100);
294 :
295 : //size = sizeof(test_rb_wait_sleep);
296 : //status = db_get_value(hDB, hSet, "rb_wait_sleep", &test_rb_wait_sleep, &size, TID_DWORD, TRUE);
297 : //assert(status == DB_SUCCESS);
298 : //printf("Ring buffer wait sleep %d ms\n", test_rb_wait_sleep);
299 :
300 0 : fThread = new std::thread(&EqBulk::Thread, this);
301 :
302 0 : return TMFeOk();
303 : }
304 :
305 0 : void SendEvent()
306 : {
307 0 : char* buf = fEventBuffer.data();
308 0 : size_t bufsize = fEventBuffer.size();
309 0 : ComposeEvent(buf, bufsize);
310 0 : BkInit(buf, bufsize);
311 :
312 0 : char* ptr = (char*)BkOpen(buf, "bulk", TID_BYTE);
313 0 : ptr += fEventSize;
314 0 : BkClose(buf, ptr);
315 :
316 0 : EqSendEvent(buf);
317 0 : }
318 :
319 0 : void Thread()
320 : {
321 0 : printf("FeBulk::Thread: thread started\n");
322 :
323 0 : EqSetStatus("Thread running", "#00FF00");
324 :
325 0 : fThreadRunning = true;
326 0 : while (!fMfe->fShutdownRequested) {
327 0 : if (fMfe->fStateRunning || !fEqConfReadOnlyWhenRunning) {
328 0 : fMfe->Sleep(fEventSleep);
329 0 : SendEvent();
330 : } else {
331 0 : fMfe->Sleep(1.0);
332 : }
333 : }
334 :
335 0 : printf("FeBulk::Thread: thread finished\n");
336 0 : fThreadRunning = false;
337 0 : }
338 :
339 : #if 0
340 : EQUIPMENT equipment[] = {
341 :
342 : { "test" , /* equipment name */
343 : {
344 : EVID_TEST, (1<<EVID_TEST), /* event ID, trigger mask */
345 : "SYSTEM", /* event buffer */
346 : EQ_USER, /* equipment type */
347 : 0, /* event source */
348 : "MIDAS", /* format */
349 : TRUE, /* enabled */
350 : RO_RUNNING, /* Read when running */
351 : 100, /* poll every so milliseconds */
352 : 0, /* stop run after this event limit */
353 : 0, /* number of sub events */
354 : 0, /* no history */
355 : "", "", ""
356 : },
357 : read_test_event,/* readout routine */
358 : },
359 : { "" }
360 : };
361 : #endif
362 : };
363 :
364 : class EqRpc :
365 : public TMFeEquipment
366 : {
367 : public:
368 0 : EqRpc(const char* eqname, const char* eqfilename) // ctor
369 0 : : TMFeEquipment(eqname, eqfilename)
370 : {
371 0 : fEqConfEventID = 1;
372 0 : }
373 :
374 0 : ~EqRpc() // dtor
375 0 : {
376 0 : }
377 :
378 0 : TMFeResult HandleInit(const std::vector<std::string>& args)
379 : {
380 0 : fEqConfBuffer = "SYSTEM";
381 0 : EqSetStatus("Started...", "white");
382 0 : fMfe->Msg(MINFO, "HandleInit", std::string("Init") + " Ok!");
383 0 : return TMFeOk();
384 : }
385 :
386 0 : TMFeResult HandleRpc(const char* cmd, const char* args, std::string& response)
387 : {
388 0 : fMfe->Msg(MINFO, "HandleRpc", "RPC cmd [%s], args [%s]", cmd, args);
389 :
390 : // RPC handler
391 :
392 : char tmp[256];
393 0 : time_t now = time(NULL);
394 0 : sprintf(tmp, "{ \"current_time\" : [ %d, \"%s\"] }", (int)now, ctime(&now));
395 :
396 0 : response = tmp;
397 :
398 0 : return TMFeOk();
399 : }
400 :
401 0 : TMFeResult HandleBinaryRpc(const char* cmd, const char* args, std::vector<char>& response)
402 : {
403 0 : fMfe->Msg(MINFO, "HandleBinaryRpc", "RPC cmd [%s], args [%s]", cmd, args);
404 :
405 : // RPC handler
406 :
407 0 : response.resize(8*64);
408 :
409 0 : uint64_t* p64 = (uint64_t*)response.data();
410 :
411 0 : for (size_t i=0; i<response.size()/sizeof(p64[0]); i++) {
412 0 : *p64++ = (1<<i);
413 : }
414 :
415 0 : return TMFeOk();
416 : }
417 :
418 0 : TMFeResult HandleBeginRun(int run_number)
419 : {
420 0 : fMfe->Msg(MINFO, "HandleBeginRun", "Begin run %d!", run_number);
421 0 : EqSetStatus("Running", "#00FF00");
422 :
423 0 : printf("begin_of_run %d\n", run_number);
424 :
425 0 : int fail = 0;
426 0 : fOdbEqSettings->RI("begin_of_run_fail", &fail, true);
427 :
428 0 : if (fail) {
429 0 : printf("fail_begin_of_run: returning error status %d\n", fail);
430 0 : return TMFeErrorMessage("begin of run failed by ODB setting!");
431 : }
432 :
433 0 : double s = 0;
434 0 : fOdbEqSettings->RD("begin_of_run_sleep_sec", &s, true);
435 :
436 0 : if (s) {
437 0 : fMfe->SetWatchdogSec(s + 1);
438 0 : int ms = int(s*1000.0);
439 0 : printf("sleep_begin_of_run: calling ss_sleep(%d)\n", ms);
440 0 : ss_sleep(ms);
441 : }
442 :
443 0 : return TMFeOk();
444 : }
445 :
446 0 : TMFeResult HandleEndRun(int run_number)
447 : {
448 0 : fMfe->Msg(MINFO, "HandleEndRun", "End run %d!", run_number);
449 0 : EqSetStatus("Stopped", "#00FF00");
450 :
451 0 : printf("end_of_run %d\n", run_number);
452 :
453 0 : int fail = 0;
454 0 : fOdbEqSettings->RI("end_of_run_fail", &fail, true);
455 :
456 0 : if (fail) {
457 0 : printf("fail_end_of_run: returning error status %d\n", fail);
458 0 : return TMFeResult(fail, "end of run failed by ODB setting!");
459 : }
460 :
461 0 : double s = 0;
462 0 : fOdbEqSettings->RD("end_of_run_sleep_sec", &s, true);
463 :
464 0 : if (s) {
465 0 : fMfe->SetWatchdogSec(s + 1);
466 0 : int ms = int(s*1000.0);
467 0 : printf("sleep_end_of_run: calling ss_sleep(%d)\n", ms);
468 0 : ss_sleep(ms);
469 : }
470 :
471 0 : return TMFeOk();
472 : }
473 :
474 0 : TMFeResult HandlePauseRun(int run_number)
475 : {
476 0 : fMfe->Msg(MINFO, "HandlePauseRun", "Pause run %d!", run_number);
477 0 : EqSetStatus("Stopped", "#00FF00");
478 :
479 0 : printf("pause_run %d\n", run_number);
480 :
481 0 : int fail = 0;
482 0 : fOdbEqSettings->RI("pause_run_fail", &fail, true);
483 :
484 0 : if (fail) {
485 0 : printf("fail_pause_run: returning error status %d\n", fail);
486 0 : return TMFeResult(fail, "pause run failed by ODB setting!");
487 : }
488 :
489 0 : return TMFeOk();
490 : }
491 :
492 0 : TMFeResult HandleResumeRun(int run_number)
493 : {
494 0 : fMfe->Msg(MINFO, "HandleResumeRun", "Resume run %d!", run_number);
495 0 : EqSetStatus("Stopped", "#00FF00");
496 :
497 0 : printf("resume_run %d\n", run_number);
498 :
499 0 : int fail = 0;
500 0 : fOdbEqSettings->RI("resume_run_fail", &fail, true);
501 :
502 0 : if (fail) {
503 0 : printf("fail_resume_run: returning error status %d\n", fail);
504 0 : return TMFeResult(fail, "resume run failed by ODB setting!");
505 : }
506 :
507 0 : return TMFeOk();
508 : }
509 :
510 0 : TMFeResult HandleStartAbortRun(int run_number)
511 : {
512 0 : fMfe->Msg(MINFO, "HandleStartAbortRun", "Begin run %d aborted!", run_number);
513 0 : EqSetStatus("Stopped", "#00FF00");
514 :
515 0 : printf("start abort run %d\n", run_number);
516 :
517 0 : int fail = 0;
518 0 : fOdbEqSettings->RI("start_abort_fail", &fail, true);
519 :
520 0 : if (fail) {
521 0 : printf("fail_start_abort: returning error status %d\n", fail);
522 0 : return TMFeResult(fail, "start abort failed by ODB setting!");
523 : }
524 :
525 0 : return TMFeOk();
526 : }
527 : };
528 :
529 : class FeTest: public TMFrontend
530 : {
531 : public:
532 0 : FeTest() // ctor
533 0 : {
534 0 : FeSetName("fetest");
535 0 : FeAddEquipment(new EqRpc("test_rpc", __FILE__));
536 0 : FeAddEquipment(new EqRandom("test_random", __FILE__));
537 0 : FeAddEquipment(new EqSlow("test_slow", __FILE__));
538 0 : FeAddEquipment(new EqRare("test_rare", __FILE__));
539 0 : FeAddEquipment(new EqBulk("test_bulk", __FILE__));
540 0 : }
541 :
542 0 : void HandleUsage()
543 : {
544 : //printf("FeEverything::HandleUsage!\n");
545 0 : };
546 :
547 0 : TMFeResult HandleArguments(const std::vector<std::string>& args)
548 : {
549 : //printf("FeEverything::HandleArguments!\n");
550 0 : return TMFeOk();
551 : };
552 :
553 0 : TMFeResult HandleFrontendInit(const std::vector<std::string>& args)
554 : {
555 : //printf("FeEverything::HandleFrontendInit!\n");
556 0 : return TMFeOk();
557 : };
558 :
559 0 : TMFeResult HandleFrontendReady(const std::vector<std::string>& args)
560 : {
561 : //printf("FeEverything::HandleFrontendReady!\n");
562 : //FeStartPeriodicThread();
563 : //fMfe->StartRpcThread();
564 0 : return TMFeOk();
565 : };
566 :
567 0 : void HandleFrontendExit()
568 : {
569 : //printf("FeEverything::HandleFrontendExit!\n");
570 0 : };
571 : };
572 :
573 : // boilerplate main function
574 :
575 0 : int main(int argc, char* argv[])
576 : {
577 0 : FeTest fe_test;
578 0 : return fe_test.FeMain(argc, argv);
579 0 : }
580 :
581 : /* emacs
582 : * Local Variables:
583 : * tab-width: 8
584 : * c-basic-offset: 3
585 : * indent-tabs-mode: nil
586 : * End:
587 : */
|