Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 47 additions & 21 deletions scratch-vm/src/extensions/scratch3_tello/telloProcessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const dgram = require('dgram');
class TelloProcessor {
initialize () {
this.queue = []; // command queue
this.timer = null;

this.client = dgram.createSocket('udp4');
this.server = dgram.createSocket('udp4');
Expand All @@ -17,30 +18,28 @@ class TelloProcessor {
this.send('command');

this.client.on('message', (message, remote) => {
const readableMessage = message.toString();
const readableMessage = message.toString().trim();

// Previous command executed
if (readableMessage === 'ok') {
this.executing = false;
// Clear timeout since we got a response
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}

// Mark as not executing so we can send the next command
this.executing = false;

// Update flying state based on successful commands
if (readableMessage === 'ok') {
if (this.executingCommand === 'takeoff') this.flying = true;
if (this.executingCommand === 'land') this.flying = false;
}
// Note: We do NOT set flying=false on error, because a failed 'flip'
// shouldn't prevent us from sending 'land' later.

// Dequeue
this.queue.shift();

// Send next element
this.inquire();
} else if (readableMessage.includes('error')) {
this.executing = false;
this.flying = false;

// Dequeue
this.queue.shift();

// Send next element
this.inquire();
}
// Dequeue and proceed
this.queue.shift();
this.inquire();
});

// Tello State
Expand Down Expand Up @@ -80,19 +79,46 @@ class TelloProcessor {
const msg = Buffer.from(cmd);
// While grounding, `command`, `mon`, `mdirection 2` and `takeoff` are only executable
if (!this.flying && cmd !== 'command' && cmd !== 'mon' && cmd !== 'mdirection 2' && cmd !== 'takeoff') {
// If we are on the ground and try to fly/flip, skip it silently or log warning
// But we must dequeue it to prevent blocking
this.queue.shift();
this.inquire();
return;
}

this.executing = true;
this.executingCommand = cmd;

// Set watchdog timer
this.timer = setTimeout(() => {
// console.warn(`[Tello] Timeout waiting for '${cmd}'. Skipping.`);
this.executing = false;
this.queue.shift();
this.inquire();
}, 3000);

this.client.send(msg, 0, msg.length, 8889, '192.168.10.1', (err, bytes) => {
if (err) throw err;
if (err) {
// console.error(`[Tello] Send error: ${err}`);
// Don't crash, just try to recover
clearTimeout(this.timer);
this.executing = false;
this.queue.shift();
this.inquire();
}
});
}

resetQueue () {
this.queue = [];
this.flying = false;
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
// We generally don't want to reset 'flying' state here blindly
// because the drone might still be in the air.
// But for safety/reset purposes as originally intended:
this.flying = false;
this.executing = false;
}
}
Expand Down