Commit 632ad024 authored by Léo-Paul Géneau's avatar Léo-Paul Géneau 👾

software/js-drone: print pubsub logs in the GUI

parent eae3a24e
......@@ -14,7 +14,7 @@
# not need these here).
[index-html]
_update_hash_filename_ = web-gui/index.html.jinja2
md5sum = 1eedc017ecc9d1a6761dc2fff3bbab9b
md5sum = 94479f7e7299650fc41878fab06e6555
[instance-profile]
filename = instance.cfg.in
......@@ -38,8 +38,8 @@ md5sum = 1555496ad591a31a845f33488d5c335d
[script-js]
_update_hash_filename_ = web-gui/script.js.jinja2
md5sum = e28492276416c2d84e770217ae97a88f
md5sum = a88028c1248d2b6a91b7d3cb03047196
[worker]
_update_hash_filename_ = drone-scripts/worker.js.jinja2
md5sum = 48540afedd5437129196d84832d2ed40
md5sum = 06a322cc711830262fbbfdc1bfe7947a
......@@ -11,6 +11,7 @@ import {
getClimbRate,
getInitialAltitude,
gpsIsOk,
getLog,
getPosition,
getYaw,
initPubsub,
......@@ -36,8 +37,8 @@ import { evalScript, fdopen, loadFile, open } from "std";
(function (Drone, SIGTERM, WNOHANG, Worker, close, console, evalScript, exec,
fdopen, getAltitude, getInitialAltitude, gpsIsOk, getPosition,
getYaw, initPubsub, kill, isLanding, loadFile, loiter, open, pipe,
setAirSpeed, setMessage, setReadHandler, setTargetCoordinates,
getLog, getYaw, initPubsub, isLanding, kill, loadFile, loiter, open,
pipe, setAirSpeed, setMessage, setReadHandler, setTargetCoordinates,
triggerParachute, updateLogAndProjection, waitpid) {
// Every script is evaluated per drone
"use strict";
......@@ -200,7 +201,7 @@ import { evalScript, fdopen, loadFile, open } from "std";
}
function handleMainMessage(evt) {
var type = evt.data.type, message, peer_id;
var type = evt.data.type, message, peer_id, log;
switch (type) {
......@@ -234,7 +235,15 @@ import { evalScript, fdopen, loadFile, open } from "std";
}
}
});
// Call the drone onStart function
if (clientId !== undefined) {
log = getLog();
if (log.length > 0) {
user_me.writeWebsocketMessage(JSON.stringify({log: log}));
}
}
// Call the drone onUpdate function
if (user_me.hasOwnProperty("onUpdate")) {
user_me.onUpdate(evt.data.timestamp);
}
......@@ -267,7 +276,7 @@ import { evalScript, fdopen, loadFile, open } from "std";
}
};
}(Drone, SIGTERM, WNOHANG, Worker, close, console, evalScript, exec,
fdopen, getAltitude, getInitialAltitude, gpsIsOk, getPosition, getYaw,
fdopen, getAltitude, getInitialAltitude, gpsIsOk, getPosition, getLog, getYaw,
initPubsub, isLanding, kill, loadFile, loiter, open, pipe, setAirSpeed,
setMessage, setReadHandler, setTargetCoordinates, triggerParachute,
updateLogAndProjection, waitpid));
......@@ -284,6 +284,49 @@ class SubscriberTestCase(SlapOSInstanceTestCase):
b'Unknown instruction %s' % ws.sock.getsockname()[0].encode(),
ws.recv_frame().data
)
self.assertIn(
b'\\u001b[32minfo/userland\\u001b[0m\\tfieldsSize 3\\n"}',
ws.recv_frame().data,
)
self.assertEqual(
ws.recv_frame().data,
b''.join((
b'{"drone_dict":{"0":{"latitude":',
b'"%.6f","longitude":"%.6f","altitude":"%.2f",' % (0, 0, 0),
b'"yaw":"%.2f","speed":"%.2f","climbRate":"%.2f",' % (0, 0, 0),
b'"timestamp":%d}}}' % 0,
))
)
self.assertIn(
b'\\u001b[32minfo/client\\u001b[0m\\tReceived position of drone 0: %.6f ? %.6f ? %.2f m %.2f m\\n"}' % (0, 0 , 0, 0),
ws.recv_frame().data,
)
self.assertEqual(
ws.recv_frame().data,
b''.join((
b'{"drone_dict":{"0":{"latitude":',
b'"%.6f","longitude":"%.6f","altitude":"%.2f",' % (0, 0, 0),
b'"yaw":"%.2f","speed":"%.2f","climbRate":"%.2f",' % (0, 0, 0),
b'"timestamp":%d}}}' % 0,
))
)
self.assertIn(
b'\\u001b[32minfo/client\\u001b[0m\\tReceived speed of drone 0: %.2f ? %.2f m/s %.2f m/s\\n"}' % (0, 0 , 0),
ws.recv_frame().data,
)
self.assertEqual(
ws.recv_frame().data,
b''.join((
b'{"drone_dict":{"0":{"latitude":',
b'"%.6f","longitude":"%.6f","altitude":"%.2f",' % (0, 0, 0),
b'"yaw":"%.2f","speed":"%.2f","climbRate":"%.2f",' % (0, 0, 0),
b'"timestamp":%d}}}' % 0,
))
)
self.assertIn(
b'\\u001b[32minfo/userland\\u001b[0m\\tfieldsSize 1\\n"}',
ws.recv_frame().data,
)
self.assertEqual(
ws.recv_frame().data,
b''.join((
......@@ -296,6 +339,10 @@ class SubscriberTestCase(SlapOSInstanceTestCase):
self.send_ua_networkMessage()
time.sleep(0.1)
self.assertEqual(ws.recv_frame().data, MESSAGE_CONTENT.replace(b'\\', b''))
self.assertIn(
b'\\u001b[32minfo/client\\u001b[0m\\tReceived position of drone 0: %.6f ? %.6f ? %.2f m %.2f m\\n"}' % POSITION_ARRAY_OUTPUT_VALUES,
ws.recv_frame().data,
)
self.assertEqual(
ws.recv_frame().data,
b''.join((
......@@ -305,4 +352,8 @@ class SubscriberTestCase(SlapOSInstanceTestCase):
b'"timestamp":%d}}}' % POSITION_ARRAY_INPUT_VALUES[-1],
))
)
self.assertIn(
b'\\u001b[32minfo/client\\u001b[0m\\tReceived speed of drone 0: %.2f ? %.2f m/s %.2f m/s\\n"}' % SPEED_ARRAY_VALUES,
ws.recv_frame().data,
)
ws.close()
......@@ -9,7 +9,8 @@
<style>
button {
padding: 0.5%;
margin: 2vh;
padding: 2vh;
font-size: 24px;
cursor: pointer;
border: none;
......@@ -20,38 +21,60 @@
box-shadow: 0 2px #666;
transform: translateY(4px);
}
div > * {margin: 1%}
label {margin: 2%}
table {width: 30%}
label {margin: auto 2%}
table {
min-width: 1028px;
height: max-content;
}
th, td{
padding: 1%;
text-align: center;
vertical-align: middle;
}
.blue-text {color: blue}
.connected {color: green}
.container {
display: flex;
align-items: center;
justify-content: center;
}
.cyan-text {color: cyan}
.disconnected {color: red}
.gray-button {background-color: lightgray}
.gray-button:hover {background-color: gray}
.green-text {color: green}
.green-button {background-color: #4caf50}
.green-button:hover {background-color: #3e8e41}
.magenta-text {color: magenta}
.red-button {background-color: red}
.red-button {background-color: #e42828}
.red-button:hover {background-color: #e42828}
.red-text {color: red}
.white-text {color: white}
.yellow-text {color: yellow}
#drones-status {height: 50vh}
#prompt {
background-color: rgb(18, 19, 20);
max-width: 1028px;
height: 20vh;
margin: auto;
}
#prompt-div {
height: max-content;
}
</style>
</head>
<body>
<header class="container">
<label for="web-socket-status">web socket status:</label>
<output class="disconnected" id="web-socket-status">Disconnected</output>
</header>
<div id="prompt-div">
<div class="container">
<label for="web-socket-status">web socket status:</label>
<output class="disconnected" id="web-socket-status">Disconnected</output>
</div>
<pre id="prompt"></pre>
</div>
<div class="container">
<div class="container" id="drones-status">
<table>
<tr>
<th></th>
......
......@@ -13,6 +13,9 @@
GREEN_BTN_CLASS_NAME = "green-button",
LATITUDE_BASE_ID = "latitude_",
LONGITUDE_BASE_ID = "longitude_",
PROMPT_COLOR_RE = /\u001b.{2,3}m/g,
PROMPT_ID = "prompt",
PROMPT_MAX_MSG,
QUIT_BTN_ID = "quit-btn",
RED_BTN_CLASS_NAME = "red-button",
SWITCH_BTN_ID = "switch-btn",
......@@ -21,8 +24,12 @@
socket;
function updateConnexionClass(element, status) {
element.classList.remove(status ? DISCONNECTED_CLASS_NAME : CONNECTED_CLASS_NAME);
element.classList.add(status ? CONNECTED_CLASS_NAME : DISCONNECTED_CLASS_NAME);
element.classList.remove(
status ? DISCONNECTED_CLASS_NAME : CONNECTED_CLASS_NAME
);
element.classList.add(
status ? CONNECTED_CLASS_NAME : DISCONNECTED_CLASS_NAME
);
}
function setWebSocketStatus(connected, status) {
......@@ -49,15 +56,22 @@
socket = new WebSocket('ws://{{ websocket_url }}');
socket.onopen = function(event) {
socket.onopen = function (event) {
setWebSocketStatus(true, "Connected");
};
socket.onmessage = function(event) {
var message = JSON.parse(event.data),
flight_state_cell;
socket.onmessage = function (event) {
var color_array,
flight_state_cell,
i,
message = JSON.parse(event.data),
prompt,
new_div,
new_span,
text_array;
if (message.hasOwnProperty("drone_dict")) {
Object.entries(message["drone_dict"]).forEach(function ([id, drone]) {
Object.entries(message.drone_dict).forEach(function ([id, drone]) {
document.getElementById(LATITUDE_BASE_ID + id).innerHTML = drone["latitude"];
document.getElementById(LONGITUDE_BASE_ID + id).innerHTML = drone["longitude"];
document.getElementById(ALTITUDE_BASE_ID + id).innerHTML = drone["altitude"];
......@@ -69,6 +83,56 @@
flight_state_cell = document.getElementById(FLIGHT_STATUS_BASE_ID + message['id']);
flight_state_cell.innerHTML = message['state'];
updateConnexionClass(flight_state_cell, message['inAir']);
} else if(message.hasOwnProperty("log")) {
prompt = document.getElementById(PROMPT_ID);
if (PROMPT_MAX_MSG === undefined && prompt.children.length > 0) {
PROMPT_MAX_MSG = Math.trunc(
prompt.offsetHeight / prompt.children[0].offsetHeight
);
}
new_div = document.createElement("div");
text_array = message['log'].split(PROMPT_COLOR_RE);
color_array = message['log'].match(PROMPT_COLOR_RE);
for (i = 0; i < text_array.length; i++) {
new_span = document.createElement("span");
new_span.appendChild(document.createTextNode(text_array[i]));
if (i > 0 && i < color_array.length + 1) {
switch (color_array[i - 1]) {
case "\u001b[31m":
new_span.classList.add('red-text');
break;
case "\u001b[32m":
new_span.classList.add('green-text');
break;
case "\u001b[33m":
new_span.classList.add('yellow-text');
break;
case "\u001b[34m":
new_span.classList.add('blue-text');
break;
case "\u001b[35m":
new_span.classList.add('magenta-text');
break;
case "\u001b[36m":
new_span.classList.add('cyan-text');
break;
default:
new_span.classList.add('white-text');
break;
};
} else {
new_span.classList.add('white-text');
}
new_div.appendChild(new_span);
}
if (prompt.children.length === PROMPT_MAX_MSG) {
prompt.removeChild(prompt.firstElementChild);
}
prompt.appendChild(new_div);
} else {
console.info(message);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment