MIDAS
Loading...
Searching...
No Matches
midas.js
Go to the documentation of this file.
1/********************************************************************\
2
3 Name: midas.js
4 Created by: Stefan Ritt
5 Created by: Konstantin Olchanski
6
7 Contents: JavaScript midas library for building custom pages
8
9\********************************************************************/
10
11// MIDAS type definitions from midas.h
12
13const tid_name = [
14 "NULL",
15 "UINT8",
16 "INT8",
17 "CHAR",
18 "UINT16",
19 "INT16",
20 "UINT32",
21 "INT32",
22 "BOOL",
23 "FLOAT",
24 "DOUBLE",
25 "BITFIELD",
26 "STRING",
27 "ARRAY",
28 "STRUCT",
29 "KEY",
30 "LINK",
31 "INT64",
32 "UINT64"
33];
34
35const tid_size = [
36 0,
37 1,
38 1,
39 1,
40 2,
41 2,
42 4,
43 4,
44 4,
45 4,
46 8,
47 0,
48 0,
49 0,
50 0,
51 0,
52 0,
53 8,
54 8
55];
56
57const TID_BYTE = 1;
58const TID_UINT8 = 1;
59const TID_SBYTE = 2;
60const TID_INT8 = 2;
61const TID_CHAR = 3;
62const TID_WORD = 4;
63const TID_UINT16 = 4;
64const TID_SHORT = 5;
65const TID_INT16 = 5;
66const TID_DWORD = 6;
67const TID_UINT32 = 6;
68const TID_INT = 7;
69const TID_INT32 = 7;
70const TID_BOOL = 8;
71const TID_FLOAT = 9;
72const TID_FLOAT32 = 9;
73const TID_DOUBLE = 10;
74const TID_FLOAT64 = 10;
75const TID_BITFIELD = 11;
76const TID_STRING = 12;
77const TID_ARRAY = 13;
78const TID_STRUCT = 14;
79const TID_KEY = 15;
80const TID_LINK = 16;
81const TID_INT64 = 17;
82const TID_UINT64 = 18;
83const TID_QWORD = 18;
84const TID_LAST = 19;
85
86const AT_INTERNAL = 1;
87const AT_PROGRAM = 2;
88const AT_EVALUATED = 3;
89const AT_PERIODIC = 4;
90
91const MT_ERROR = (1<<0);
92const MT_INFO = (1<<1);
93const MT_DEBUG = (1<<2);
94const MT_USER = (1<<3);
95const MT_LOG = (1<<4);
96const MT_TALK = (1<<5);
97const MT_CALL = (1<<6);
98
99const STATE_STOPPED = 1; /**< MIDAS run stopped */
100const STATE_PAUSED = 2; /**< MIDAS run paused */
101const STATE_RUNNING = 3; /**< MIDAS run running */
102
103const TR_START = 1; /**< Start transition */
104const TR_STOP = 2; /**< Stop transition */
105const TR_PAUSE = 4; /**< Pause transition */
106const TR_RESUME = 8; /**< Resume transition */
107const TR_STARTABORT = 16; /**< Start aborted transition */
108const TR_DEFERRED = 4096;
109
110const MODE_READ = (1<<0);
111const MODE_WRITE = (1<<1);
112const MODE_DELETE = (1<<2);
113const MODE_EXCLUSIVE = (1<<3);
114const MODE_ALLOC = (1<<6);
115const MODE_WATCH = (1<<7);
116
117/// \defgroup mjsonrpc_js JSON-RPC Javascript library (mjsonrpc_xxx)
118
119var mjsonrpc_default_url_web = "";
120var mjsonrpc_default_url_file = "https://localhost:8443/";
121
122var mjsonrpc_url;
123
124{
125if (window.location.protocol == 'file:') {
126 mjsonrpc_url = mjsonrpc_default_url_file;
127} else {
128 mjsonrpc_url = mjsonrpc_default_url_web;
129}
130}
131
132function mjsonrpc_set_url(url)
133{
134 /// \ingroup mjsonrpc_js
135 /// Change the URL of JSON-RPC server
136 /// @param[in] url the new URL, i.e. "https://daqserver.example.com:8443" (string)
137 /// @returns nothing
138 mjsonrpc_url = url;
139}
140
141function loadScript(src) {
142 return new Promise((resolve, reject) => {
143 let script = document.createElement('script');
144 script.src = src;
145
146 script.onload = () => resolve(script);
147 script.onerror = () => reject(new Error(`Script load error for ${src}`));
148
149 document.head.appendChild(script);
150 });
151}
152
153async function mjsonrpc_send_request(req)
154{
155
156 /// \ingroup mjsonrpc_js
157 /// Send JSON-RPC request(s) via HTTP POST. RPC response and error handling is done using the Javascript Promise mechanism:
158 ///
159 /// \code
160 /// var req = mjsonrpc_make_request(method, params, id);
161 /// mjsonrpc_send_request(req).then(function(rpc) {
162 /// var req = rpc.request; // reference to the rpc request
163 /// var id = rpc.id; // rpc response id (should be same as req.id)
164 /// var result = rpc.result; // rpc response result
165 /// ...
166 /// }).catch(function(error) {
167 /// mjsonrpc_error_alert(error);
168 /// });
169 /// \endcode
170 ///
171 /// @param[in] req request object or an array of request objects (object or array of objects)
172 /// @returns new Promise
173
174 //console.log("mjsonrpc_send_request!");
175
176 return new Promise(function(resolve, reject) {
177 var xhr = new XMLHttpRequest();
178 //xhr.responseType = 'json'; // this does not work: behaviour is not defined if RPC returns unparsable JSON
179 if (req.id == "arraybuffer") {
180 xhr.responseType = 'arraybuffer';
181 } else {
182 xhr.responseType = 'text';
183 }
184 xhr.withCredentials = true;
185
186 xhr.onreadystatechange = function()
187 {
188 //alert("XHR: ready state " + xhr.readyState + " status " + xhr.status);
189 if (xhr.readyState == 4) {
190
191 if (xhr.status != 200) {
192 var error = new Object;
193 error.request = req;
194 error.xhr = xhr;
195 reject(error);
196 return;
197 }
198
199 var contentType = xhr.getResponseHeader("Content-Type");
200 //console.log("XHR ContentType: " + contentType);
201 //console.log("XHR response type: " + typeof(xhr.response));
202
203 if (contentType == "application/octet-stream") {
204 var response = xhr.response;
205 //console.log("XHR response type: " + typeof(response));
206 //console.log("XHR response: " + response);
207 resolve(response);
208 return;
209 } else if (contentType == "application/json") {
210 var rpc_response = null;
211 var xhr_response = xhr.response;
212
213 // if xhr.responseType is "arraybuffer", we need to convert it back to text
214 // before we can parse it as json. K.O.
215 if (xhr.responseType == "arraybuffer") {
216 xhr_response = new TextDecoder("utf-8").decode(xhr.response);
217 }
218
219 try {
220 rpc_response = JSON.parse(xhr_response);
221 if (!rpc_response) {
222 throw "JSON parser returned null";
223 }
224 } catch (exc) {
225 //alert("exception " + exc);
226 var error = new Object;
227 error.request = req;
228 error.xhr = xhr;
229 error.exception = exc;
230 reject(error);
231 return;
232 }
233
234 if (Array.isArray(rpc_response)) {
235 var batch = new Array;
236 for (var i=0; i<rpc_response.length; i++) {
237 var rpc = new Object;
238 rpc.request = req[i];
239 rpc.id = rpc_response[i].id;
240 if (rpc_response[i].hasOwnProperty("error")) {
241 rpc.error = rpc_response[i].error;
242 } else {
243 rpc.result = rpc_response[i].result;
244 }
245 batch.push(rpc);
246 }
247 resolve(batch);
248 return;
249 }
250
251 if (rpc_response.error) {
252 var error = new Object;
253 error.request = req;
254 error.xhr = xhr;
255 error.error = rpc_response.error;
256 reject(error);
257 return;
258 }
259
260 var rpc = new Object;
261 rpc.request = req;
262 rpc.id = rpc_response.id;
263 rpc.result = rpc_response.result;
264 resolve(rpc);
265 return;
266 } else {
267 var error = new Object;
268 error.request = req;
269 error.xhr = xhr;
270 error.error = "Unexpected Content-Type: " + contentType;
271 reject(error);
272 return;
273 }
274 }
275 }
276
277 xhr.open('POST', mjsonrpc_url + "?mjsonrpc");
278 xhr.setRequestHeader('Content-Type', 'application/json');
279 xhr.setRequestHeader('Accept', 'application/json');
280 if (req == "send invalid json")
281 xhr.send("invalid json");
282 else {
283 // special serialization for BigInt numbers
284 let j = JSON.stringify(req, (key, value) =>
285 typeof value === 'bigint' ? value.toString() : value
286 );
287
288 xhr.send(j);
289 }
290 });
291}
292
293function mjsonrpc_debug_alert(rpc) {
294 /// \ingroup mjsonrpc_js
295 /// Debug method to show RPC response
296 /// @param[in] rpc object (object), see mjsonrpc_send_request()
297 /// @returns nothing
298 //console.log(rpc);
299 if (Array.isArray(rpc)) {
300 //console.log("here!");
301 var a = "";
302 rpc.forEach(function(r) {
303 //console.log(r);
304 if (r.error) {
305 a += "method: \"" + r.request.method + "\", params: " + r.request.params + ", id: " + JSON.stringify(r.id) + ", error: " + JSON.stringify(r.error);
306 } else {
307 a += "method: \"" + r.request.method + "\", params: " + r.request.params + ", id: " + JSON.stringify(r.id) + ", response: " + JSON.stringify(r.result);
308 }
309 a += "\n";
310 });
311 alert("mjsonrpc_debug_alert: array:\n" + a);
312 } else {
313 alert("mjsonrpc_debug_alert: method: \"" + rpc.request.method + "\", params: " + rpc.request.params + ", id: " + JSON.stringify(rpc.id) + ", response: " + JSON.stringify(rpc.result));
314 }
315}
316
317function mjsonrpc_decode_error(error) {
318 /// \ingroup mjsonrpc_js
319 /// Convert RPC error status to human-readable string
320 /// @param[in] error rejected promise error object (object)
321 /// @returns decoded error report (string)
322
323 //console.log("mjsonrpc_decode_error: " + JSON.stringify(error));
324 //console.log("mjsonrpc_decode_error xhr: " + JSON.stringify(error.xhr));
325 //for (var x in error.xhr) {
326 // if (x == "responseText") continue;
327 // if (x == "responseXML") continue;
328 // console.log("xhr[" + x + "] = [" + error.xhr[x] + "]");
329 //}
330
331 function is_network_error(xhr) {
332 return xhr.readyState==4 && xhr.status==0;
333 }
334 function is_http_error(xhr) {
335 return xhr.readyState==4 && xhr.status!=200;
336 }
337 function print_xhr(xhr) {
338 return "readyState: " + xhr.readyState + ", HTTP status: " + xhr.status + " (" + xhr.statusText + ")";
339 }
340 function print_request(request) {
341 //console.log("print_request: " + request + ", JSON: " + JSON.stringify(request));
342 if (Array.isArray(request)) {
343 var s = "batch request: ";
344 request.forEach(function(item, index) {
345 s += print_request(item);
346 s += " ";
347 });
348 return s;
349 }
350 return "method: \"" + request.method + "\", params: " + request.params + ", id: " + request.id;
351 }
352
353 if (error.xhr && is_network_error(error.xhr)) {
354 return "network error: see javascript console, " + print_request(error.request);
355 } else if (error.xhr && is_http_error(error.xhr)) {
356 return "http error: " + print_xhr(error.xhr) + ", " + print_request(error.request);
357 } else if (error.exception) {
358 return "json parser exception: " + error.exception + ", " + print_request(error.request);
359 } else if (error.error) {
360 return "json-rpc error: " + JSON.stringify(error.error) + ", " + print_request(error.request) + ", " +
361 "<br>" + error.xhr.response;
362 } else if (error.request && error.xhr) {
363 return "unknown error, request: " + print_request(error.request) + ", xhr: " + print_xhr(error.xhr);
364 } else {
365 return "javascript exception: " + error;
366 }
367}
368
369function mjsonrpc_error_alert(error, callback, param) {
370 /// \ingroup mjsonrpc_js
371 /// Handle all errors
372 /// @param[in] error rejected promise error object (object)
373 /// @returns nothing
374 if (error.request) {
375 var s = mjsonrpc_decode_error(error);
376 dlgMessage("RPC Error", s, true, true, callback, param);
377 } else {
378 dlgMessage("Javascript exception or error", error, true, true, callback, param);
379 throw(error);
380 }
381}
382
383function mjsonrpc_make_request(method, params, id)
384{
385 /// \ingroup mjsonrpc_js
386 /// Creates a new JSON-RPC request object
387 /// @param[in] method name of the RPC method (string)
388 /// @param[in] params parameters of the RPC method (object)
389 /// @param[in] id optional request id (see JSON-RPC specs) (object)
390 /// @returns the request object (object)
391
392 if (id == null)
393 id = Date.now();
394
395 var req = new Object();
396 req.jsonrpc = "2.0"; // version
397 req.method = method;
398 if (typeof params == 'string') {
399 req.params = JSON.parse(params);
400 } else {
401 req.params = params;
402 }
403 if (!req.params)
404 req.params = null; // make sure we have "params", even if set to null or undefined
405 req.id = id;
406
407 return req;
408}
409
410function mjsonrpc_call(method, params, id)
411{
412 /// \ingroup mjsonrpc_js
413 /// Creates a JSON-RPC request and sends it to mhttpd via HTTP POST.
414 /// RPC response and error handling is done using the Javascript Promise mechanism:
415 ///
416 /// \code
417 /// mjsonrpc_call(method, params, id).then(function(rpc) {
418 /// var req = rpc.request; // reference to the rpc request
419 /// var id = rpc.id; // rpc response id (should be same as req.id)
420 /// var result = rpc.result; // rpc response result
421 /// ...
422 /// }).catch(function(error) {
423 /// mjsonrpc_error_alert(error);
424 /// });
425 /// \endcode
426 /// @param[in] method name of the RPC method (string)
427 /// @param[in] params parameters of the RPC method (object)
428 /// @param[in] id optional request id (see JSON-RPC specs) (object)
429 /// @returns new Promise
430
431 var req = mjsonrpc_make_request(method, params, id);
432 return mjsonrpc_send_request(req);
433}
434
435function mjsonrpc_start_program(name, id) {
436 /// \ingroup mjsonrpc_js
437 /// Start a MIDAS program
438 ///
439 /// RPC method: "start_program"
440 ///
441 /// \code
442 /// mjsonrpc_start_program("logger").then(function(rpc) {
443 /// var req = rpc.request; // reference to the rpc request
444 /// var id = rpc.id; // rpc response id (should be same as req.id)
445 /// var result = rpc.result; // rpc response result
446 /// var status = rpc.result.status; // return status of ss_system(), see MIDAS JSON-RPC docs
447 /// ...
448 /// }).catch(function(error) {
449 /// mjsonrpc_error_alert(error);
450 /// });
451 /// \endcode
452 /// @param[in] name Name of program to start, should be same as the ODB entry "/Programs/name" (string)
453 /// @param[in] id optional request id (see JSON-RPC specs) (object)
454 /// @returns new Promise
455
456 var req = new Object();
457 req.name = name;
458 return mjsonrpc_call("start_program", req, id);
459}
460
461function mjsonrpc_stop_program(name, id) {
462 /// \ingroup mjsonrpc_js
463 /// Stop a MIDAS program via cm_shutdown()
464 ///
465 /// RPC method: "cm_shutdown"
466 ///
467 /// \code
468 /// mjsonrpc_stop_program("logger").then(function(rpc) {
469 /// var req = rpc.request; // reference to the rpc request
470 /// var id = rpc.id; // rpc response id (should be same as req.id)
471 /// var result = rpc.result; // rpc response result
472 /// var status = rpc.result.status; // return status of cm_shutdown(), see MIDAS JSON-RPC docs and cm_shutdown() docs
473 /// ...
474 /// }).catch(function(error) {
475 /// mjsonrpc_error_alert(error);
476 /// });
477 /// \endcode
478 /// @param[in] name Name of program to stop (string)
479 /// @param[in] id optional request id (see JSON-RPC specs) (object)
480 /// @returns new Promise
481
482 var req = new Object();
483 req.name = name;
484 return mjsonrpc_call("cm_shutdown", req, id);
485}
486
487function mjsonrpc_cm_exist(name, unique, id) {
488 /// \ingroup mjsonrpc_js
489 /// Check if a MIDAS program is running via cm_exist()
490 ///
491 /// RPC method: "cm_exist"
492 ///
493 /// \code
494 /// mjsonrpc_cm_exist("my_program_name").then(function(rpc) {
495 /// if (rpc.result.status == 1) {
496 /// // Program is running
497 /// } else if (rpc.result.status == 103) {
498 /// // Program is not running
499 /// } else {
500 /// // Some unexpected error happened
501 /// }
502 /// }).catch(function(error) {
503 /// mjsonrpc_error_alert(error);
504 /// });
505 /// \endcode
506 ///
507 /// @param[in] name Name of program to check (string)
508 /// @param[in] unique bUnique argument to cm_exist() (bool)
509 /// @param[in] id optional request id (see JSON-RPC specs) (object)
510 /// @returns new Promise
511 ///
512 var req = new Object();
513 req.name = name;
514 req.unique = unique;
515 return mjsonrpc_call("cm_exist", req, id);
516}
517
518function mjsonrpc_al_reset_alarm(alarms, id) {
519 /// \ingroup mjsonrpc_js
520 /// Reset alarms
521 ///
522 /// RPC method: "al_reset_alarm"
523 ///
524 /// \code
525 /// mjsonrpc_al_reset_alarm(["alarm1", "alarm2"]).then(function(rpc) {
526 /// var req = rpc.request; // reference to the rpc request
527 /// var id = rpc.id; // rpc response id (should be same as req.id)
528 /// var result = rpc.result; // rpc response result
529 /// ... result.status[0]; // status of al_reset_alarm() for 1st alarm
530 /// ... result.status[1]; // status of al_reset_alarm() for 2nd alarm
531 /// }).catch(function(error) {
532 /// mjsonrpc_error_alert(error);
533 /// });
534 /// \endcode
535 /// @param[in] alarms Array of alarm names (array of strings)
536 /// @param[in] id optional request id (see JSON-RPC specs) (object)
537 /// @returns new Promise
538 ///
539 var req = new Object();
540 req.alarms = alarms;
541 return mjsonrpc_call("al_reset_alarm", req, id);
542}
543
544function mjsonrpc_al_trigger_alarm(name, message, xclass, condition, type, id) {
545 /// \ingroup mjsonrpc_js
546 /// Reset alarms
547 ///
548 /// RPC method: "al_reset_alarm"
549 ///
550 /// \code
551 /// mjsonrpc_al_reset_alarm(["alarm1", "alarm2"]).then(function(rpc) {
552 /// var req = rpc.request; // reference to the rpc request
553 /// var id = rpc.id; // rpc response id (should be same as req.id)
554 /// var result = rpc.result; // rpc response result
555 /// ... result.status[0]; // status of al_reset_alarm() for 1st alarm
556 /// ... result.status[1]; // status of al_reset_alarm() for 2nd alarm
557 /// }).catch(function(error) {
558 /// mjsonrpc_error_alert(error);
559 /// });
560 /// \endcode
561 /// @param[in] alarms Array of alarm names (array of strings)
562 /// @param[in] id optional request id (see JSON-RPC specs) (object)
563 /// @returns new Promise
564 ///
565 var req = new Object();
566 req.name = name;
567 req.message = message;
568 req.class = xclass;
569 req.condition = condition;
570 req.type = type;
571 return mjsonrpc_call("al_trigger_alarm", req, id);
572}
573
574function mjsonrpc_db_copy(paths, id) {
575 /// \ingroup mjsonrpc_js
576 /// Get a copy of ODB. Symlinks are not resolved, ODB path names are not converted to lower-case.
577 ///
578 /// Instead of this function, please use db_get_values() as a simple way to get easy to use ODB values.
579 ///
580 /// RPC method: "db_copy"
581 ///
582 /// \code
583 /// mjsonrpc_db_copy(["/runinfo", "/equipment/foo"]).then(function(rpc) {
584 /// var req = rpc.request; // reference to the rpc request
585 /// var id = rpc.id; // rpc response id (should be same as req.id)
586 /// var result = rpc.result; // rpc response result
587 /// ... result.status[0]; // status of db_get_value() for /runinfo
588 /// ... result.status[1]; // status of db_get_value() for /equipment
589 /// var runinfo = result.data[0]; // javascript object representing the ODB runinfo structure
590 /// var equipment = result.data[1]; // javascript object representing /equipment/foo
591 /// }).catch(function(error) {
592 /// mjsonrpc_error_alert(error);
593 /// });
594 /// \endcode
595 /// @param[in] paths Array of ODB paths (array of strings)
596 /// @param[in] id optional request id (see JSON-RPC specs) (object)
597 /// @returns new Promise
598 ///
599 var req = new Object();
600 req.paths = paths;
601 return mjsonrpc_call("db_copy", req, id);
602}
603
604function mjsonrpc_db_get_values(paths, id) {
605 /// \ingroup mjsonrpc_js
606 /// Get values of ODB variables
607 ///
608 /// RPC method: "db_get_values"
609 ///
610 /// \code
611 /// mjsonrpc_db_get_values(["/runinfo", "/equipment"]).then(function(rpc) {
612 /// var req = rpc.request; // reference to the rpc request
613 /// var id = rpc.id; // rpc response id (should be same as req.id)
614 /// var result = rpc.result; // rpc response result
615 /// ... result.status[0]; // status of db_get_value() for /runinfo
616 /// ... result.status[1]; // status of db_get_value() for /equipment
617 /// ... result.last_written[0]; // "last written" timestamp for /runinfo
618 /// ... result.last_written[1]; // "last written" timestamp for /equipment
619 /// var runinfo = result.data[0]; // javascript object representing the ODB runinfo structure
620 /// ... runinfo["run number"]; // access the run number, note: all ODB names should be in lower-case.
621 /// ... runinfo["run number/last_written"]; // "last_written" timestamp for the run number
622 /// ... result.data[1].foo.variables.bar; // access /equipment/foo/variables/bar
623 /// }).catch(function(error) {
624 /// mjsonrpc_error_alert(error);
625 /// });
626 /// \endcode
627 /// @param[in] paths Array of ODB paths (array of strings)
628 /// @param[in] id optional request id (see JSON-RPC specs) (object)
629 /// @returns new Promise
630 ///
631 var req = new Object();
632 req.paths = paths;
633 return mjsonrpc_call("db_get_values", req, id);
634}
635
636function mjsonrpc_db_get_value(paths, id) {
637 /// \ingroup mjsonrpc_js
638 /// Get values of ODB variables
639 ///
640 /// RPC method: "db_get_value"
641 ///
642 /// \code
643 /// mjsonrpc_db_get_value("/runinfo").then(function(rpc) {
644 /// var req = rpc.request; // reference to the rpc request
645 /// var id = rpc.id; // rpc response id (should be same as req.id)
646 /// var result = rpc.result; // rpc response result
647 /// ... result.status[0]; // status of db_get_value() for /runinfo
648 /// ... result.status[1]; // status of db_get_value() for /equipment
649 /// ... result.last_written[0]; // "last written" timestamp for /runinfo
650 /// ... result.last_written[1]; // "last written" timestamp for /equipment
651 /// var runinfo = result.data[0]; // javascript object representing the ODB runinfo structure
652 /// ... runinfo["run number"]; // access the run number, note: all ODB names should be in lower-case.
653 /// ... runinfo["run number/last_written"]; // "last_written" timestamp for the run number
654 /// ... result.data[1].foo.variables.bar; // access /equipment/foo/variables/bar
655 /// }).catch(function(error) {
656 /// mjsonrpc_error_alert(error);
657 /// });
658 /// \endcode
659 /// @param[in] paths Array of ODB paths (array of strings)
660 /// @param[in] id optional request id (see JSON-RPC specs) (object)
661 /// @returns new Promise
662 ///
663 let req = new Object();
664 req.paths = [paths];
665 return mjsonrpc_call("db_get_values", req, id);
666}
667
668function db_get_value(path, callback) {
669 if (!Array.isArray(path))
670 path = [path];
671
672 let req = new Object();
673 req.paths = path;
674 req.omit_names = true;
675 req.omit_last_written = true;
676 mjsonrpc_call("db_get_values", req).then(rpc => callback(rpc))
677 .catch(error => mjsonrpc_error_alert(error));
678}
679
680function mjsonrpc_db_ls(paths, id) {
681 /// \ingroup mjsonrpc_js
682 /// Get list of contents of an ODB subdirectory, similar to odbedit command "ls -l". To get values of ODB variables, use db_get_values().
683 ///
684 /// RPC method: "db_ls"
685 ///
686 /// \code
687 /// mjsonrpc_db_ls(["/alarms/alarms", "/equipment"]).then(function(rpc) {
688 /// var req = rpc.request; // reference to the rpc request
689 /// var id = rpc.id; // rpc response id (should be same as req.id)
690 /// var result = rpc.result; // rpc response result
691 /// ... result.status[0]; // status of db_copy_json_ls() for /alarms/alarms
692 /// ... result.status[1]; // status of db_copy_json_ls() for /equipment
693 /// var alarms = result.data[0]; // javascript object representing the contents of ODB /alarms/alarms
694 /// var equipment = result.data[1]; // javascript object representing the contents of ODB /equipment
695 /// }).catch(function(error) {
696 /// mjsonrpc_error_alert(error);
697 /// });
698 /// \endcode
699 /// @param[in] paths Array of ODB paths (array of strings)
700 /// @param[in] id optional request id (see JSON-RPC specs) (object)
701 /// @returns new Promise
702 ///
703 var req = new Object();
704 req.paths = paths;
705 return mjsonrpc_call("db_ls", req, id);
706}
707
708function mjsonrpc_db_resize(paths, new_lengths, id) {
709 /// \ingroup mjsonrpc_js
710 /// Change size of ODB arrays
711 ///
712 /// RPC method: "db_resize"
713 ///
714 /// \code
715 /// mjsonrpc_db_resize(["/test/intarray1", "/test/dblarray2"], [10, 20]).then(function(rpc) {
716 /// var req = rpc.request; // reference to the rpc request
717 /// var id = rpc.id; // rpc response id (should be same as req.id)
718 /// var result = rpc.result; // rpc response result
719 /// ... result.status[0]; // status of db_set_num_values() for 1st path
720 /// ... result.status[1]; // status of db_set_num_values() for 2nd path
721 /// }).catch(function(error) {
722 /// mjsonrpc_error_alert(error);
723 /// });
724 /// \endcode
725 /// @param[in] paths Array of ODB paths (array of strings)
726 /// @param[in] new_sizes Array of new sizes for each path (array of ints)
727 /// @param[in] id optional request id (see JSON-RPC specs) (object)
728 /// @returns new Promise
729 ///
730 var req = new Object();
731 req.paths = paths;
732 req.new_lengths = new_lengths;
733 return mjsonrpc_call("db_resize", req, id);
734}
735
736function mjsonrpc_db_key(paths, id) {
737 /// \ingroup mjsonrpc_js
738 /// Get ODB keys
739 ///
740 /// RPC method: "db_key"
741 ///
742 /// \code
743 /// mjsonrpc_db_key(["/test/intarray1", "/test/dblarray2"]).then(function(rpc) {
744 /// var req = rpc.request; // reference to the rpc request
745 /// var id = rpc.id; // rpc response id (should be same as req.id)
746 /// var result = rpc.result; // rpc response result
747 /// ... result.status[0]; // status of db_get_key() for 1st path
748 /// ... result.status[1]; // status of db_get_key() for 2nd path
749 /// }).catch(function(error) {
750 /// mjsonrpc_error_alert(error);
751 /// });
752 /// \endcode
753 /// @param[in] paths Array of ODB paths (array of strings)
754 /// @param[in] id optional request id (see JSON-RPC specs) (object)
755 /// @returns new Promise
756 ///
757 var req = new Object();
758 req.paths = paths;
759 return mjsonrpc_call("db_key", req, id);
760}
761
762function mjsonrpc_db_delete(paths, id) {
763 /// \ingroup mjsonrpc_js
764 /// Delete ODB entries
765 ///
766 /// RPC method: "db_delete"
767 ///
768 /// \code
769 /// mjsonrpc_db_delete(["/test/test1", "/test/test2"]).then(function(rpc) {
770 /// var req = rpc.request; // reference to the rpc request
771 /// var id = rpc.id; // rpc response id (should be same as req.id)
772 /// var result = rpc.result; // rpc response result
773 /// ... result.status[0]; // status of db_delete() for 1st path
774 /// ... result.status[1]; // status of db_delete() for 2nd path
775 /// }).catch(function(error) {
776 /// mjsonrpc_error_alert(error);
777 /// });
778 /// \endcode
779 /// @param[in] paths Array of ODB paths (array of strings)
780 /// @param[in] id optional request id (see JSON-RPC specs) (object)
781 /// @returns new Promise
782 ///
783 var req = new Object();
784 req.paths = paths;
785 return mjsonrpc_call("db_delete", req, id);
786}
787
788function mjsonrpc_db_paste(paths, values, id) {
789 /// \ingroup mjsonrpc_js
790 /// Write values info ODB.
791 ///
792 /// RPC method: "db_paste"
793 ///
794 /// \code
795 /// mjsonrpc_db_paste(["/runinfo/run number", "/equipment/foo/settings/bar"], [123,456]).then(function(rpc) {
796 /// var req = rpc.request; // reference to the rpc request
797 /// var id = rpc.id; // rpc response id (should be same as req.id)
798 /// var result = rpc.result; // rpc response result
799 /// ... result.status[0]; // status of db_set_value() for /runinfo
800 /// ... result.status[1]; // status of db_set_value() for /equipment
801 /// }).catch(function(error) {
802 /// mjsonrpc_error_alert(error);
803 /// });
804 /// \endcode
805 /// @param[in] paths Array of ODB paths (array of strings)
806 /// @param[in] values Array of ODB values (array of anything)
807 /// @param[in] id optional request id (see JSON-RPC specs) (object)
808 /// @returns new Promise
809 ///
810 var req = new Object();
811 req.paths = paths;
812 req.values = values;
813 return mjsonrpc_call("db_paste", req, id);
814}
815
816function mjsonrpc_db_set_value(path, value, id) {
817 /// \ingroup mjsonrpc_js
818 /// Write value info ODB.
819 ///
820 /// RPC method: "db_set_value"
821 ///
822 /// \code
823 /// mjsonrpc_set_value("runinfo/run number", 123).then(function(rpc) {
824 /// var req = rpc.request; // reference to the rpc request
825 /// var id = rpc.id; // rpc response id (should be same as req.id)
826 /// var result = rpc.result; // rpc response result
827 /// ... result.status[0]; // status of db_set_value() for /runinfo
828 /// ... result.status[1]; // status of db_set_value() for /equipment
829 /// }).catch(function(error) {
830 /// mjsonrpc_error_alert(error);
831 /// });
832 /// \endcode
833 /// @param[in] paths Array of ODB paths (array of strings)
834 /// @param[in] values Array of ODB values (array of anything)
835 /// @param[in] id optional request id (see JSON-RPC specs) (object)
836 /// @returns new Promise
837 ///
838 var req = new Object();
839 req.paths = [path];
840 req.values = [value];
841 return mjsonrpc_call("db_paste", req, id);
842}
843
844function mjsonrpc_db_create(paths, id) {
845 /// \ingroup mjsonrpc_js
846 /// Create ODB entries
847 ///
848 /// RPC method: "db_create"
849 ///
850 /// @param[in] paths Array of ODB entries to create (array of objects)
851 /// @param[in] paths[i].path ODB path name to create (string)
852 /// @param[in] paths[i].type TID_xxx data type (integer)
853 /// @param[in] paths[i].array_length Optional array length (default is 1) (integer)
854 /// @param[in] paths[i].string_length Optional string length (default is NAME_LENGTH) (integer)
855 /// @param[in] id optional request id (see JSON-RPC specs) (object)
856 /// @returns new Promise
857
858 return mjsonrpc_call("db_create", paths, id);
859}
860
861function mjsonrpc_cm_msg(message, type, id) {
862 /// \ingroup mjsonrpc_js
863 /// Get values of ODB variables
864 ///
865 /// RPC method: "cm_msg1"
866 ///
867 /// \code
868 /// mjsonrpc_cm_msg("this is a new message").then(function(rpc) {
869 /// var req = rpc.request; // reference to the rpc request
870 /// var id = rpc.id; // rpc response id (should be same as req.id)
871 /// var status = rpc.result.status; // return status of MIDAS cm_msg1()
872 /// ...
873 /// }).catch(function(error) {
874 /// mjsonrpc_error_alert(error);
875 /// });
876 /// \endcode
877 /// @param[in] message Text of midas message (string)
878 /// @param[in] type optional message type, one of MT_xxx. Default is MT_INFO (integer)
879 /// @param[in] id optional request id (see JSON-RPC specs) (object)
880 /// @returns new Promise
881 ///
882 var req = new Object();
883 req.message = message;
884 if (type)
885 req.type = type;
886 return mjsonrpc_call("cm_msg1", req, id);
887}
888
889function mjsonrpc_get_timezone() {
890 /// Get timezone offset of server in hours
891 ///
892 /// RPC method: "get_timezone"
893 ///
894 /// \code
895 /// mjsonrpc_get_timezone().then(function(rpc) {
896 /// var req = rpc.request; // reference to the rpc request
897 /// var tz = rpc.result; // server timezone
898 /// ...
899 /// }).catch(function(error) {
900 /// mjsonrpc_error_alert(error);
901 /// });
902 /// \endcode
903 /// @returns new Promise
904 ///
905 var req = new Object();
906 return mjsonrpc_call("get_timezone", req, 0);
907}
908
909function modbset(path, value)
910 /// \ingroup mjsonrpc_js
911 /// Simplified function to initiate an ODB write RPC request. This function returns immediately, without waiting for the request to complete. There is no way to check that the write request completed without error. Multiple calls to modbset() may result in out-of-order writes to ODB (later requests may be processed before earlier requests).
912 ///
913{
914 if (Array.isArray(path)) {
915 mjsonrpc_db_paste(path,value).then(function(rpc) {}).catch(function(error) {
916 mjsonrpc_error_alert(error); });
917 } else {
918 mjsonrpc_db_paste([path],[value]).then(function(rpc) {}).catch(function(error) {
919 mjsonrpc_error_alert(error); });
920 }
921}
922
923function align8(x) {
924 return ((x+7) & ~7);
925}
926
927function bkToObj(array) {
928 /// Midas banks-to-object: Parses a raw midas even received via the new bm_receive_event
929 /// call and converts it into an JS object of with following elements and returns it:
930 ///
931 /// e.event_id <-- elements of midas event header
932 /// e.trigger_mask <-/
933 /// e.serial_number <-/
934 /// e.time_stamp <-/
935 /// e.time_stamp_date<-/
936 /// e.data_size <-/
937 ///
938 /// e.banks_16bit <-- true if we have 16-bit banks
939 /// e.banks_32bit <-- true if we have 32-bit banks
940 /// e.banks_32bita <-- true if we have 64-bit aligned 32-bit banks
941
942
943 /// e.bank[] <-- array of banks
944 /// .name <-- name of bank
945 /// .type <-- bank type, one of TID_xxx
946 /// .size <-- bank size in bytes
947 /// .hexdata[] <-- array of raw (byte) data
948 /// .array[] <-- array of converted data (UINT16, UINT32, UINT32, INT32, FLOAT, DOUBLE)
949 ///
950 /// This function is used by the event_dump.html page and can be used in a custom
951 /// page for single event displays.
952
953 let e = {};
954 e.bank = [];
955
956 try {
957 if (!array || typeof array.byteLength !== "number" || array.byteLength % 4 !== 0)
958 return e;
959
960 let data8 = new Uint8Array(array);
961 let data16 = new Uint16Array(array);
962 let data32 = new Uint32Array(array);
963 let event_header_size = 16; // bytes
964
965 if (array.byteLength < event_header_size)
966 return e;
967
968 // decode event header
969 e.event_id = data16[0];
970 e.trigger_mask = data16[1];
971 e.serial_number = data32[1];
972 e.time_stamp = data32[2];
973 e.time_stamp_date = new Date(e.time_stamp*1000);
974 e.data_size = data32[3];
975
976 // decode banks size and type
977 let bank_header_size = 8;
978 let event_end = e.data_size + event_header_size;
979 if (e.data_size < bank_header_size || array.byteLength < event_header_size + bank_header_size)
980 return e;
981
982 e.bank_total_size = data32[4];
983 e.bank_flags = data32[5];
984 e.banks_16bit = (e.bank_flags === 0x01);
985 e.banks_32bit = (e.bank_flags === 0x11);
986 e.banks_32bita = (e.bank_flags === 0x31);
987
988 if (!e.banks_16bit && !e.banks_32bit && !e.banks_32bita)
989 return e;
990
991 let i8 = event_header_size + bank_header_size;
992
993 //console.log("AAA bank type: " + e.banks_16bit + e.banks_32bit + e.banks_32bita);
994
995 // iterate over banks
996 while(i8 < event_end) {
997 let bank_data_header_size = e.banks_16bit ? 8 : (e.banks_32bit ? 12 : 16);
998 if (i8 + bank_data_header_size > event_end ||
999 i8 + bank_data_header_size > array.byteLength)
1000 return e;
1001
1002 let b = {};
1003 b.name = String.fromCharCode(data8[i8], data8[i8 + 1], data8[i8 + 2], data8[i8 + 3]);
1004 if (e.banks_16bit) {
1005 b.type = data16[i8/2 + 2];
1006 b.size = data16[i8/2 + 3];
1007 } else {
1008 b.type = data32[i8/4 + 1];
1009 b.size = data32[i8/4 + 2];
1010 }
1011 i8 += bank_data_header_size;
1012
1013 if (b.type >= tid_name.length)
1014 b.type = 0;
1015
1016 let size_align = 1;
1017
1018 if (b.type === TID_INT8) {
1019 } else if (b.type === TID_UINT8) {
1020 } else if (b.type === TID_INT16) {
1021 size_align = 2;
1022 } else if (b.type === TID_UINT16) {
1023 size_align = 2;
1024 } else if (b.type === TID_INT32) {
1025 size_align = 4;
1026 } else if (b.type === TID_UINT32) {
1027 size_align = 4;
1028 } else if (b.type === TID_INT64) {
1029 size_align = 8;
1030 } else if (b.type === TID_UINT64) {
1031 size_align = 8;
1032 } else if (b.type === TID_FLOAT) {
1033 size_align = 4;
1034 } else if (b.type === TID_DOUBLE) {
1035 size_align = 8;
1036 } else {
1037 }
1038
1039 let aligned_size = align8(b.size);
1040 if (i8 + b.size > event_end || i8 + b.size > array.byteLength ||
1041 i8 + aligned_size > event_end || i8 + aligned_size > array.byteLength)
1042 return e;
1043
1044 if (b.size % size_align != 0) {
1045 //console.log("b.size: " + b.size + " misalign: " + b.size % size_align);
1046 b.size -= (b.size % size_align);
1047 }
1048
1049 b.data = array.slice(i8, i8+b.size);
1050 i8 += aligned_size;
1051
1052 //if (e.banks_32bit) {
1053 // let pad = align8(b.size) - b.size;
1054 // i8 += pad;
1055 //} else
1056 // i8 = align8(i8);
1057
1058 b.hexdata = new Uint8Array(b.data);
1059
1060 if (b.type === TID_INT8)
1061 b.array = new Int8Array(b.data);
1062 else if (b.type === TID_UINT8)
1063 b.array = new Uint8Array(b.data);
1064 else if (b.type === TID_INT16)
1065 b.array = new Int16Array(b.data);
1066 else if (b.type === TID_UINT16)
1067 b.array = new Uint16Array(b.data);
1068 else if (b.type === TID_INT32)
1069 b.array = new Int32Array(b.data);
1070 else if (b.type === TID_UINT32)
1071 b.array = new Uint32Array(b.data);
1072 else if (b.type === TID_INT64)
1073 b.array = new BigInt64Array(b.data);
1074 else if (b.type === TID_UINT64)
1075 b.array = new BigUint64Array(b.data);
1076 else if (b.type === TID_FLOAT)
1077 b.array = new Float32Array(b.data);
1078 else if (b.type === TID_DOUBLE)
1079 b.array = new Float64Array(b.data);
1080 else
1081 b.array = "Unknown data type " + b.type;
1082
1083 e.bank.push(b);
1084 }
1085 } catch (error) {
1086 return e;
1087 }
1088
1089 return e;
1090}
1091
1092/* emacs
1093 * Local Variables:
1094 * tab-width: 8
1095 * c-basic-offset: 3
1096 * js-indent-level: 3
1097 * indent-tabs-mode: nil
1098 * End:
1099 */