1/********************************************************************\
4 Created by: Stefan Ritt
5 Created by: Konstantin Olchanski
7 Contents: JavaScript midas library for building custom pages
9\********************************************************************/
11// MIDAS type definitions from midas.h
74const TID_FLOAT64 = 10;
75const TID_BITFIELD = 11;
88const AT_EVALUATED = 3;
91const MT_ERROR = (1<<0);
92const MT_INFO = (1<<1);
93const MT_DEBUG = (1<<2);
94const MT_USER = (1<<3);
96const MT_TALK = (1<<5);
97const MT_CALL = (1<<6);
99const STATE_STOPPED = 1; /**< MIDAS run stopped */
100const STATE_PAUSED = 2; /**< MIDAS run paused */
101const STATE_RUNNING = 3; /**< MIDAS run running */
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;
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);
117/// \defgroup mjsonrpc_js JSON-RPC Javascript library (mjsonrpc_xxx)
119var mjsonrpc_default_url_web = "";
120var mjsonrpc_default_url_file = "https://localhost:8443/";
125if (window.location.protocol == 'file:') {
126 mjsonrpc_url = mjsonrpc_default_url_file;
128 mjsonrpc_url = mjsonrpc_default_url_web;
132function mjsonrpc_set_url(url)
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)
141function loadScript(src) {
142 return new Promise((resolve, reject) => {
143 let script = document.createElement('script');
146 script.onload = () => resolve(script);
147 script.onerror = () => reject(new Error(`Script load error for ${src}`));
149 document.head.appendChild(script);
153async function mjsonrpc_send_request(req)
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:
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
166 /// }).catch(function(error) {
167 /// mjsonrpc_error_alert(error);
171 /// @param[in] req request object or an array of request objects (object or array of objects)
172 /// @returns new Promise
174 //console.log("mjsonrpc_send_request!");
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';
182 xhr.responseType = 'text';
184 xhr.withCredentials = true;
186 xhr.onreadystatechange = function()
188 //alert("XHR: ready state " + xhr.readyState + " status " + xhr.status);
189 if (xhr.readyState == 4) {
191 if (xhr.status != 200) {
192 var error = new Object;
199 var contentType = xhr.getResponseHeader("Content-Type");
200 //console.log("XHR ContentType: " + contentType);
201 //console.log("XHR response type: " + typeof(xhr.response));
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);
209 } else if (contentType == "application/json") {
210 var rpc_response = null;
211 var xhr_response = xhr.response;
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);
220 rpc_response = JSON.parse(xhr_response);
222 throw "JSON parser returned null";
225 //alert("exception " + exc);
226 var error = new Object;
229 error.exception = exc;
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;
243 rpc.result = rpc_response[i].result;
251 if (rpc_response.error) {
252 var error = new Object;
255 error.error = rpc_response.error;
260 var rpc = new Object;
262 rpc.id = rpc_response.id;
263 rpc.result = rpc_response.result;
267 var error = new Object;
270 error.error = "Unexpected Content-Type: " + contentType;
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");
283 // special serialization for BigInt numbers
284 let j = JSON.stringify(req, (key, value) =>
285 typeof value === 'bigint' ? value.toString() : value
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()
299 if (Array.isArray(rpc)) {
300 //console.log("here!");
302 rpc.forEach(function(r) {
305 a += "method: \"" + r.request.method + "\", params: " + r.request.params + ", id: " + JSON.stringify(r.id) + ", error: " + JSON.stringify(r.error);
307 a += "method: \"" + r.request.method + "\", params: " + r.request.params + ", id: " + JSON.stringify(r.id) + ", response: " + JSON.stringify(r.result);
311 alert("mjsonrpc_debug_alert: array:\n" + a);
313 alert("mjsonrpc_debug_alert: method: \"" + rpc.request.method + "\", params: " + rpc.request.params + ", id: " + JSON.stringify(rpc.id) + ", response: " + JSON.stringify(rpc.result));
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)
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] + "]");
331 function is_network_error(xhr) {
332 return xhr.readyState==4 && xhr.status==0;
334 function is_http_error(xhr) {
335 return xhr.readyState==4 && xhr.status!=200;
337 function print_xhr(xhr) {
338 return "readyState: " + xhr.readyState + ", HTTP status: " + xhr.status + " (" + xhr.statusText + ")";
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);
350 return "method: \"" + request.method + "\", params: " + request.params + ", id: " + request.id;
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);
365 return "javascript exception: " + error;
369function mjsonrpc_error_alert(error, callback, param) {
370 /// \ingroup mjsonrpc_js
371 /// Handle all errors
372 /// @param[in] error rejected promise error object (object)
375 var s = mjsonrpc_decode_error(error);
376 dlgMessage("RPC Error", s, true, true, callback, param);
378 dlgMessage("Javascript exception or error", error, true, true, callback, param);
383function mjsonrpc_make_request(method, params, id)
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)
395 var req = new Object();
396 req.jsonrpc = "2.0"; // version
398 if (typeof params == 'string') {
399 req.params = JSON.parse(params);
404 req.params = null; // make sure we have "params", even if set to null or undefined
410function mjsonrpc_call(method, params, id)
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:
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
422 /// }).catch(function(error) {
423 /// mjsonrpc_error_alert(error);
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
431 var req = mjsonrpc_make_request(method, params, id);
432 return mjsonrpc_send_request(req);
435function mjsonrpc_start_program(name, id) {
436 /// \ingroup mjsonrpc_js
437 /// Start a MIDAS program
439 /// RPC method: "start_program"
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
448 /// }).catch(function(error) {
449 /// mjsonrpc_error_alert(error);
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
456 var req = new Object();
458 return mjsonrpc_call("start_program", req, id);
461function mjsonrpc_stop_program(name, id) {
462 /// \ingroup mjsonrpc_js
463 /// Stop a MIDAS program via cm_shutdown()
465 /// RPC method: "cm_shutdown"
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
474 /// }).catch(function(error) {
475 /// mjsonrpc_error_alert(error);
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
482 var req = new Object();
484 return mjsonrpc_call("cm_shutdown", req, id);
487function mjsonrpc_cm_exist(name, unique, id) {
488 /// \ingroup mjsonrpc_js
489 /// Check if a MIDAS program is running via cm_exist()
491 /// RPC method: "cm_exist"
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
500 /// // Some unexpected error happened
502 /// }).catch(function(error) {
503 /// mjsonrpc_error_alert(error);
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
512 var req = new Object();
515 return mjsonrpc_call("cm_exist", req, id);
518function mjsonrpc_al_reset_alarm(alarms, id) {
519 /// \ingroup mjsonrpc_js
522 /// RPC method: "al_reset_alarm"
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);
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
539 var req = new Object();
541 return mjsonrpc_call("al_reset_alarm", req, id);
544function mjsonrpc_al_trigger_alarm(name, message, xclass, condition, type, id) {
545 /// \ingroup mjsonrpc_js
548 /// RPC method: "al_reset_alarm"
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);
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
565 var req = new Object();
567 req.message = message;
569 req.condition = condition;
571 return mjsonrpc_call("al_trigger_alarm", req, id);
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.
578 /// Instead of this function, please use db_get_values() as a simple way to get easy to use ODB values.
580 /// RPC method: "db_copy"
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);
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
599 var req = new Object();
601 return mjsonrpc_call("db_copy", req, id);
604function mjsonrpc_db_get_values(paths, id) {
605 /// \ingroup mjsonrpc_js
606 /// Get values of ODB variables
608 /// RPC method: "db_get_values"
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);
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
631 var req = new Object();
633 return mjsonrpc_call("db_get_values", req, id);
636function mjsonrpc_db_get_value(paths, id) {
637 /// \ingroup mjsonrpc_js
638 /// Get values of ODB variables
640 /// RPC method: "db_get_value"
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);
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
663 let req = new Object();
665 return mjsonrpc_call("db_get_values", req, id);
668function db_get_value(path, callback) {
669 if (!Array.isArray(path))
672 let req = new Object();
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));
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().
684 /// RPC method: "db_ls"
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);
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
703 var req = new Object();
705 return mjsonrpc_call("db_ls", req, id);
708function mjsonrpc_db_resize(paths, new_lengths, id) {
709 /// \ingroup mjsonrpc_js
710 /// Change size of ODB arrays
712 /// RPC method: "db_resize"
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);
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
730 var req = new Object();
732 req.new_lengths = new_lengths;
733 return mjsonrpc_call("db_resize", req, id);
736function mjsonrpc_db_key(paths, id) {
737 /// \ingroup mjsonrpc_js
740 /// RPC method: "db_key"
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);
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
757 var req = new Object();
759 return mjsonrpc_call("db_key", req, id);
762function mjsonrpc_db_delete(paths, id) {
763 /// \ingroup mjsonrpc_js
764 /// Delete ODB entries
766 /// RPC method: "db_delete"
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);
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
783 var req = new Object();
785 return mjsonrpc_call("db_delete", req, id);
788function mjsonrpc_db_paste(paths, values, id) {
789 /// \ingroup mjsonrpc_js
790 /// Write values info ODB.
792 /// RPC method: "db_paste"
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);
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
810 var req = new Object();
813 return mjsonrpc_call("db_paste", req, id);
816function mjsonrpc_db_set_value(path, value, id) {
817 /// \ingroup mjsonrpc_js
818 /// Write value info ODB.
820 /// RPC method: "db_set_value"
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);
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
838 var req = new Object();
840 req.values = [value];
841 return mjsonrpc_call("db_paste", req, id);
844function mjsonrpc_db_create(paths, id) {
845 /// \ingroup mjsonrpc_js
846 /// Create ODB entries
848 /// RPC method: "db_create"
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
858 return mjsonrpc_call("db_create", paths, id);
861function mjsonrpc_cm_msg(message, type, id) {
862 /// \ingroup mjsonrpc_js
863 /// Get values of ODB variables
865 /// RPC method: "cm_msg1"
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()
873 /// }).catch(function(error) {
874 /// mjsonrpc_error_alert(error);
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
882 var req = new Object();
883 req.message = message;
886 return mjsonrpc_call("cm_msg1", req, id);
889function mjsonrpc_get_timezone() {
890 /// Get timezone offset of server in hours
892 /// RPC method: "get_timezone"
895 /// mjsonrpc_get_timezone().then(function(rpc) {
896 /// var req = rpc.request; // reference to the rpc request
897 /// var tz = rpc.result; // server timezone
899 /// }).catch(function(error) {
900 /// mjsonrpc_error_alert(error);
903 /// @returns new Promise
905 var req = new Object();
906 return mjsonrpc_call("get_timezone", req, 0);
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).
914 if (Array.isArray(path)) {
915 mjsonrpc_db_paste(path,value).then(function(rpc) {}).catch(function(error) {
916 mjsonrpc_error_alert(error); });
918 mjsonrpc_db_paste([path],[value]).then(function(rpc) {}).catch(function(error) {
919 mjsonrpc_error_alert(error); });
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:
931 /// e.event_id <-- elements of midas event header
932 /// e.trigger_mask <-/
933 /// e.serial_number <-/
935 /// e.time_stamp_date<-/
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
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)
950 /// This function is used by the event_dump.html page and can be used in a custom
951 /// page for single event displays.
957 if (!array || typeof array.byteLength !== "number" || array.byteLength % 4 !== 0)
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
965 if (array.byteLength < event_header_size)
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];
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)
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);
988 if (!e.banks_16bit && !e.banks_32bit && !e.banks_32bita)
991 let i8 = event_header_size + bank_header_size;
993 //console.log("AAA bank type: " + e.banks_16bit + e.banks_32bit + e.banks_32bita);
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)
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];
1008 b.type = data32[i8/4 + 1];
1009 b.size = data32[i8/4 + 2];
1011 i8 += bank_data_header_size;
1013 if (b.type >= tid_name.length)
1018 if (b.type === TID_INT8) {
1019 } else if (b.type === TID_UINT8) {
1020 } else if (b.type === TID_INT16) {
1022 } else if (b.type === TID_UINT16) {
1024 } else if (b.type === TID_INT32) {
1026 } else if (b.type === TID_UINT32) {
1028 } else if (b.type === TID_INT64) {
1030 } else if (b.type === TID_UINT64) {
1032 } else if (b.type === TID_FLOAT) {
1034 } else if (b.type === TID_DOUBLE) {
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)
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);
1049 b.data = array.slice(i8, i8+b.size);
1052 //if (e.banks_32bit) {
1053 // let pad = align8(b.size) - b.size;
1058 b.hexdata = new Uint8Array(b.data);
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);
1081 b.array = "Unknown data type " + b.type;
1096 * js-indent-level: 3
1097 * indent-tabs-mode: nil