Commit ead1b62e 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 aa71ff0a
......@@ -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 = bf69b4317283f59acda44e341c0a644e
md5sum = 7d4969239eb9d46bb44d57fc32b68c44
[main]
filename = main.js
md5sum = 271736c5286f0032b22878f915964429
md5sum = 4b1b27ea3e06b8d40cbc33f0ec617601
[pubsub]
filename = pubsub.js
md5sum = d8798c3206f129e8715afd3ca23afa1a
md5sum = 4a0c63f9e088fa525a3699484d193c4d
[worker]
filename = worker.js
md5sum = 2f3761f14a4cbd557c91f949fba3471e
md5sum = 5ed534e9ca56b9c0ee321b96b5d7c458
......@@ -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_a_drone drone:is-a-drone
key log_dir directory:log
......
/*global console*/
/* global console */
import {
arm,
start,
......@@ -29,15 +29,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);
......@@ -59,14 +58,15 @@ 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();
}
......@@ -88,7 +88,7 @@ import { exit } from "std";
}
function loop() {
var timestamp = Date.now(),
let timestamp = Date.now(),
timeout;
if (can_update) {
if (FPS <= (timestamp - previous_timestamp)) {
......@@ -114,11 +114,12 @@ 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 }},
interval: FPS,
publish: IS_A_DRONE
});
load();
......
......@@ -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_A_DRONE = {{ 'true' if is_a_drone 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_A_DRONE && 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