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, unique, 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] unique bUnique argument to cm_shutdown() (bool)
480 /// @param[in] id optional request id (see JSON-RPC specs) (object)
481 /// @returns new Promise
482
483 var req = new Object();
484 req.name = name;
485 req.unique = unique;
486 return mjsonrpc_call("cm_shutdown", req, id);
487}
488
489function mjsonrpc_cm_exist(name, unique, id) {
490 /// \ingroup mjsonrpc_js
491 /// Stop a MIDAS program via cm_exist()
492 ///
493 /// RPC method: "cm_exist"
494 ///
495 /// @param[in] name Name of program to stop (string)
496 /// @param[in] unique bUnique argument to cm_shutdown() (bool)
497 /// @param[in] id optional request id (see JSON-RPC specs) (object)
498 var req = new Object();
499 req.name = name;
500 req.unique = unique;
501 return mjsonrpc_call("cm_exist", req, id);
502}
503
504function mjsonrpc_al_reset_alarm(alarms, id) {
505 /// \ingroup mjsonrpc_js
506 /// Reset alarms
507 ///
508 /// RPC method: "al_reset_alarm"
509 ///
510 /// \code
511 /// mjsonrpc_al_reset_alarm(["alarm1", "alarm2"]).then(function(rpc) {
512 /// var req = rpc.request; // reference to the rpc request
513 /// var id = rpc.id; // rpc response id (should be same as req.id)
514 /// var result = rpc.result; // rpc response result
515 /// ... result.status[0]; // status of al_reset_alarm() for 1st alarm
516 /// ... result.status[1]; // status of al_reset_alarm() for 2nd alarm
517 /// }).catch(function(error) {
518 /// mjsonrpc_error_alert(error);
519 /// });
520 /// \endcode
521 /// @param[in] alarms Array of alarm names (array of strings)
522 /// @param[in] id optional request id (see JSON-RPC specs) (object)
523 /// @returns new Promise
524 ///
525 var req = new Object();
526 req.alarms = alarms;
527 return mjsonrpc_call("al_reset_alarm", req, id);
528}
529
530function mjsonrpc_al_trigger_alarm(name, message, xclass, condition, type, id) {
531 /// \ingroup mjsonrpc_js
532 /// Reset alarms
533 ///
534 /// RPC method: "al_reset_alarm"
535 ///
536 /// \code
537 /// mjsonrpc_al_reset_alarm(["alarm1", "alarm2"]).then(function(rpc) {
538 /// var req = rpc.request; // reference to the rpc request
539 /// var id = rpc.id; // rpc response id (should be same as req.id)
540 /// var result = rpc.result; // rpc response result
541 /// ... result.status[0]; // status of al_reset_alarm() for 1st alarm
542 /// ... result.status[1]; // status of al_reset_alarm() for 2nd alarm
543 /// }).catch(function(error) {
544 /// mjsonrpc_error_alert(error);
545 /// });
546 /// \endcode
547 /// @param[in] alarms Array of alarm names (array of strings)
548 /// @param[in] id optional request id (see JSON-RPC specs) (object)
549 /// @returns new Promise
550 ///
551 var req = new Object();
552 req.name = name;
553 req.message = message;
554 req.class = xclass;
555 req.condition = condition;
556 req.type = type;
557 return mjsonrpc_call("al_trigger_alarm", req, id);
558}
559
560function mjsonrpc_db_copy(paths, id) {
561 /// \ingroup mjsonrpc_js
562 /// Get a copy of ODB. Symlinks are not resolved, ODB path names are not converted to lower-case.
563 ///
564 /// Instead of this function, please use db_get_values() as a simple way to get easy to use ODB values.
565 ///
566 /// RPC method: "db_copy"
567 ///
568 /// \code
569 /// mjsonrpc_db_copy(["/runinfo", "/equipment/foo"]).then(function(rpc) {
570 /// var req = rpc.request; // reference to the rpc request
571 /// var id = rpc.id; // rpc response id (should be same as req.id)
572 /// var result = rpc.result; // rpc response result
573 /// ... result.status[0]; // status of db_get_value() for /runinfo
574 /// ... result.status[1]; // status of db_get_value() for /equipment
575 /// var runinfo = result.data[0]; // javascript object representing the ODB runinfo structure
576 /// var equipment = result.data[1]; // javascript object representing /equipment/foo
577 /// }).catch(function(error) {
578 /// mjsonrpc_error_alert(error);
579 /// });
580 /// \endcode
581 /// @param[in] paths Array of ODB paths (array of strings)
582 /// @param[in] id optional request id (see JSON-RPC specs) (object)
583 /// @returns new Promise
584 ///
585 var req = new Object();
586 req.paths = paths;
587 return mjsonrpc_call("db_copy", req, id);
588}
589
590function mjsonrpc_db_get_values(paths, id) {
591 /// \ingroup mjsonrpc_js
592 /// Get values of ODB variables
593 ///
594 /// RPC method: "db_get_values"
595 ///
596 /// \code
597 /// mjsonrpc_db_get_values(["/runinfo", "/equipment"]).then(function(rpc) {
598 /// var req = rpc.request; // reference to the rpc request
599 /// var id = rpc.id; // rpc response id (should be same as req.id)
600 /// var result = rpc.result; // rpc response result
601 /// ... result.status[0]; // status of db_get_value() for /runinfo
602 /// ... result.status[1]; // status of db_get_value() for /equipment
603 /// ... result.last_written[0]; // "last written" timestamp for /runinfo
604 /// ... result.last_written[1]; // "last written" timestamp for /equipment
605 /// var runinfo = result.data[0]; // javascript object representing the ODB runinfo structure
606 /// ... runinfo["run number"]; // access the run number, note: all ODB names should be in lower-case.
607 /// ... runinfo["run number/last_written"]; // "last_written" timestamp for the run number
608 /// ... result.data[1].foo.variables.bar; // access /equipment/foo/variables/bar
609 /// }).catch(function(error) {
610 /// mjsonrpc_error_alert(error);
611 /// });
612 /// \endcode
613 /// @param[in] paths Array of ODB paths (array of strings)
614 /// @param[in] id optional request id (see JSON-RPC specs) (object)
615 /// @returns new Promise
616 ///
617 var req = new Object();
618 req.paths = paths;
619 return mjsonrpc_call("db_get_values", req, id);
620}
621
622function mjsonrpc_db_get_value(paths, id) {
623 /// \ingroup mjsonrpc_js
624 /// Get values of ODB variables
625 ///
626 /// RPC method: "db_get_value"
627 ///
628 /// \code
629 /// mjsonrpc_db_get_value("/runinfo").then(function(rpc) {
630 /// var req = rpc.request; // reference to the rpc request
631 /// var id = rpc.id; // rpc response id (should be same as req.id)
632 /// var result = rpc.result; // rpc response result
633 /// ... result.status[0]; // status of db_get_value() for /runinfo
634 /// ... result.status[1]; // status of db_get_value() for /equipment
635 /// ... result.last_written[0]; // "last written" timestamp for /runinfo
636 /// ... result.last_written[1]; // "last written" timestamp for /equipment
637 /// var runinfo = result.data[0]; // javascript object representing the ODB runinfo structure
638 /// ... runinfo["run number"]; // access the run number, note: all ODB names should be in lower-case.
639 /// ... runinfo["run number/last_written"]; // "last_written" timestamp for the run number
640 /// ... result.data[1].foo.variables.bar; // access /equipment/foo/variables/bar
641 /// }).catch(function(error) {
642 /// mjsonrpc_error_alert(error);
643 /// });
644 /// \endcode
645 /// @param[in] paths Array of ODB paths (array of strings)
646 /// @param[in] id optional request id (see JSON-RPC specs) (object)
647 /// @returns new Promise
648 ///
649 let req = new Object();
650 req.paths = [paths];
651 return mjsonrpc_call("db_get_values", req, id);
652}
653
654function db_get_value(path, callback) {
655 if (!Array.isArray(path))
656 path = [path];
657
658 let req = new Object();
659 req.paths = path;
660 req.omit_names = true;
661 req.omit_last_written = true;
662 mjsonrpc_call("db_get_values", req).then(rpc => callback(rpc))
663 .catch(error => mjsonrpc_error_alert(error));
664}
665
666function mjsonrpc_db_ls(paths, id) {
667 /// \ingroup mjsonrpc_js
668 /// Get list of contents of an ODB subdirectory, similar to odbedit command "ls -l". To get values of ODB variables, use db_get_values().
669 ///
670 /// RPC method: "db_ls"
671 ///
672 /// \code
673 /// mjsonrpc_db_ls(["/alarms/alarms", "/equipment"]).then(function(rpc) {
674 /// var req = rpc.request; // reference to the rpc request
675 /// var id = rpc.id; // rpc response id (should be same as req.id)
676 /// var result = rpc.result; // rpc response result
677 /// ... result.status[0]; // status of db_copy_json_ls() for /alarms/alarms
678 /// ... result.status[1]; // status of db_copy_json_ls() for /equipment
679 /// var alarms = result.data[0]; // javascript object representing the contents of ODB /alarms/alarms
680 /// var equipment = result.data[1]; // javascript object representing the contents of ODB /equipment
681 /// }).catch(function(error) {
682 /// mjsonrpc_error_alert(error);
683 /// });
684 /// \endcode
685 /// @param[in] paths Array of ODB paths (array of strings)
686 /// @param[in] id optional request id (see JSON-RPC specs) (object)
687 /// @returns new Promise
688 ///
689 var req = new Object();
690 req.paths = paths;
691 return mjsonrpc_call("db_ls", req, id);
692}
693
694function mjsonrpc_db_resize(paths, new_lengths, id) {
695 /// \ingroup mjsonrpc_js
696 /// Change size of ODB arrays
697 ///
698 /// RPC method: "db_resize"
699 ///
700 /// \code
701 /// mjsonrpc_db_resize(["/test/intarray1", "/test/dblarray2"], [10, 20]).then(function(rpc) {
702 /// var req = rpc.request; // reference to the rpc request
703 /// var id = rpc.id; // rpc response id (should be same as req.id)
704 /// var result = rpc.result; // rpc response result
705 /// ... result.status[0]; // status of db_set_num_values() for 1st path
706 /// ... result.status[1]; // status of db_set_num_values() for 2nd path
707 /// }).catch(function(error) {
708 /// mjsonrpc_error_alert(error);
709 /// });
710 /// \endcode
711 /// @param[in] paths Array of ODB paths (array of strings)
712 /// @param[in] new_sizes Array of new sizes for each path (array of ints)
713 /// @param[in] id optional request id (see JSON-RPC specs) (object)
714 /// @returns new Promise
715 ///
716 var req = new Object();
717 req.paths = paths;
718 req.new_lengths = new_lengths;
719 return mjsonrpc_call("db_resize", req, id);
720}
721
722function mjsonrpc_db_key(paths, id) {
723 /// \ingroup mjsonrpc_js
724 /// Get ODB keys
725 ///
726 /// RPC method: "db_key"
727 ///
728 /// \code
729 /// mjsonrpc_db_key(["/test/intarray1", "/test/dblarray2"]).then(function(rpc) {
730 /// var req = rpc.request; // reference to the rpc request
731 /// var id = rpc.id; // rpc response id (should be same as req.id)
732 /// var result = rpc.result; // rpc response result
733 /// ... result.status[0]; // status of db_get_key() for 1st path
734 /// ... result.status[1]; // status of db_get_key() for 2nd path
735 /// }).catch(function(error) {
736 /// mjsonrpc_error_alert(error);
737 /// });
738 /// \endcode
739 /// @param[in] paths Array of ODB paths (array of strings)
740 /// @param[in] id optional request id (see JSON-RPC specs) (object)
741 /// @returns new Promise
742 ///
743 var req = new Object();
744 req.paths = paths;
745 return mjsonrpc_call("db_key", req, id);
746}
747
748function mjsonrpc_db_delete(paths, id) {
749 /// \ingroup mjsonrpc_js
750 /// Delete ODB entries
751 ///
752 /// RPC method: "db_delete"
753 ///
754 /// \code
755 /// mjsonrpc_db_delete(["/test/test1", "/test/test2"]).then(function(rpc) {
756 /// var req = rpc.request; // reference to the rpc request
757 /// var id = rpc.id; // rpc response id (should be same as req.id)
758 /// var result = rpc.result; // rpc response result
759 /// ... result.status[0]; // status of db_delete() for 1st path
760 /// ... result.status[1]; // status of db_delete() for 2nd path
761 /// }).catch(function(error) {
762 /// mjsonrpc_error_alert(error);
763 /// });
764 /// \endcode
765 /// @param[in] paths Array of ODB paths (array of strings)
766 /// @param[in] id optional request id (see JSON-RPC specs) (object)
767 /// @returns new Promise
768 ///
769 var req = new Object();
770 req.paths = paths;
771 return mjsonrpc_call("db_delete", req, id);
772}
773
774function mjsonrpc_db_paste(paths, values, id) {
775 /// \ingroup mjsonrpc_js
776 /// Write values info ODB.
777 ///
778 /// RPC method: "db_paste"
779 ///
780 /// \code
781 /// mjsonrpc_db_paste(["/runinfo/run number", "/equipment/foo/settings/bar"], [123,456]).then(function(rpc) {
782 /// var req = rpc.request; // reference to the rpc request
783 /// var id = rpc.id; // rpc response id (should be same as req.id)
784 /// var result = rpc.result; // rpc response result
785 /// ... result.status[0]; // status of db_set_value() for /runinfo
786 /// ... result.status[1]; // status of db_set_value() for /equipment
787 /// }).catch(function(error) {
788 /// mjsonrpc_error_alert(error);
789 /// });
790 /// \endcode
791 /// @param[in] paths Array of ODB paths (array of strings)
792 /// @param[in] values Array of ODB values (array of anything)
793 /// @param[in] id optional request id (see JSON-RPC specs) (object)
794 /// @returns new Promise
795 ///
796 var req = new Object();
797 req.paths = paths;
798 req.values = values;
799 return mjsonrpc_call("db_paste", req, id);
800}
801
802function mjsonrpc_db_set_value(path, value, id) {
803 /// \ingroup mjsonrpc_js
804 /// Write value info ODB.
805 ///
806 /// RPC method: "db_set_value"
807 ///
808 /// \code
809 /// mjsonrpc_set_value("runinfo/run number", 123).then(function(rpc) {
810 /// var req = rpc.request; // reference to the rpc request
811 /// var id = rpc.id; // rpc response id (should be same as req.id)
812 /// var result = rpc.result; // rpc response result
813 /// ... result.status[0]; // status of db_set_value() for /runinfo
814 /// ... result.status[1]; // status of db_set_value() for /equipment
815 /// }).catch(function(error) {
816 /// mjsonrpc_error_alert(error);
817 /// });
818 /// \endcode
819 /// @param[in] paths Array of ODB paths (array of strings)
820 /// @param[in] values Array of ODB values (array of anything)
821 /// @param[in] id optional request id (see JSON-RPC specs) (object)
822 /// @returns new Promise
823 ///
824 var req = new Object();
825 req.paths = [path];
826 req.values = [value];
827 return mjsonrpc_call("db_paste", req, id);
828}
829
830function mjsonrpc_db_create(paths, id) {
831 /// \ingroup mjsonrpc_js
832 /// Create ODB entries
833 ///
834 /// RPC method: "db_create"
835 ///
836 /// @param[in] paths Array of ODB entries to create (array of objects)
837 /// @param[in] paths[i].path ODB path name to create (string)
838 /// @param[in] paths[i].type TID_xxx data type (integer)
839 /// @param[in] paths[i].array_length Optional array length (default is 1) (integer)
840 /// @param[in] paths[i].string_length Optional string length (default is NAME_LENGTH) (integer)
841 /// @param[in] id optional request id (see JSON-RPC specs) (object)
842 /// @returns new Promise
843
844 return mjsonrpc_call("db_create", paths, id);
845}
846
847function mjsonrpc_cm_msg(message, type, id) {
848 /// \ingroup mjsonrpc_js
849 /// Get values of ODB variables
850 ///
851 /// RPC method: "cm_msg1"
852 ///
853 /// \code
854 /// mjsonrpc_cm_msg("this is a new message").then(function(rpc) {
855 /// var req = rpc.request; // reference to the rpc request
856 /// var id = rpc.id; // rpc response id (should be same as req.id)
857 /// var status = rpc.result.status; // return status of MIDAS cm_msg1()
858 /// ...
859 /// }).catch(function(error) {
860 /// mjsonrpc_error_alert(error);
861 /// });
862 /// \endcode
863 /// @param[in] message Text of midas message (string)
864 /// @param[in] type optional message type, one of MT_xxx. Default is MT_INFO (integer)
865 /// @param[in] id optional request id (see JSON-RPC specs) (object)
866 /// @returns new Promise
867 ///
868 var req = new Object();
869 req.message = message;
870 if (type)
871 req.type = type;
872 return mjsonrpc_call("cm_msg1", req, id);
873}
874
875function mjsonrpc_get_timezone() {
876 /// Get timezone offset of server in hours
877 ///
878 /// RPC method: "get_timezone"
879 ///
880 /// \code
881 /// mjsonrpc_get_timezone().then(function(rpc) {
882 /// var req = rpc.request; // reference to the rpc request
883 /// var tz = rpc.result; // server timezone
884 /// ...
885 /// }).catch(function(error) {
886 /// mjsonrpc_error_alert(error);
887 /// });
888 /// \endcode
889 /// @returns new Promise
890 ///
891 var req = new Object();
892 return mjsonrpc_call("get_timezone", req, 0);
893}
894
895function modbset(path, value)
896 /// \ingroup mjsonrpc_js
897 /// 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).
898 ///
899{
900 if (Array.isArray(path)) {
901 mjsonrpc_db_paste(path,value).then(function(rpc) {}).catch(function(error) {
902 mjsonrpc_error_alert(error); });
903 } else {
904 mjsonrpc_db_paste([path],[value]).then(function(rpc) {}).catch(function(error) {
905 mjsonrpc_error_alert(error); });
906 }
907}
908
909function align8(x) {
910 return ((x+7) & ~7);
911}
912
913function bkToObj(array) {
914 /// Midas banks-to-object: Parses a raw midas even received via the new bm_receive_event
915 /// call and converts it into an JS object of with following elements and returns it:
916 ///
917 /// e.event_id <-- elements of midas event header
918 /// e.trigger_mask <-/
919 /// e.serial_number <-/
920 /// e.time_stamp <-/
921 /// e.time_stamp_date<-/
922 /// e.data_size <-/
923 ///
924 /// e.banks_16bit <-- true if we have 16-bit banks
925 /// e.banks_32bit <-- true if we have 32-bit banks
926 /// e.banks_32bita <-- true if we have 64-bit aligned 32-bit banks
927
928
929 /// e.bank[] <-- array of banks
930 /// .name <-- name of bank
931 /// .type <-- bank type, one of TID_xxx
932 /// .size <-- bank size in bytes
933 /// .hexdata[] <-- array of raw (byte) data
934 /// .array[] <-- array of converted data (UINT16, UINT32, UINT32, INT32, FLOAT, DOUBLE)
935 ///
936 /// This function is used by the event_dump.html page and can be used in a custom
937 /// page for single event displays.
938
939 let e = {};
940
941 let data8 = new Uint8Array(array);
942 let data16 = new Uint16Array(array);
943 let data32 = new Uint32Array(array);
944
945 // decode event header
946 e.event_id = data16[0];
947 e.trigger_mask = data16[1];
948 e.serial_number = data32[1];
949 e.time_stamp = data32[2];
950 e.time_stamp_date = new Date(e.time_stamp*1000);
951 e.data_size = data32[3];
952 e.bank = [];
953 let event_header_size = 16; // bytes
954
955 // decode banks size and type
956 e.bank_total_size = data32[4];
957 e.bank_flags = data32[5];
958 e.banks_16bit = (e.bank_flags === 0x01);
959 e.banks_32bit = (e.bank_flags === 0x11);
960 e.banks_32bita = (e.bank_flags === 0x31);
961 let bank_header_size = 8;
962
963 let i8 = event_header_size + bank_header_size;
964
965 //console.log("AAA bank type: " + e.banks_16bit + e.banks_32bit + e.banks_32bita);
966
967 // iterate over banks
968 while(i8 < e.data_size + event_header_size) {
969 let b = {};
970 b.name = String.fromCharCode(data8[i8], data8[i8 + 1], data8[i8 + 2], data8[i8 + 3]);
971 if (e.banks_16bit) {
972 b.type = data16[i8/2 + 2];
973 b.size = data16[i8/2 + 3];
974 i8 += 8;
975 } else if (e.banks_32bit) {
976 b.type = data32[i8/4 + 1];
977 b.size = data32[i8/4 + 2];
978 i8 += 12;
979 } else if (e.banks_32bita) {
980 b.type = data32[i8/4 + 1];
981 b.size = data32[i8/4 + 2];
982 i8 += 16;
983 }
984 if (b.type >= tid_name.length)
985 b.type = 0;
986
987 let size_align = 1;
988
989 if (b.type === TID_INT8) {
990 } else if (b.type === TID_UINT8) {
991 } else if (b.type === TID_INT16) {
992 size_align = 2;
993 } else if (b.type === TID_UINT16) {
994 size_align = 2;
995 } else if (b.type === TID_INT32) {
996 size_align = 4;
997 } else if (b.type === TID_UINT32) {
998 size_align = 4;
999 } else if (b.type === TID_INT64) {
1000 size_align = 8;
1001 } else if (b.type === TID_UINT64) {
1002 size_align = 8;
1003 } else if (b.type === TID_FLOAT) {
1004 size_align = 4;
1005 } else if (b.type === TID_DOUBLE) {
1006 size_align = 8;
1007 } else {
1008 }
1009
1010 let aligned_size = align8(b.size);
1011
1012 if (b.size % size_align != 0) {
1013 //console.log("b.size: " + b.size + " misalign: " + b.size % size_align);
1014 b.size -= (b.size % size_align);
1015 }
1016
1017 b.data = array.slice(i8, i8+b.size);
1018 i8 += aligned_size;
1019
1020 //if (e.banks_32bit) {
1021 // let pad = align8(b.size) - b.size;
1022 // i8 += pad;
1023 //} else
1024 // i8 = align8(i8);
1025
1026 b.hexdata = new Uint8Array(b.data);
1027
1028 if (b.type === TID_INT8)
1029 b.array = new Int8Array(b.data);
1030 else if (b.type === TID_UINT8)
1031 b.array = new Uint8Array(b.data);
1032 else if (b.type === TID_INT16)
1033 b.array = new Int16Array(b.data);
1034 else if (b.type === TID_UINT16)
1035 b.array = new Uint16Array(b.data);
1036 else if (b.type === TID_INT32)
1037 b.array = new Int32Array(b.data);
1038 else if (b.type === TID_UINT32)
1039 b.array = new Uint32Array(b.data);
1040 else if (b.type === TID_INT64)
1041 b.array = new BigInt64Array(b.data);
1042 else if (b.type === TID_UINT64)
1043 b.array = new BigUint64Array(b.data);
1044 else if (b.type === TID_FLOAT)
1045 b.array = new Float32Array(b.data);
1046 else if (b.type === TID_DOUBLE)
1047 b.array = new Float64Array(b.data);
1048 else
1049 b.array = "Unknown data type " + b.type;
1050
1051 e.bank.push(b);
1052 }
1053
1054 return e;
1055}
1056
1057/* emacs
1058 * Local Variables:
1059 * tab-width: 8
1060 * c-basic-offset: 3
1061 * js-indent-level: 3
1062 * indent-tabs-mode: nil
1063 * End:
1064 */