Commit 2478a4d6 authored by Léo-Paul Géneau's avatar Léo-Paul Géneau 👾

component/qjs-wrapper: add message API

Add support of the message API (send and receive custom messages between drones).
parent 9479398d
......@@ -10,8 +10,8 @@ parts = qjs-wrapper
recipe = slapos.recipe.cmmi
shared = true
configure-command = true
url = https://lab.nexedi.com/nexedi/qjs-wrapper/-/archive/v0.3/qjs-wrapper-v0.3.tar.gz
md5sum = 850b9d5b8530521635a08baa1a2aa9e0
url = https://lab.nexedi.com/nexedi/qjs-wrapper/-/archive/v1.0/qjs-wrapper-v1.0.tar.gz
md5sum = 0f1393fa15d46b2b551836197af9de46
environment =
C_INCLUDE_PATH=include:${open62541:location}/include:${open62541:location}/deps:${open62541:location}/src/pubsub:${quickjs:location}/include
CPLUS_INCLUDE_PATH=include:${mavsdk:location}/include:${mavsdk:location}/include/mavsdk
......
......@@ -14,8 +14,6 @@
* is-a-simulation: Must be set to 'true' to automatically take off during simulation
* leader-id: Id of the drone chosen to be the leader of the swarm
* multicast-ipv6: IPv6 of the multicast group of the swarm
* net-if: Network interface used for multicast traffic
......
......@@ -14,16 +14,16 @@
# not need these here).
[instance-profile]
filename = instance.cfg
md5sum = ec3dad4513c8587300f1ad64266a4887
md5sum = 4adca48396a569d2bb9148200866f0d6
[main]
filename = main.js
md5sum = b5814f9c0985d7b06c77637baf30a124
md5sum = 693f8c0f6cee38f52e14e4945a5a63a1
[pubsub]
filename = pubsub.js
md5sum = d8798c3206f129e8715afd3ca23afa1a
md5sum = 4a0c63f9e088fa525a3699484d193c4d
[worker]
filename = worker.js
md5sum = 926094ffa8f32cc62c991d8528543cc7
md5sum = 7e927dae7a0717fb59733bb1d228257f
......@@ -29,8 +29,6 @@ init =
options['autopilot-ip'] = options['slapparameter-dict'].get('autopilot-ip', '192.168.27.1')
options['id'] = options['slapparameter-dict'].get('id', 1)
options['is-a-simulation'] = options['slapparameter-dict'].get('is-a-simulation', False)
options['leader-id'] = options['slapparameter-dict'].get('leader-id', 1)
options['is-leader'] = options['id'] == options['leader-id']
options['multicast-ipv6'] = options['slapparameter-dict'].get('multicast-ip', 'ff15::1111')
options['net-if'] = options['slapparameter-dict'].get('net-if', 'eth0')
options['drone-id-list'] = options['slapparameter-dict'].get('drone-id-list', [])
......@@ -71,8 +69,6 @@ context =
extra-context =
key autopilot_ip drone:autopilot-ip
key id drone:id
key leader_id drone:leader-id
key is_leader drone:is-leader
key is_a_simulation drone:is-a-simulation
key is_publisher drone:is-publisher
key log_dir directory:log
......
/*global console*/
/* global console */
import {
arm,
start,
......@@ -30,15 +30,14 @@ import { exit } from "std";
// Use the same FPS than browser's requestAnimationFrame
FPS = 1000 / 60,
previous_timestamp,
can_update = false,
i = 0;
can_update = false;
function connect() {
console.log("Will connect to", URL);
exit_on_fail(start(URL, LOG_FILE, 60), "Failed to connect to " + URL);
exitOnFail(start(URL, LOG_FILE, 60), "Failed to connect to " + URL);
}
function exit_on_fail(ret, msg) {
function exitOnFail(ret, msg) {
if (ret) {
console.log(msg);
quit(1);
......@@ -60,19 +59,20 @@ import { exit } from "std";
pubsubWorker = new Worker("{{ pubsub_script }}");
pubsubWorker.onmessage = function(e) {
if (!e.data.publishing)
if (!e.data.publishing) {
pubsubWorker.onmessage = null;
}
}
worker.postMessage({type: "initPubsub"});
function takeOff() {
exit_on_fail(arm(), "Failed to arm");
exitOnFail(arm(), "Failed to arm");
takeOffAndWait();
}
function load() {
if(IS_PUBLISHER && SIMULATION) {
if (IS_PUBLISHER && SIMULATION) {
takeOff();
}
......@@ -89,7 +89,7 @@ import { exit } from "std";
}
function loop() {
var timestamp = Date.now(),
let timestamp = Date.now(),
timeout;
if (can_update) {
if (FPS <= (timestamp - previous_timestamp)) {
......@@ -116,9 +116,14 @@ import { exit } from "std";
}
worker.onmessage = function (e) {
var type = e.data.type;
let type = e.data.type;
if (type === 'initialized') {
pubsubWorker.postMessage({ action: "run", id: {{ id }}, publish: IS_PUBLISHER });
pubsubWorker.postMessage({
action: "run",
id: {{ id }},
interval: FPS,
publish: IS_PUBLISHER
});
pubsubRunning = true;
load();
} else if (type === 'loaded') {
......@@ -130,12 +135,12 @@ import { exit } from "std";
can_update = true;
} else if (type === 'exited') {
worker.onmessage = null;
if(IS_PUBLISHER) {
if (IS_PUBLISHER) {
quit(e.data.exit);
} else {
stopPubsub();
exit(e.data.exit);
};
}
} else {
console.log('Unsupported message type', type);
quit(1);
......
......@@ -4,12 +4,12 @@ import {Worker} from "os";
const PORT = "4840";
const IPV6 = "{{ ipv6 }}";
var parent = Worker.parent;
let parent = Worker.parent;
function handle_msg(e) {
switch(e.data.action) {
case "run":
runPubsub(IPV6, PORT, "{{ net_if }}", e.data.id, e.data.publish);
runPubsub(IPV6, PORT, "{{ net_if }}", e.data.id, e.data.interval, e.data.publish);
parent.postMessage({running: false});
parent.onmessage = null;
break;
......
/*global console*/
/* global console, std */
import {
Drone,
triggerParachute,
......@@ -14,12 +14,12 @@ import {
loiter,
setAirspeed,
setAltitude,
setCheckpoint,
setManualControlInput,
setMessage,
setTargetCoordinates
} from "{{ qjs_wrapper }}";
import { Worker } from "os"
import * as std from "std";
import { Worker } from "os";
(function (console, Worker) {
// Every script is evaluated per drone
......@@ -28,13 +28,11 @@ import * as std from "std";
drone_id_list = {{ drone_id_list }},
IS_PUBLISHER = {{ 'true' if is_publisher else 'false' }};
var parent = Worker.parent,
let parent = Worker.parent,
user_me = {
//for debugging purpose
fdopen: std.fdopen,
in: std.in,
//to move into user script
setCheckpoint: setCheckpoint,
//required to fly
triggerParachute: triggerParachute,
drone_dict: {},
......@@ -55,51 +53,68 @@ import * as std from "std";
id: {{ id }},
landed: landed,
loiter: loiter,
sendMsg: function(msg, id = -1) {
setMessage(JSON.stringify({ content: msg, dest_id: id }));
},
setAirspeed: setAirspeed,
setAltitude: setAltitude,
setTargetCoordinates: setTargetCoordinates
};
function loadUserScript(path) {
var script_content = std.loadFile(path);
let script_content = std.loadFile(path);
if (script_content === null) {
console.log('Failed to load user script ' + path);
console.log("Failed to load user script " + path);
std.exit(1);
}
try {
std.evalScript(
'function execUserScript(from, me) {' +
"function execUserScript(from, me) {" +
script_content +
'};'
"};"
);
} catch (e) {
console.log('Failed to evaluate user script', e);
console.log("Failed to evaluate user script", e);
std.exit(1);
}
execUserScript(null, user_me);
// Call the drone onStart function
if (user_me.hasOwnProperty('onStart')) {
if (user_me.hasOwnProperty("onStart")) {
user_me.onStart();
}
}
function handleMainMessage(evt) {
var type = evt.data.type;
let type = evt.data.type,
message,
drone_id;
if (type === 'initPubsub') {
if (type === "initPubsub") {
initPubsub(drone_id_list.length);
for (let i = 0; i < drone_id_list.length; i++) {
let id = drone_id_list[i];
user_me.drone_dict[id] = new Drone(id);
user_me.drone_dict[id].init(i);
drone_id = drone_id_list[i];
user_me.drone_dict[drone_id] = new Drone(drone_id);
user_me.drone_dict[drone_id].init(i);
}
parent.postMessage({type: "initialized"});
}
else if (type === 'load') {
} else if (type === "load") {
loadUserScript(evt.data.path);
parent.postMessage({type: "loaded"});
} else if (type === 'update') {
} else if (type === "update") {
for (const [id, drone] of Object.entries(user_me.drone_dict)) {
message = drone.message
if (message.length > 0) {
message = JSON.parse(message);
if (user_me.id === id) {
continue;
}
if (user_me.hasOwnProperty("onGetMsg") &&
[-1, user_me.id].includes(message.dest_id)) {
user_me.onGetMsg(message.content);
}
}
}
// Call the drone onStart function
if (user_me.hasOwnProperty("onUpdate")) {
if (IS_PUBLISHER && isInManualMode()) {
......@@ -109,7 +124,7 @@ import * as std from "std";
}
parent.postMessage({type: "updated"});
} else {
throw new Error('Unsupported message type', type);
throw new Error("Unsupported message type", type);
}
}
......@@ -123,5 +138,4 @@ import * as std from "std";
std.exit(1);
}
};
}(console, Worker));
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