create separate sumorobot class
This commit is contained in:
		@@ -1,595 +1,101 @@
 | 
				
			|||||||
/* disable enable hotkeys */
 | 
					// Sumorobot constructor
 | 
				
			||||||
var hotkeys = true;
 | 
					var Sumorobot = function(wsUri, robotId) {
 | 
				
			||||||
/* enable disable remote control */
 | 
					    // Assign the WebSocket URI
 | 
				
			||||||
var remoteControl = false;
 | 
					 | 
				
			||||||
/* the local/remote server URL */
 | 
					 | 
				
			||||||
//var robotServer = "10.42.0.1";
 | 
					 | 
				
			||||||
var robotServer = "ws.achex.ca:4010";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* ace editor object */
 | 
					 | 
				
			||||||
var codingEditor = null;
 | 
					 | 
				
			||||||
/* read only ace editor object */
 | 
					 | 
				
			||||||
var readOnlyCodingEditor = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// sumorobot ID
 | 
					 | 
				
			||||||
var robotId = "";
 | 
					 | 
				
			||||||
/* the sumorobot code */
 | 
					 | 
				
			||||||
var sumocode = "";
 | 
					 | 
				
			||||||
/* the sumorobot object */
 | 
					 | 
				
			||||||
var sumorobot = null;
 | 
					 | 
				
			||||||
/* Blockly workspace */
 | 
					 | 
				
			||||||
var workspace = null;
 | 
					 | 
				
			||||||
/* the sumorobot state */
 | 
					 | 
				
			||||||
var sumostart = false;
 | 
					 | 
				
			||||||
/* disable / enable coding mode */
 | 
					 | 
				
			||||||
var codingEnabled = false;
 | 
					 | 
				
			||||||
/* disable / enable live stream */
 | 
					 | 
				
			||||||
var liveStreamVisible = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* connection watchdog counter */
 | 
					 | 
				
			||||||
var watchdogCounter = 0;
 | 
					 | 
				
			||||||
/* control_if block id */
 | 
					 | 
				
			||||||
var controlBlockId = "";
 | 
					 | 
				
			||||||
/* last hightlighted block id */
 | 
					 | 
				
			||||||
var lastHighlighted = "";
 | 
					 | 
				
			||||||
/* block highlight WebSocket */
 | 
					 | 
				
			||||||
var blockHighlight = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var Sumorobot = function(wsUri) {
 | 
					 | 
				
			||||||
    /* assign the WebSocket URI */
 | 
					 | 
				
			||||||
    this.wsUri = wsUri;
 | 
					    this.wsUri = wsUri;
 | 
				
			||||||
    /* start connecting to the WebSocket */
 | 
					    // Assign the SumoRobot ID
 | 
				
			||||||
    this.connect();
 | 
					    this.robotId = robotId;
 | 
				
			||||||
    /* to ping the robot */
 | 
					    // To keep track of the WebSocket connection
 | 
				
			||||||
 | 
					    this.watchdogTimer = 0;
 | 
				
			||||||
 | 
					    // Timer to ping the SumoRobot
 | 
				
			||||||
    this.watchdogTimer = null;
 | 
					    this.watchdogTimer = null;
 | 
				
			||||||
 | 
					    // To store Blockly code
 | 
				
			||||||
 | 
					    this.blocklyCode = "";
 | 
				
			||||||
 | 
					    // Start connecting to the WebSocket
 | 
				
			||||||
 | 
					    this.connect();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function to initiate the WebSocket connection
 | 
				
			||||||
Sumorobot.prototype.connect = function() {
 | 
					Sumorobot.prototype.connect = function() {
 | 
				
			||||||
    /* to have access to this object */
 | 
					    // To have access to this object inside events
 | 
				
			||||||
    var self = this;
 | 
					    var self = this;
 | 
				
			||||||
    this.websocket = new WebSocket(this.wsUri);
 | 
					    this.websocket = new WebSocket(this.wsUri);
 | 
				
			||||||
    /* setup connection watchdog interval */
 | 
					    // Setup connection watchdog interval
 | 
				
			||||||
    setInterval(function() {
 | 
					    setInterval(function() {
 | 
				
			||||||
        if (watchdogCounter == 0) {
 | 
					        if (self.watchdogCounter == 0) {
 | 
				
			||||||
            $("#battery").removeClass("connected");
 | 
					            $("#battery").removeClass("connected");
 | 
				
			||||||
            $("#battery").html("Disconnected");
 | 
					            $("#battery").html("Disconnected");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        /* reset watchdog counter */
 | 
					        // Reset watchdog counter
 | 
				
			||||||
        watchdogCounter = 0;
 | 
					        self.watchdogCounter = 0;
 | 
				
			||||||
    }, 3000);
 | 
					    }, 3000);
 | 
				
			||||||
    /* when the WebSocket gets connected */
 | 
					    // When the WebSocket gets connected
 | 
				
			||||||
    this.websocket.onopen = function(evt) {
 | 
					    this.websocket.onopen = function(evt) {
 | 
				
			||||||
        console.log("INFO websocket connected");
 | 
					        // Send authentication packet
 | 
				
			||||||
        // send authentication message
 | 
					        self.websocket.send(`{"setID": "browser-${self.robotId}@00000514", "passwd": "salakala"}`);
 | 
				
			||||||
        sumorobot.send('{"setID": "browser-' + robotId + '@00000514", "passwd": "salakala"}');
 | 
					        // Setup a timer to ping the robot
 | 
				
			||||||
        /* setup a timer to ping the robot */
 | 
					 | 
				
			||||||
        self.watchdogTimer = setInterval(function() {
 | 
					        self.watchdogTimer = setInterval(function() {
 | 
				
			||||||
            /* send a ping to the robot */
 | 
					            // Send a ping to the robot
 | 
				
			||||||
            //console.log("ping the robot")
 | 
					            self.send(self.robotId, "ping");
 | 
				
			||||||
            self.send('{"to": "sumo-' + robotId + '@00000514", "cmd": "ping"}');
 | 
					 | 
				
			||||||
        }, 500);
 | 
					        }, 500);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    /* when the WebSocket closes */
 | 
					    // When the WebSocket closes
 | 
				
			||||||
    this.websocket.onclose = function(evt) {
 | 
					    this.websocket.onclose = function(evt) {
 | 
				
			||||||
        console.log("INFO websocket disconnected");
 | 
					        console.log("INFO websocket disconnected");
 | 
				
			||||||
        /* clear the pinging */
 | 
					        // Clear the pinging
 | 
				
			||||||
        clearInterval(self.watchdogTimer);
 | 
					        clearInterval(self.watchdogTimer);
 | 
				
			||||||
        /* Try to recnnect to the sumorobot */
 | 
					        // Try to recnnect to the sumorobot
 | 
				
			||||||
        self.connect();
 | 
					        self.connect();
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    /* when there is a message from the WebSocket */
 | 
					    // When there is a message from the WebSocket
 | 
				
			||||||
    this.websocket.onmessage = function(evt) {
 | 
					    this.websocket.onmessage = function(evt) {
 | 
				
			||||||
        /* when scope is received */
 | 
					        // When scope is received
 | 
				
			||||||
        var data = evt.data.replace(/'/g, '"').toLowerCase();
 | 
					        var data = evt.data.replace(/'/g, '"').toLowerCase();
 | 
				
			||||||
        console.log(data);
 | 
					        // Get SumoRobot battery voltage
 | 
				
			||||||
        var battery = JSON.parse(data)["battery_voltage"];
 | 
					        var battery = JSON.parse(data)["battery_voltage"];
 | 
				
			||||||
 | 
					        // When sensor data received
 | 
				
			||||||
 | 
					        if (battery) {
 | 
				
			||||||
            $("#battery").html(battery + "V");
 | 
					            $("#battery").html(battery + "V");
 | 
				
			||||||
            $("#battery").addClass("connected");
 | 
					            $("#battery").addClass("connected");
 | 
				
			||||||
        /* keep track of data packets */
 | 
					        }
 | 
				
			||||||
        /* to see if we have a connection to the robot */
 | 
					        // Count data received packets
 | 
				
			||||||
        watchdogCounter += 1;
 | 
					        self.watchdogCounter += 1;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    /* when there is an WebSocket error */
 | 
					    // When there is an WebSocket error
 | 
				
			||||||
    this.websocket.onerror = function(err) {
 | 
					    this.websocket.onerror = function(err) {
 | 
				
			||||||
        console.log("ERROR websocket error: " + err);
 | 
					        console.log("ERROR websocket error: " + err);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Sumorobot.prototype.send = function(msg) {
 | 
					// Function to send WebSocket data
 | 
				
			||||||
    /* ready state constants: CONNECTING 0, OPEN 1, CLOSING 2, CLOSED 3 */
 | 
					Sumorobot.prototype.send = function(msg, val) {
 | 
				
			||||||
    /* https://developer.mozilla.org/en-US/docs/Web/API/WebSocket */
 | 
					    // Ready state constants: CONNECTING 0, OPEN 1, CLOSING 2, CLOSED 3
 | 
				
			||||||
 | 
					    // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
 | 
				
			||||||
    if (this.websocket.readyState == 1) {
 | 
					    if (this.websocket.readyState == 1) {
 | 
				
			||||||
        this.websocket.send(msg);
 | 
					        if (val === 'undefined') {
 | 
				
			||||||
 | 
					            console.log("no val")
 | 
				
			||||||
 | 
					            this.websocket.send(`{"to": "sumo-${this.robotId}@00000514", "cmd": "${msg}"}`);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            console.log("val")
 | 
				
			||||||
 | 
					            this.websocket.send(`{"to": "sumo-${this.robotId}@00000514", "cmd": "${msg}", "val": "${val}"}`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function to close the WebSocket connection
 | 
				
			||||||
Sumorobot.prototype.close = function() {
 | 
					Sumorobot.prototype.close = function() {
 | 
				
			||||||
    /* close the WebSocket connection */
 | 
					    // When a WebSocket connection exists
 | 
				
			||||||
 | 
					    if (this.websocket !== 'undefined') {
 | 
				
			||||||
 | 
					        // Close the WebSocket connection
 | 
				
			||||||
        this.websocket.close();
 | 
					        this.websocket.close();
 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* function to set local storage */
 | 
					 | 
				
			||||||
function getLocalStorageItem(item) {
 | 
					 | 
				
			||||||
    /* when the local storage doesn't exist, return empty string */
 | 
					 | 
				
			||||||
    if (typeof(Storage) === "undefined") return "";
 | 
					 | 
				
			||||||
    /* otherwise return item from the local storage*/
 | 
					 | 
				
			||||||
    return localStorage.getItem(item);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* function to set local storage */
 | 
					 | 
				
			||||||
function setLocalStorageItem(item, value) {
 | 
					 | 
				
			||||||
    /* when local storage doesn't exist, return */
 | 
					 | 
				
			||||||
    if (typeof(Storage) === "undefined") return;
 | 
					 | 
				
			||||||
    /* otherwise set the item to the local storage */
 | 
					 | 
				
			||||||
    localStorage.setItem(item, value)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
window.onload = function() {
 | 
					 | 
				
			||||||
    $("#robot-id").val(getLocalStorageItem("sumorobot.robotId"));
 | 
					 | 
				
			||||||
    /* load read only ace editor */
 | 
					 | 
				
			||||||
    readOnlyCodingEditor = ace.edit("readOnlyBlocklyCode");
 | 
					 | 
				
			||||||
    /* set the style */
 | 
					 | 
				
			||||||
    readOnlyCodingEditor.setTheme("ace/theme/textmate");
 | 
					 | 
				
			||||||
    readOnlyCodingEditor.session.setMode("ace/mode/python");
 | 
					 | 
				
			||||||
    readOnlyCodingEditor.session.setTabSize(2);
 | 
					 | 
				
			||||||
    /* make as read only */
 | 
					 | 
				
			||||||
    readOnlyCodingEditor.setReadOnly(true);
 | 
					 | 
				
			||||||
    /* disable scrolling warning */
 | 
					 | 
				
			||||||
    readOnlyCodingEditor.$blockScrolling = Infinity;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* load ace editor */
 | 
					 | 
				
			||||||
    codingEditor = ace.edit("blocklyCode");
 | 
					 | 
				
			||||||
    /* set the style */
 | 
					 | 
				
			||||||
    codingEditor.setTheme("ace/theme/textmate");
 | 
					 | 
				
			||||||
    codingEditor.session.setMode("ace/mode/python");
 | 
					 | 
				
			||||||
    codingEditor.session.setTabSize(2);
 | 
					 | 
				
			||||||
    /* disable scrolling warning */
 | 
					 | 
				
			||||||
    codingEditor.$blockScrolling = Infinity;
 | 
					 | 
				
			||||||
    /* enable autocomplete */
 | 
					 | 
				
			||||||
    ace.require("ace/ext/language_tools");
 | 
					 | 
				
			||||||
    codingEditor.setOptions({
 | 
					 | 
				
			||||||
        enableSnippets: true,
 | 
					 | 
				
			||||||
        enableLiveAutocompletion: true,
 | 
					 | 
				
			||||||
        enableBasicAutocompletion: true
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    /* add autocomplete keywords */
 | 
					 | 
				
			||||||
    codingEditor.completers.push({
 | 
					 | 
				
			||||||
    getCompletions: function(editor, session, pos, prefix, callback) {
 | 
					 | 
				
			||||||
            callback(null, [
 | 
					 | 
				
			||||||
                {value: "STOP", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "LEFT", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "RIGHT", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "SEARCH", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "FORWARD", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "BACKWARD", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "STATUS", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "LEFT_LINE", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "RIGHT_LINE", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "sumorobot", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "move", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "sleep", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "set_led", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "is_line", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "get_line", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "set_servo", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "is_opponent", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "calibrate_line", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "get_battery_voltage", score: 1000, meta: "sumorobot"},
 | 
					 | 
				
			||||||
                {value: "get_opponent_distance", score: 1000, meta: "sumorobot"}
 | 
					 | 
				
			||||||
            ]);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    /* set the code to the saved code from local storage or empty */
 | 
					 | 
				
			||||||
    codingEditor.setValue(getLocalStorageItem("sumorobot.code") || "");
 | 
					 | 
				
			||||||
    /* clear the selection after setting the value */
 | 
					 | 
				
			||||||
    codingEditor.clearSelection();
 | 
					 | 
				
			||||||
    /* add an change listener for the code editor */
 | 
					 | 
				
			||||||
    codingEditor.on("change", function() {
 | 
					 | 
				
			||||||
        /* when change occurs, save the new code to the localstorage */
 | 
					 | 
				
			||||||
        setLocalStorageItem("sumorobot.code", codingEditor.getValue())
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* change the if block to be more cheerful */
 | 
					 | 
				
			||||||
    Blockly.Msg.LOGIC_HUE = '#44CC00';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* remote previous and next statement from control_if block */
 | 
					 | 
				
			||||||
    Blockly.defineBlocksWithJsonArray([
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "type": "controls_if",
 | 
					 | 
				
			||||||
          "message0": "%{BKY_CONTROLS_IF_MSG_IF} %1",
 | 
					 | 
				
			||||||
          "args0": [
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              "type": "input_value",
 | 
					 | 
				
			||||||
              "name": "IF0",
 | 
					 | 
				
			||||||
              "check": "Boolean"
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          ],
 | 
					 | 
				
			||||||
          "message1": "%{BKY_CONTROLS_IF_MSG_THEN} %1",
 | 
					 | 
				
			||||||
          "args1": [
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              "type": "input_statement",
 | 
					 | 
				
			||||||
              "name": "DO0"
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          ],
 | 
					 | 
				
			||||||
          "colour": "%{BKY_LOGIC_HUE}",
 | 
					 | 
				
			||||||
          "helpUrl": "%{BKY_CONTROLS_IF_HELPURL}",
 | 
					 | 
				
			||||||
          "mutator": "controls_if_mutator",
 | 
					 | 
				
			||||||
          "extensions": ["controls_if_tooltip"]
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* make control_if mutator icon bigger */
 | 
					 | 
				
			||||||
    Blockly.Icon.prototype.renderIcon = function(cursorX) {
 | 
					 | 
				
			||||||
        if (this.collapseHidden && this.block_.isCollapsed()) {
 | 
					 | 
				
			||||||
            this.iconGroup_.setAttribute('display', 'none');
 | 
					 | 
				
			||||||
            return cursorX;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.iconGroup_.setAttribute('display', 'block');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        var SIZE = 1.7;
 | 
					 | 
				
			||||||
        var TOP_MARGIN = 2;
 | 
					 | 
				
			||||||
        var LEFT_MARGIN = 5;
 | 
					 | 
				
			||||||
        var width = this.SIZE;
 | 
					 | 
				
			||||||
        if (this.block_.RTL) {
 | 
					 | 
				
			||||||
            cursorX -= width;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.iconGroup_.setAttribute('transform',
 | 
					 | 
				
			||||||
            'translate(' + LEFT_MARGIN + ',' + TOP_MARGIN + ') scale(' + SIZE + ')');
 | 
					 | 
				
			||||||
        this.computeIconLocation();
 | 
					 | 
				
			||||||
        if (this.block_.RTL) {
 | 
					 | 
				
			||||||
            cursorX -= Blockly.BlockSvg.SEP_SPACE_X;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            cursorX += width + Blockly.BlockSvg.SEP_SPACE_X;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return cursorX;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* when mouse click occures on Blockly workspace */
 | 
					 | 
				
			||||||
    Blockly.utils.isRightButton = function(e) {
 | 
					 | 
				
			||||||
        var target = e.target;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* when control_if block is in use */
 | 
					 | 
				
			||||||
        if (controlBlockId != "") {
 | 
					 | 
				
			||||||
            /* when the user clicks anywhere outside the mutator and not on the mutator icon */
 | 
					 | 
				
			||||||
            if (!$(target).is('.blocklyBubbleCanvas') && !$(target).parents().is('.blocklyBubbleCanvas')) {
 | 
					 | 
				
			||||||
                if (!$(target).is('.blocklyIconGroup') && !$(target).parents().is('.blocklyIconGroup')) {
 | 
					 | 
				
			||||||
                    /* hide the mutator */
 | 
					 | 
				
			||||||
                    workspace.getBlockById(controlBlockId).mutator.setVisible(false);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        /* disable right click on Blockly workspace */
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Blockly.Blocks['sumorobot_sleep'] = {
 | 
					 | 
				
			||||||
        init: function() {
 | 
					 | 
				
			||||||
            this.setColour("#E64C00");
 | 
					 | 
				
			||||||
            this.appendDummyInput()
 | 
					 | 
				
			||||||
              .appendField("sleep")
 | 
					 | 
				
			||||||
                .appendField(new Blockly.FieldTextInput('1000',
 | 
					 | 
				
			||||||
                  Blockly.FieldNumber.numberValidator), 'SLEEP');
 | 
					 | 
				
			||||||
            this.setPreviousStatement(true);
 | 
					 | 
				
			||||||
            this.setNextStatement(true);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Blockly.Blocks['sumorobot_move'] = {
 | 
					// Function to get SumoRobot Blockly code
 | 
				
			||||||
        init: function() {
 | 
					Sumorobot.prototype.getBlocklyCode = function() {
 | 
				
			||||||
            var OPERATORS = [
 | 
					    return this.blocklyCode;
 | 
				
			||||||
                ['move stop', 'STOP'],
 | 
					 | 
				
			||||||
                ['move left', 'LEFT'],
 | 
					 | 
				
			||||||
                ['move right', 'RIGHT'],
 | 
					 | 
				
			||||||
                ['move search', 'SEARCH'],
 | 
					 | 
				
			||||||
                ['move forward', 'FORWARD'],
 | 
					 | 
				
			||||||
                ['move backward', 'BACKWARD']
 | 
					 | 
				
			||||||
            ];
 | 
					 | 
				
			||||||
            this.setColour("#E60000");
 | 
					 | 
				
			||||||
            var dropdown = new Blockly.FieldDropdown(OPERATORS);
 | 
					 | 
				
			||||||
            this.appendDummyInput().appendField(dropdown, 'MOVE');
 | 
					 | 
				
			||||||
            this.setPreviousStatement(true);
 | 
					 | 
				
			||||||
            this.setNextStatement(true);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Blockly.Blocks['sumorobot_opponent'] = {
 | 
					// Function to set SumoRobot Blockly code
 | 
				
			||||||
        init: function() {
 | 
					Sumorobot.prototype.setBlocklyCode = function(blocklyCode) {
 | 
				
			||||||
            this.setColour("#0099E6");
 | 
					    this.blocklyCode = blocklyCode;
 | 
				
			||||||
            this.appendDummyInput().appendField('opponent');
 | 
					 | 
				
			||||||
            this.setOutput(true, 'Boolean');
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
    Blockly.Blocks['sumorobot_line'] = {
 | 
					 | 
				
			||||||
        init: function() {
 | 
					 | 
				
			||||||
            var OPERATORS = [
 | 
					 | 
				
			||||||
                ['line left', 'LEFT'],
 | 
					 | 
				
			||||||
                ['line right', 'RIGHT']
 | 
					 | 
				
			||||||
            ];
 | 
					 | 
				
			||||||
            this.setColour("#E6BF00");
 | 
					 | 
				
			||||||
            var dropdown = new Blockly.FieldDropdown(OPERATORS);
 | 
					 | 
				
			||||||
            this.appendDummyInput().appendField(dropdown, 'LINE');
 | 
					 | 
				
			||||||
            this.setOutput(true, 'Boolean');
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Blockly.Python['sumorobot_sleep'] = function(block) {
 | 
					 | 
				
			||||||
        var code = 'sumorobot.sleep(' + parseFloat(block.getFieldValue('SLEEP')) + ', "' + block.id + '")\n';
 | 
					 | 
				
			||||||
        return code;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Blockly.Python['sumorobot_move'] = function(block) {
 | 
					 | 
				
			||||||
        var code = 'sumorobot.move(' + block.getFieldValue('MOVE') + ', "' + block.id + '")\n';
 | 
					 | 
				
			||||||
        return code;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Blockly.Python['sumorobot_opponent'] = function(block) {
 | 
					 | 
				
			||||||
        var code = 'sumorobot.is_opponent("' + block.id + '")';
 | 
					 | 
				
			||||||
        return [code, Blockly.Python.ORDER_ATOMIC];
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Blockly.Python['sumorobot_line'] = function(block) {
 | 
					 | 
				
			||||||
        var code = 'sumorobot.is_line(' + block.getFieldValue('LINE') + ', "' + block.id + '")';
 | 
					 | 
				
			||||||
        return [code, Blockly.Python.ORDER_ATOMIC];
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* inject Blockly */
 | 
					 | 
				
			||||||
    var blocklyArea = document.getElementById('blocklyArea');
 | 
					 | 
				
			||||||
    var blocklyDiv = document.getElementById('blocklyDiv');
 | 
					 | 
				
			||||||
    workspace = Blockly.inject(blocklyDiv, {
 | 
					 | 
				
			||||||
        scrollbars: false,
 | 
					 | 
				
			||||||
        media: 'assets/blockly/media/',
 | 
					 | 
				
			||||||
        trashcan: true,
 | 
					 | 
				
			||||||
        sounds: true,
 | 
					 | 
				
			||||||
        zoom: {
 | 
					 | 
				
			||||||
            wheel: true,
 | 
					 | 
				
			||||||
            controls: true,
 | 
					 | 
				
			||||||
            startScale: 1.2
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        toolbox: document.getElementById('toolbox')
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* on Blockly resize */
 | 
					 | 
				
			||||||
    var onresize = function(e) {
 | 
					 | 
				
			||||||
        // compute the absolute coordinates and dimensions of blocklyArea.
 | 
					 | 
				
			||||||
        var element = blocklyArea;
 | 
					 | 
				
			||||||
        var x = 0;
 | 
					 | 
				
			||||||
        var y = 0;
 | 
					 | 
				
			||||||
        do {
 | 
					 | 
				
			||||||
            x += element.offsetLeft;
 | 
					 | 
				
			||||||
            y += element.offsetTop;
 | 
					 | 
				
			||||||
            element = element.offsetParent;
 | 
					 | 
				
			||||||
        } while (element);
 | 
					 | 
				
			||||||
        /* position blocklyDiv over blocklyArea */
 | 
					 | 
				
			||||||
        blocklyDiv.style.left = x + 'px';
 | 
					 | 
				
			||||||
        blocklyDiv.style.top = y + 'px';
 | 
					 | 
				
			||||||
        blocklyDiv.style.width = blocklyArea.offsetWidth + 'px';
 | 
					 | 
				
			||||||
        blocklyDiv.style.height = blocklyArea.offsetHeight + 'px';
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    window.addEventListener('resize', onresize, false);
 | 
					 | 
				
			||||||
    onresize();
 | 
					 | 
				
			||||||
    Blockly.svgResize(workspace);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* retrieve the blocks */
 | 
					 | 
				
			||||||
    var xml = Blockly.Xml.textToDom(getLocalStorageItem("sumorobot.blockly"));
 | 
					 | 
				
			||||||
    /* resume the blocks */
 | 
					 | 
				
			||||||
    Blockly.Xml.domToWorkspace(xml, workspace);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* on Blockly code change */
 | 
					 | 
				
			||||||
    function onCodeChanged(event) {
 | 
					 | 
				
			||||||
        /* if the if condition block was created */
 | 
					 | 
				
			||||||
        if (event.type == Blockly.Events.CREATE && event.xml.getAttributeNode("type").nodeValue == "controls_if") {
 | 
					 | 
				
			||||||
            /* remember the control_if block id */
 | 
					 | 
				
			||||||
            controlBlockId = event.blockId;
 | 
					 | 
				
			||||||
            /* get the control_if block object */
 | 
					 | 
				
			||||||
            var block = workspace.getBlockById(event.blockId);
 | 
					 | 
				
			||||||
            /* if the control_if block doesn't already have an else */
 | 
					 | 
				
			||||||
            if (block.elseCount_ == 0) {
 | 
					 | 
				
			||||||
                /* automatically add the else statement input */
 | 
					 | 
				
			||||||
                block.elseCount_ = 1;
 | 
					 | 
				
			||||||
                block.updateShape_();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        /* if the if condition block was removed */
 | 
					 | 
				
			||||||
        } else if (event.type == Blockly.Events.DELETE && event.oldXml.getAttributeNode("type").nodeValue == "controls_if") {
 | 
					 | 
				
			||||||
            /* remove the control_if block id */
 | 
					 | 
				
			||||||
            controlBlockId = "";
 | 
					 | 
				
			||||||
            /* enable the if condition block */
 | 
					 | 
				
			||||||
            workspace.updateToolbox(document.getElementById("toolbox"));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* only process change and move commands */
 | 
					 | 
				
			||||||
        if (event.type != Blockly.Events.CHANGE && event.type != Blockly.Events.MOVE) return;
 | 
					 | 
				
			||||||
        /* generate code from the used blocks */
 | 
					 | 
				
			||||||
        sumocode = Blockly.Python.workspaceToCode(workspace);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* show the code in the ace editor, filter out block IDs */
 | 
					 | 
				
			||||||
        readOnlyCodingEditor.setValue("\n" + sumocode.replace(/[,]?[ ]?"(.*?)"/g, ""));
 | 
					 | 
				
			||||||
        readOnlyCodingEditor.clearSelection();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* save the code to the local storage */
 | 
					 | 
				
			||||||
        var xml = Blockly.Xml.workspaceToDom(workspace);
 | 
					 | 
				
			||||||
        localStorage.setItem("sumorobot.blockly", Blockly.Xml.domToText(xml));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* if control_if block is used */
 | 
					 | 
				
			||||||
        if (controlBlockId != "") {
 | 
					 | 
				
			||||||
            /* disable the if condition block */
 | 
					 | 
				
			||||||
            workspace.updateToolbox(document.getElementById("toolbox_no_if"));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* add a change listener to Blockly */
 | 
					 | 
				
			||||||
    workspace.addChangeListener(onCodeChanged);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* key down event */
 | 
					 | 
				
			||||||
    $(document).keydown(function(e) {
 | 
					 | 
				
			||||||
        /* if the hotkeys are disabled or the alt key is not pressed, don't use hotkeys */
 | 
					 | 
				
			||||||
        if (hotkeys == false || e.altKey == false) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* prevent typing in textfields */
 | 
					 | 
				
			||||||
        e.preventDefault();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* select the hotkey */
 | 
					 | 
				
			||||||
        switch(e.which) {
 | 
					 | 
				
			||||||
            case 32: // space bar
 | 
					 | 
				
			||||||
                sumostart = !sumostart;
 | 
					 | 
				
			||||||
                if (sumostart) {
 | 
					 | 
				
			||||||
                    $(".btn-start").addClass("hover");
 | 
					 | 
				
			||||||
                    $(".btn-start").click();
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    $(".btn-stop").addClass("hover");
 | 
					 | 
				
			||||||
                    $(".btn-stop").click();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 37: // left
 | 
					 | 
				
			||||||
                if (remoteControl) sumorobot.send("left");
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 38: // up
 | 
					 | 
				
			||||||
                if (remoteControl) sumorobot.send("forward");
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 39: // right
 | 
					 | 
				
			||||||
                if (remoteControl) sumorobot.send("right");
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 40: // down
 | 
					 | 
				
			||||||
                if (remoteControl) sumorobot.send("backward");
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 67: // c
 | 
					 | 
				
			||||||
                $("#panel").toggle();
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 76: // l
 | 
					 | 
				
			||||||
                /* load the Mixer stream */
 | 
					 | 
				
			||||||
                if ($("#stream").is(':empty')) {
 | 
					 | 
				
			||||||
                    $("#stream").html('<iframe src="https://mixer.com/embed/player/14551694"></iframe>');
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                $("#stream").toggle();
 | 
					 | 
				
			||||||
                /* toggle live steam visible */
 | 
					 | 
				
			||||||
                liveStreamVisible = !liveStreamVisible;
 | 
					 | 
				
			||||||
                /* if not in coding mode */
 | 
					 | 
				
			||||||
                if (codingEnabled == false) {
 | 
					 | 
				
			||||||
                    $("#readOnlyBlocklyCode").toggle();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 80: // p
 | 
					 | 
				
			||||||
                $("#blocklyDiv").toggle();
 | 
					 | 
				
			||||||
                $("#blocklyArea").toggle();
 | 
					 | 
				
			||||||
                $("#blocklyCode").toggle();
 | 
					 | 
				
			||||||
                if (liveStreamVisible == false) {
 | 
					 | 
				
			||||||
                    $("#readOnlyBlocklyCode").toggle();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                /* toggle coding enabled */
 | 
					 | 
				
			||||||
                codingEnabled = !codingEnabled;
 | 
					 | 
				
			||||||
                if (codingEnabled) {
 | 
					 | 
				
			||||||
                    /* resize the coding editor */
 | 
					 | 
				
			||||||
                    codingEditor.resize();
 | 
					 | 
				
			||||||
                    /* focus, so the user can start coding */
 | 
					 | 
				
			||||||
                    codingEditor.focus();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 82: // r
 | 
					 | 
				
			||||||
                /* toggle remote control */
 | 
					 | 
				
			||||||
                remoteControl = !remoteControl;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 83: // s
 | 
					 | 
				
			||||||
                $(".btn-stop").addClass("hover");
 | 
					 | 
				
			||||||
                $(".btn-stop").click();
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 84: // t
 | 
					 | 
				
			||||||
                sumorobot.send("calibrate_line");
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case 87: // w
 | 
					 | 
				
			||||||
                $(".btn-start").addClass("hover");
 | 
					 | 
				
			||||||
                $(".btn-start").click();
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* key up event */
 | 
					 | 
				
			||||||
    $(document).keyup(function(e) {
 | 
					 | 
				
			||||||
        /* if the hotkeys are disabled or the focused element is a textarea or text input, don't use hotkeys */
 | 
					 | 
				
			||||||
        if (hotkeys == false || e.altKey == false) return;
 | 
					 | 
				
			||||||
        /* remove hover from buttons */
 | 
					 | 
				
			||||||
        $('.btn').removeClass('hover');
 | 
					 | 
				
			||||||
        /* if arrow keys */
 | 
					 | 
				
			||||||
        if (e.which == 37 || e.which == 38 || e.which == 39 || e.which == 40) {
 | 
					 | 
				
			||||||
            if (remoteControl) sumorobot.send("stop");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* start button listener */
 | 
					 | 
				
			||||||
    $(".btn-start").click(function() {
 | 
					 | 
				
			||||||
        sumostart = true;
 | 
					 | 
				
			||||||
        /* if we are in coding mode */
 | 
					 | 
				
			||||||
        if (codingEnabled) {
 | 
					 | 
				
			||||||
            /* send the code from the textarea to the SumoRobot */
 | 
					 | 
				
			||||||
            sumorobot.send('{"to": "sumo-' + robotId + '@00000514", "cmd": "code", "val": "' + codingEditor.getValue() + '"}');
 | 
					 | 
				
			||||||
        /* otherwise when we are in Blockly mode */
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            /* send the code from the blocks to the SumoRobot */
 | 
					 | 
				
			||||||
            sumorobot.send('{"to": "sumo-' + robotId + '@00000514", "cmd": "code", "val": "' + sumocode + '"}');
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* stop button listener */
 | 
					 | 
				
			||||||
    $(".btn-stop").click(function() {
 | 
					 | 
				
			||||||
        sumostart = false;
 | 
					 | 
				
			||||||
        sumorobot.send('{"to": "sumo-' + robotId + '@00000514", "cmd": "stop"}');
 | 
					 | 
				
			||||||
        workspace.highlightBlock(lastHighlighted, false);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* enter listener on robot ID field */
 | 
					 | 
				
			||||||
    $("#robot-id").keypress(function(e) {
 | 
					 | 
				
			||||||
        if (e.which == 13) {
 | 
					 | 
				
			||||||
            /* simulate robot GO button click */
 | 
					 | 
				
			||||||
            $(".btn-robot-go").click();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* robot number button listener */
 | 
					 | 
				
			||||||
    $(".btn-robot-go").click(function() {
 | 
					 | 
				
			||||||
        /* extract and validate the selected robot ID */
 | 
					 | 
				
			||||||
        robotId = $("#robot-id").val().trim();
 | 
					 | 
				
			||||||
        if (robotId === "" || /^([a-f0-9]{6})$/.test(robotId) == false) {
 | 
					 | 
				
			||||||
            $("#robot-id, #robot-label").addClass("has-error");
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            $("#robot-id, #robot-label").removeClass("has-error");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        /* update robot IDs in local storage */
 | 
					 | 
				
			||||||
        setLocalStorageItem("sumorobot.robotId", robotId);
 | 
					 | 
				
			||||||
        /* in case there is a open connection */
 | 
					 | 
				
			||||||
        if (sumorobot/* && blockHighlight*/) {
 | 
					 | 
				
			||||||
            /* close the connections */
 | 
					 | 
				
			||||||
            sumorobot.close();
 | 
					 | 
				
			||||||
            //blockHighlight.close();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        /* connect to the selected robots WebSocket */
 | 
					 | 
				
			||||||
        sumorobot = new Sumorobot("ws://" + robotServer);
 | 
					 | 
				
			||||||
        /* connect to the other block highlight WebSocket */
 | 
					 | 
				
			||||||
        /*blockHighlight = new WebSocket("ws://" + robotServer + ":80/p2p/browser/" + robotId + "-highlight/");
 | 
					 | 
				
			||||||
        // when there is a message from the WebSocket
 | 
					 | 
				
			||||||
        blockHighlight.onmessage = function(evt) {
 | 
					 | 
				
			||||||
            // when scope is received
 | 
					 | 
				
			||||||
            if (evt.data.length == 20 && sumostart) {
 | 
					 | 
				
			||||||
                workspace.highlightBlock(evt.data);
 | 
					 | 
				
			||||||
                lastHighlighted = evt.data;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        };*/
 | 
					 | 
				
			||||||
        /* hide the configuration panel */
 | 
					 | 
				
			||||||
        $("#panel").hide();
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* set a click listener on the document */
 | 
					 | 
				
			||||||
    $(document).click(function(e) {
 | 
					 | 
				
			||||||
        var target = e.target;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* when control_if block is in use */
 | 
					 | 
				
			||||||
        if (controlBlockId != "") {
 | 
					 | 
				
			||||||
            /* when the user clicks anywhere outside the mutator and not on the mutator icon */
 | 
					 | 
				
			||||||
            if (!$(target).is('.blocklyBubbleCanvas') && !$(target).parents().is('.blocklyBubbleCanvas')) {
 | 
					 | 
				
			||||||
                if (!$(target).is('.blocklyIconGroup') && !$(target).parents().is('.blocklyIconGroup')) {
 | 
					 | 
				
			||||||
                    /* hide the mutator */
 | 
					 | 
				
			||||||
                    workspace.getBlockById(controlBlockId).mutator.setVisible(false);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user