243 </xsl:for-each> |
247 </xsl:for-each> |
244 <xsl:text>} |
248 <xsl:text>} |
245 </xsl:text> |
249 </xsl:text> |
246 <xsl:text> |
250 <xsl:text> |
247 </xsl:text> |
251 </xsl:text> |
248 <xsl:text>var hmi_index = [ |
252 <xsl:text>var hmitree_types = [ |
249 </xsl:text> |
253 </xsl:text> |
250 <xsl:variable name="svg" select="/"/> |
|
251 <xsl:for-each select="$indexed_hmitree/*"> |
254 <xsl:for-each select="$indexed_hmitree/*"> |
252 <xsl:text>{ /* </xsl:text> |
255 <xsl:text>/* </xsl:text> |
253 <xsl:value-of select="@index"/> |
256 <xsl:value-of select="@index"/> |
254 <xsl:text> </xsl:text> |
257 <xsl:text> </xsl:text> |
255 <xsl:value-of select="@hmipath"/> |
258 <xsl:value-of select="@hmipath"/> |
256 <xsl:text> */ |
259 <xsl:text> */ "</xsl:text> |
257 </xsl:text> |
260 <xsl:value-of select="substring(local-name(), 5)"/> |
258 <xsl:text> type: "</xsl:text> |
261 <xsl:text>"</xsl:text> |
259 <xsl:value-of select="local-name()"/> |
|
260 <xsl:text>", |
|
261 </xsl:text> |
|
262 <xsl:text> ids: [ |
|
263 </xsl:text> |
|
264 <xsl:variable name="hmipath" select="@hmipath"/> |
|
265 <xsl:for-each select="$svg//*[substring-after(@inkscape:label,'@') = $hmipath]"> |
|
266 <xsl:text> hmi_widgets["</xsl:text> |
|
267 <xsl:value-of select="@id"/> |
|
268 <xsl:text>"]</xsl:text> |
|
269 <xsl:if test="position()!=last()"> |
|
270 <xsl:text>,</xsl:text> |
|
271 </xsl:if> |
|
272 <xsl:text> |
|
273 </xsl:text> |
|
274 </xsl:for-each> |
|
275 <xsl:text> ] |
|
276 </xsl:text> |
|
277 <xsl:text>}</xsl:text> |
|
278 <xsl:if test="position()!=last()"> |
262 <xsl:if test="position()!=last()"> |
279 <xsl:text>,</xsl:text> |
263 <xsl:text>,</xsl:text> |
280 </xsl:if> |
264 </xsl:if> |
281 <xsl:text> |
265 <xsl:text> |
282 </xsl:text> |
266 </xsl:text> |
350 </xsl:text> |
315 </xsl:text> |
351 <xsl:text>// svghmi.js |
316 <xsl:text>// svghmi.js |
352 </xsl:text> |
317 </xsl:text> |
353 <xsl:text> |
318 <xsl:text> |
354 </xsl:text> |
319 </xsl:text> |
355 <xsl:text>(function(){ |
320 <xsl:text>function dispatch_value(index, value) { |
356 </xsl:text> |
321 </xsl:text> |
357 <xsl:text> // Open WebSocket to relative "/ws" address |
322 <xsl:text> console.log("dispatch_value("+index+value+")"); |
358 </xsl:text> |
323 </xsl:text> |
359 <xsl:text> var ws = new WebSocket(window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws')); |
324 <xsl:text>}; |
360 </xsl:text> |
325 </xsl:text> |
361 <xsl:text> |
326 <xsl:text> |
362 </xsl:text> |
327 </xsl:text> |
363 <xsl:text> // Register message reception handler |
328 <xsl:text>// Open WebSocket to relative "/ws" address |
364 </xsl:text> |
329 </xsl:text> |
365 <xsl:text> ws.onmessage = function (evt) { |
330 <xsl:text>var ws = new WebSocket(window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws')); |
366 </xsl:text> |
331 </xsl:text> |
367 <xsl:text> // TODO : dispatch and cache hmi tree updates |
332 <xsl:text>ws.binaryType = 'arraybuffer'; |
368 </xsl:text> |
333 </xsl:text> |
369 <xsl:text> |
334 <xsl:text> |
370 </xsl:text> |
335 </xsl:text> |
371 <xsl:text> var received_msg = evt.data; |
336 <xsl:text>const dvgetters = { |
372 </xsl:text> |
337 </xsl:text> |
373 <xsl:text> // TODO : check for hmitree hash header |
338 <xsl:text> INT: [DataView.prototype.getInt16, 2], |
374 </xsl:text> |
339 </xsl:text> |
375 <xsl:text> // if not matching, reload page |
340 <xsl:text> BOOL: [DataView.prototype.getInt8, 1] |
376 </xsl:text> |
341 </xsl:text> |
377 <xsl:text> alert("Message is received..."+received_msg); |
342 <xsl:text> /* TODO */ |
|
343 </xsl:text> |
|
344 <xsl:text>}; |
|
345 </xsl:text> |
|
346 <xsl:text> |
|
347 </xsl:text> |
|
348 <xsl:text>// Register message reception handler |
|
349 </xsl:text> |
|
350 <xsl:text>ws.onmessage = function (evt) { |
|
351 </xsl:text> |
|
352 <xsl:text> |
|
353 </xsl:text> |
|
354 <xsl:text> let data = evt.data; |
|
355 </xsl:text> |
|
356 <xsl:text> let dv = new DataView(data); |
|
357 </xsl:text> |
|
358 <xsl:text> let i = 0; |
|
359 </xsl:text> |
|
360 <xsl:text> for(let hash_int of hmi_hash) { |
|
361 </xsl:text> |
|
362 <xsl:text> if(hash_int != dv.getUint8(i)){ |
|
363 </xsl:text> |
|
364 <xsl:text> console.log("Recv non maching hash. Reload."); |
|
365 </xsl:text> |
|
366 <xsl:text> |
|
367 </xsl:text> |
|
368 <xsl:text> // 1003 is for "Unsupported Data" |
|
369 </xsl:text> |
|
370 <xsl:text> ws.close(1003,"Hash doesn't match"); |
|
371 </xsl:text> |
|
372 <xsl:text> |
|
373 </xsl:text> |
|
374 <xsl:text> // TODO : remove debug alert ? |
|
375 </xsl:text> |
|
376 <xsl:text> alert("HMI will be reloaded."); |
|
377 </xsl:text> |
|
378 <xsl:text> |
|
379 </xsl:text> |
|
380 <xsl:text> // force reload ignoring cache |
|
381 </xsl:text> |
|
382 <xsl:text> location.reload(true); |
|
383 </xsl:text> |
|
384 <xsl:text> }; |
|
385 </xsl:text> |
|
386 <xsl:text> i++; |
378 </xsl:text> |
387 </xsl:text> |
379 <xsl:text> }; |
388 <xsl:text> }; |
380 </xsl:text> |
389 </xsl:text> |
381 <xsl:text> |
390 <xsl:text> |
382 </xsl:text> |
391 </xsl:text> |
383 <xsl:text> // Once connection established |
392 <xsl:text> while(i < data.length){ |
384 </xsl:text> |
393 </xsl:text> |
385 <xsl:text> ws.onopen = function (evt) { |
394 <xsl:text> let index = dv.getUint32(i); |
386 </xsl:text> |
395 </xsl:text> |
387 <xsl:text> // TODO : enable the HMI (was previously offline, or just starts) |
396 <xsl:text> i += 4; |
388 </xsl:text> |
397 </xsl:text> |
389 <xsl:text> // show main page |
398 <xsl:text> let iectype = hmitree_types[index]; |
390 </xsl:text> |
399 </xsl:text> |
391 <xsl:text> |
400 <xsl:text> let [dvgetter, bytesize] = dvgetters[iectypes]; |
392 </xsl:text> |
401 </xsl:text> |
393 <xsl:text> |
402 <xsl:text> value = dvgetter.call(dv,i); |
394 </xsl:text> |
403 </xsl:text> |
395 <xsl:text> // TODO : prefix with hmitree hash header |
404 <xsl:text> dispatch_value(index, value); |
396 </xsl:text> |
405 </xsl:text> |
397 <xsl:text> ws.send("test"); |
406 <xsl:text> i += bytesize; |
398 </xsl:text> |
407 </xsl:text> |
399 <xsl:text> }; |
408 <xsl:text> }; |
400 </xsl:text> |
409 </xsl:text> |
401 <xsl:text> |
410 <xsl:text>}; |
402 </xsl:text> |
411 </xsl:text> |
403 <xsl:text> var pending_updates = {}; |
412 <xsl:text> |
404 </xsl:text> |
413 </xsl:text> |
405 <xsl:text> |
414 <xsl:text> |
406 </xsl:text> |
415 </xsl:text> |
407 <xsl:text> // subscription state, as it should be in hmi server |
416 <xsl:text>function send_blob(data) { |
408 </xsl:text> |
417 </xsl:text> |
409 <xsl:text> // expected {index:period} |
418 <xsl:text> if(data.length > 0) { |
410 </xsl:text> |
419 </xsl:text> |
411 <xsl:text> const subscriptions = new Map(); |
420 <xsl:text> ws.send(new Blob([ |
412 </xsl:text> |
421 </xsl:text> |
413 <xsl:text> |
422 <xsl:text> new Uint8Array(hmi_hash), |
414 </xsl:text> |
423 </xsl:text> |
415 <xsl:text> // subscription state as needed by widget now |
424 <xsl:text> data])); |
416 </xsl:text> |
425 </xsl:text> |
417 <xsl:text> // expected {index:[widgets]}; |
426 <xsl:text> }; |
418 </xsl:text> |
427 </xsl:text> |
419 <xsl:text> var subscribers = new Map(); |
428 <xsl:text>}; |
420 </xsl:text> |
429 </xsl:text> |
421 <xsl:text> |
430 <xsl:text> |
422 </xsl:text> |
431 </xsl:text> |
423 <xsl:text> // return the diff in between curently subscribed and subscription |
432 <xsl:text>const typedarray_types = { |
424 </xsl:text> |
433 </xsl:text> |
425 <xsl:text> function update_subscriptions() { |
434 <xsl:text> INT: Int16Array, |
426 </xsl:text> |
435 </xsl:text> |
427 <xsl:text> let delta = []; |
436 <xsl:text> BOOL: Uint8Array |
428 </xsl:text> |
437 </xsl:text> |
429 <xsl:text> for(let [index, widgets] in subscribers.entries()){ |
438 <xsl:text> /* TODO */ |
430 </xsl:text> |
439 </xsl:text> |
431 <xsl:text> |
440 <xsl:text>}; |
432 </xsl:text> |
441 </xsl:text> |
433 <xsl:text> // periods are in ms |
442 <xsl:text> |
434 </xsl:text> |
443 </xsl:text> |
435 <xsl:text> let previous_period = subscriptions.get(index); |
444 <xsl:text>function send_reset() { |
436 </xsl:text> |
445 </xsl:text> |
437 <xsl:text> |
446 <xsl:text> send_blob(new Uint8Array([1])); /* reset = 1 */ |
438 </xsl:text> |
447 </xsl:text> |
439 <xsl:text> let new_period = Math.min(...widgets.map(widget => 1000/widget.frequency)); |
448 <xsl:text>}; |
440 </xsl:text> |
449 </xsl:text> |
441 <xsl:text> |
450 <xsl:text> |
442 </xsl:text> |
451 </xsl:text> |
443 <xsl:text> if(previous_period != new_period) { |
452 <xsl:text>// subscription state, as it should be in hmi server |
444 </xsl:text> |
453 </xsl:text> |
445 <xsl:text> subscriptions.set(index, new_period); |
454 <xsl:text>// hmitree indexed array of integers |
446 </xsl:text> |
455 </xsl:text> |
447 <xsl:text> delta.push({index: index, period: new_period}); |
456 <xsl:text>var subscriptions = hmitree_types.map(_ignored => 0); |
448 </xsl:text> |
457 </xsl:text> |
449 <xsl:text> } |
458 <xsl:text> |
450 </xsl:text> |
459 </xsl:text> |
451 <xsl:text> |
460 <xsl:text>// subscription state as needed by widget now |
452 </xsl:text> |
461 </xsl:text> |
453 <xsl:text> }) |
462 <xsl:text>// hmitree indexed array of Sets of widgets objects |
454 </xsl:text> |
463 </xsl:text> |
455 <xsl:text> return result; |
464 <xsl:text>var subscribers = hmitree_types.map(_ignored => new Set()); |
|
465 </xsl:text> |
|
466 <xsl:text> |
|
467 </xsl:text> |
|
468 <xsl:text>function update_subscriptions() { |
|
469 </xsl:text> |
|
470 <xsl:text> let delta = []; |
|
471 </xsl:text> |
|
472 <xsl:text> for(let index = 0; index < subscribers.length; index++){ |
|
473 </xsl:text> |
|
474 <xsl:text> let widgets = subscribers[index]; |
|
475 </xsl:text> |
|
476 <xsl:text> |
|
477 </xsl:text> |
|
478 <xsl:text> // periods are in ms |
|
479 </xsl:text> |
|
480 <xsl:text> let previous_period = subscriptions[index]; |
|
481 </xsl:text> |
|
482 <xsl:text> |
|
483 </xsl:text> |
|
484 <xsl:text> let new_period; |
|
485 </xsl:text> |
|
486 <xsl:text> if(widgets.size > 0) { |
|
487 </xsl:text> |
|
488 <xsl:text> let maxfreq = 0; |
|
489 </xsl:text> |
|
490 <xsl:text> for(let widget of widgets) |
|
491 </xsl:text> |
|
492 <xsl:text> if(maxfreq < widgets.frequency) |
|
493 </xsl:text> |
|
494 <xsl:text> maxfreq = widgets.frequency; |
|
495 </xsl:text> |
|
496 <xsl:text> |
|
497 </xsl:text> |
|
498 <xsl:text> new_period = 1000/maxfreq; |
|
499 </xsl:text> |
|
500 <xsl:text> } else { |
|
501 </xsl:text> |
|
502 <xsl:text> new_period = 0; |
|
503 </xsl:text> |
|
504 <xsl:text> } |
|
505 </xsl:text> |
|
506 <xsl:text> |
|
507 </xsl:text> |
|
508 <xsl:text> if(previous_period != new_period) { |
|
509 </xsl:text> |
|
510 <xsl:text> subscriptions[index] = new_period; |
|
511 </xsl:text> |
|
512 <xsl:text> delta.push([ |
|
513 </xsl:text> |
|
514 <xsl:text> new Uint8Array([2]), /* subscribe = 2 */ |
|
515 </xsl:text> |
|
516 <xsl:text> new Uint32Array([index]), |
|
517 </xsl:text> |
|
518 <xsl:text> new Uint16Array([new_period])]); |
|
519 </xsl:text> |
|
520 <xsl:text> } |
|
521 </xsl:text> |
|
522 <xsl:text> |
456 </xsl:text> |
523 </xsl:text> |
457 <xsl:text> } |
524 <xsl:text> } |
458 </xsl:text> |
525 </xsl:text> |
459 <xsl:text> |
526 <xsl:text> send_blob(delta); |
460 </xsl:text> |
527 </xsl:text> |
461 <xsl:text> |
528 <xsl:text>}; |
462 </xsl:text> |
529 </xsl:text> |
463 <xsl:text> function update_value(index, value) { |
530 <xsl:text> |
464 </xsl:text> |
531 </xsl:text> |
465 <xsl:text> |
532 <xsl:text>function update_value(index, value) { |
466 </xsl:text> |
533 </xsl:text> |
467 <xsl:text> }; |
534 <xsl:text> iectype = hmitree_types[index]; |
468 </xsl:text> |
535 </xsl:text> |
469 <xsl:text> |
536 <xsl:text> jstype = typedarray_types[iectypes]; |
470 </xsl:text> |
537 </xsl:text> |
471 <xsl:text> var current_page = default_page; |
538 <xsl:text> send_blob([ |
472 </xsl:text> |
539 </xsl:text> |
473 <xsl:text> |
540 <xsl:text> new Uint8Array([0]), /* setval = 0 */ |
474 </xsl:text> |
541 </xsl:text> |
475 <xsl:text> function switch_page(page_name) { |
542 <xsl:text> new jstype([value]) |
476 </xsl:text> |
543 </xsl:text> |
477 <xsl:text> let new_desc = page_desc[page_name]; |
544 <xsl:text> ]); |
478 </xsl:text> |
545 </xsl:text> |
479 <xsl:text> let old_desc = page_desc[page_name]; |
546 <xsl:text> |
480 </xsl:text> |
547 </xsl:text> |
481 <xsl:text> /* TODO hide / show widgets */ |
548 <xsl:text>}; |
482 </xsl:text> |
549 </xsl:text> |
483 <xsl:text> /* TODO move viewport */ |
550 <xsl:text> |
484 </xsl:text> |
551 </xsl:text> |
485 <xsl:text> |
552 <xsl:text>var current_page; |
486 </xsl:text> |
553 </xsl:text> |
487 <xsl:text> /* Update subscribers */ |
554 <xsl:text> |
488 </xsl:text> |
555 </xsl:text> |
489 <xsl:text> /* Update subscriptions */ |
556 <xsl:text>function switch_page(page_name) { |
490 </xsl:text> |
557 </xsl:text> |
491 <xsl:text> |
558 <xsl:text> let old_desc = page_desc[current_page]; |
492 </xsl:text> |
559 </xsl:text> |
493 <xsl:text> |
560 <xsl:text> let new_desc = page_desc[page_name]; |
494 </xsl:text> |
561 </xsl:text> |
495 <xsl:text> }; |
562 <xsl:text> /* TODO hide / show widgets */ |
|
563 </xsl:text> |
|
564 <xsl:text> /* TODO move viewport */ |
|
565 </xsl:text> |
|
566 <xsl:text> |
|
567 </xsl:text> |
|
568 <xsl:text> /* remove subsribers of previous page if any */ |
|
569 </xsl:text> |
|
570 <xsl:text> if(old_desc) for(let widget of old_desc.widgets){ |
|
571 </xsl:text> |
|
572 <xsl:text> for(let index of widget.indexes){ |
|
573 </xsl:text> |
|
574 <xsl:text> subscribers[index].delete(widget); |
|
575 </xsl:text> |
|
576 <xsl:text> } |
|
577 </xsl:text> |
|
578 <xsl:text> } |
|
579 </xsl:text> |
|
580 <xsl:text> /* add new subsribers if any */ |
|
581 </xsl:text> |
|
582 <xsl:text> if(new_desc) for(let widget of new_desc.widgets){ |
|
583 </xsl:text> |
|
584 <xsl:text> for(let index of widget.indexes){ |
|
585 </xsl:text> |
|
586 <xsl:text> subscribers[index].add(widget); |
|
587 </xsl:text> |
|
588 <xsl:text> } |
|
589 </xsl:text> |
|
590 <xsl:text> } |
|
591 </xsl:text> |
|
592 <xsl:text> |
|
593 </xsl:text> |
|
594 <xsl:text> current_page = page_name; |
|
595 </xsl:text> |
|
596 <xsl:text> |
|
597 </xsl:text> |
|
598 <xsl:text> update_subscriptions(); |
|
599 </xsl:text> |
|
600 <xsl:text>}; |
|
601 </xsl:text> |
|
602 <xsl:text> |
|
603 </xsl:text> |
|
604 <xsl:text> |
|
605 </xsl:text> |
|
606 <xsl:text>// Once connection established |
|
607 </xsl:text> |
|
608 <xsl:text>ws.onopen = function (evt) { |
|
609 </xsl:text> |
|
610 <xsl:text> send_reset(); |
|
611 </xsl:text> |
|
612 <xsl:text> // show main page |
|
613 </xsl:text> |
|
614 <xsl:text> switch_page(default_page); |
|
615 </xsl:text> |
|
616 <xsl:text> |
|
617 </xsl:text> |
|
618 <xsl:text>}; |
496 </xsl:text> |
619 </xsl:text> |
497 <xsl:text> |
620 <xsl:text> |
498 </xsl:text> |
621 </xsl:text> |
499 <xsl:text>})(); |
622 <xsl:text>})(); |
500 </xsl:text> |
623 </xsl:text> |