diff --git a/index.html b/index.html index 8e23c0e..d0f7b48 100644 --- a/index.html +++ b/index.html @@ -48,10 +48,14 @@ Subnet Mask: - . - . - . -   +
+ + . + . + . +   + +
WX modules: diff --git a/index.js b/index.js index 6c277ba..41384c4 100644 --- a/index.js +++ b/index.js @@ -1,10 +1,5 @@ /* Copyright (c) 2019 Parallax Inc., All Rights Reserved. */ - -// TODO: allow user to change port and server IP/addr. Feilds and button are there, but no supporting code. -// TODO: update bkg img to include S3 robot. -// TODO: Add all linking messages/data for the BlocklyProp site via the websocket connection. - // jQuery-like convience ;) function $(id) { return document.getElementById(id); @@ -14,6 +9,20 @@ function $(id) { const initialBaudrate = 115200; //Initial Propeller communication baud rate (standard boot loader) const finalBaudrate = 921600; //Final Propeller communication baud rate (Micro Boot Loader) +// Defaults +const defaultPort = '6009'; +const defaultURL = 'localhost'; +const defaultSM0 = '255'; +const defaultSM1 = '255'; +const defaultSM2 = '255'; +const defaultSM3 = '0'; +const defaultWX = true; + +// Communication metrics (ensure intervals don't coincide) +const portListSendInterval = 5000; +const wDiscoverInterval = 6100; +const wxDiscoverInterval = 3500; + // Messaging types // These classify messages sent to log() to be routed to one or more destinations (browser dialog, app log, or app/browser console). // The intention is that such messages can be later filtered via options set in the app itself to make debugging easier. @@ -43,15 +52,15 @@ function log(text = "", type = mStat, socket = null) { text is the message to convey. type is an optional category and destination(s) that the message applies too; defaults to mStat (log status). socket is the websocket to send an mUser message to; ignored unless message is an mcUser category.*/ - if (type & (mcUser | mcStatus | mcVerbose)) { - // Deliver categorized message to proper destination - if ((type & mdDisplay) && socket !== null) { - let dispText = text !== "." ? '\r' + text : text; - socket.send(JSON.stringify({type:'ui-command', action:'message-compile', msg:dispText})) - } - if (type & mdLog) {$('log').innerHTML += text + '
'} - if (type & mdConsole) {console.log(Date.now().toString().slice(-5) + ': ' + text)} - } + if (type & (mcUser | mcStatus | mcVerbose)) { + // Deliver categorized message to proper destination + if ((type & mdDisplay) && socket !== null) { + let dispText = text !== "." ? '\r' + text : text; + socket.send(JSON.stringify({type:'ui-command', action:'message-compile', msg:dispText})) + } + if (type & mdLog) {$('log').innerHTML += text + '
'} + if (type & mdConsole) {console.log(Date.now().toString().slice(-5) + ': ' + text)} + } } function isJson(str) { @@ -92,159 +101,183 @@ var isServer = false; var wScannerInterval = null; var portLister = []; +// Timer to manage possible disableWX/enableWX cycling (resetWX) +var wxEnableDelay = null; + // Is verbose loggin turned on? var verboseLogging = false; document.addEventListener('DOMContentLoaded', function() { - $('version-text').innerHTML = 'v'+clientVersion; + // Previous subnet mask (for future comparison) + var sm = null; - // Determine platform - chrome.runtime.getPlatformInfo(function(platformInfo) { - if (!chrome.runtime.lastError) { - let os = platformInfo.os; - platform = (os === "cros" ? pfChr : (os === "linux" ? pfLin : (os === "mac" ? pfMac : (os === "win" ? pfWin : pfUnk)))); - } - }); - - // Restore settings from storage (if possible) - if(chrome.storage) { - chrome.storage.sync.get('s_port', function(result) {$('bpc-port').value = result.s_port || '6009';}); - chrome.storage.sync.get('s_url', function(result) {$('bpc-url').value = result.s_url || 'localhost';}); - chrome.storage.sync.get('sm0', function(result) {$('sm0').value = result.sm0 || '255';}); - chrome.storage.sync.get('sm1', function(result) {$('sm1').value = result.sm1 || '255';}); - chrome.storage.sync.get('sm2', function(result) {$('sm2').value = result.sm2 || '255';}); - chrome.storage.sync.get('sm3', function(result) {$('sm3').value = result.sm3 || '0';}); - chrome.storage.sync.get('en_wx', function(result) {$('wx-allow').checked = (result.en_wx !== undefined) ? result.en_wx : true;}); - } else { - $('bpc-port').value = '6009'; - $('bpc-url').value = 'localhost'; - $('sm0').value = '255'; - $('sm1').value = '255'; - $('sm2').value = '255'; - $('sm3').value = '0'; - $('wx-allow').checked = true; - } + $('version-text').innerHTML = 'v'+clientVersion; - $('open-browser').onclick = function() { - chrome.browser.openTab({ url: "https://blockly.parallax.com/"}); - }; - - // TODO: re-write this to use onblur and/or onchange to auto-save. - $('refresh-connection').onclick = function() { - disconnect(); - closeServer(); + // Determine platform + chrome.runtime.getPlatformInfo(function(platformInfo) { + if (!chrome.runtime.lastError) { + let os = platformInfo.os; + platform = (os === "cros" ? pfChr : (os === "linux" ? pfLin : (os === "mac" ? pfMac : (os === "win" ? pfWin : pfUnk)))); + } + }); + + // Restore settings from storage (if possible) if(chrome.storage) { - chrome.storage.sync.set({'s_port':$('bpc-port').value}, function() {}); - chrome.storage.sync.set({'s_url':$('bpc-url').value}, function() {}); + chrome.storage.sync.get(null, function(result) { + if (!chrome.runtime.lastError) { + // Stored values retrieved + $('bpc-port').value = result.s_port || defaultPort; + $('bpc-url').value = result.s_url || defaultURL; + $('sm0').value = result.sm0 || defaultSM0; + $('sm1').value = result.sm1 || defaultSM1; + $('sm2').value = result.sm2 || defaultSM2; + $('sm3').value = result.sm3 || defaultSM3; + $('wx-allow').checked = (result.en_wx !== undefined) ? result.en_wx : defaultWX; + // Save subnet mask for future comparison (must be done here because chrome.storage.sync is asynchronous) + sm = sm32bit(); + } else { + storageError(); + } + }) + } else { + $('bpc-port').value = defaultPort; + $('bpc-url').value = defaultURL; + $('sm0').value = defaultSM0; + $('sm1').value = defaultSM1; + $('sm2').value = defaultSM2; + $('sm3').value = defaultSM3; + $('wx-allow').checked = defaultWX; + // Save subnet mask for future comparison + sm = sm32bit(); } - connect(); - }; - // Save netmask changes to storage (if possible) - if (chrome.storage) { - $('sm0').onblur = function() { - chrome.storage.sync.set({'sm0': $('sm0').value}, function () {}); - } - $('sm1').onblur = function() { - chrome.storage.sync.set({'sm1': $('sm1').value}, function () {}); - } - $('sm2').onblur = function() { - chrome.storage.sync.set({'sm2': $('sm2').value}, function () {}); + $('open-browser').onclick = function() { + chrome.browser.openTab({ url: "https://blockly.parallax.com/"}); + }; + + // TODO: re-write this to use onblur and/or onchange to auto-save. + $('refresh-connection').onclick = function() { + disconnect(); + closeServer(); + if(chrome.storage) { + chrome.storage.sync.set({'s_port':$('bpc-port').value, 's_url':$('bpc-url').value}, function() {if (chrome.runtime.lastError) {storageError()}}); } - $('sm3').onblur = function() { - chrome.storage.sync.set({'sm3': $('sm3').value}, function () {}); + connect(); + }; + + $('netmask').addEventListener("blur", function() { + if (sm32bit() !== sm) { + // Subnet mask changed; retain new mask (for future comparison) and re-discover WX + sm = sm32bit(); + if (chrome.storage) { + // Storage available + chrome.storage.sync.set({'sm0':$('sm0').value, 'sm1':$('sm1').value, 'sm2':$('sm2').value, 'sm3':$('sm3').value}, function () { + if (chrome.runtime.lastError) {storageError()} + }) + } + resetWX(); } - } + }, true); - $('open-settings').onclick = function() { - if($('settings-pane').style.top !== '10px') { - setTimeout(function() {$('version-text').style.visibility = 'hidden'}, 200); - $('settings-pane').style.top = '10px'; - $('open-settings').className = 'button settings-active'; - } else { - setTimeout(function() {$('version-text').style.visibility = 'visible'}, 350); - $('settings-pane').style.top = '550px'; - $('open-settings').className = 'button settings'; - } - }; + $('open-settings').onclick = function() { + if($('settings-pane').style.top !== '10px') { + setTimeout(function() {$('version-text').style.visibility = 'hidden'}, 200); + $('settings-pane').style.top = '10px'; + $('open-settings').className = 'button settings-active'; + } else { + setTimeout(function() {$('version-text').style.visibility = 'visible'}, 350); + $('settings-pane').style.top = '550px'; + $('open-settings').className = 'button settings'; + } + }; - $('bpc-trace').onclick = function() { - verboseLogging = $('bpc-trace').checked; - }; - - // Enable/disable wireless (WX) port scanning; save setting - $('wx-allow').onclick = function() { - if($('wx-allow').checked) { - enableWX(); - } else { - disableWX(); - } - if(chrome.storage) { - chrome.storage.sync.set({'en_wx': $('wx-allow').checked}, function () {}); - } - }; - - $('wmt').onclick = function() { - if($('wx-module-tab').className === 'tab-unselect tab-right') { - $('wx-module-tab').className = 'tab-selected tab-right'; - $('port-path-tab').className = 'tab-unselect tab-left'; - $('wx-module-settings').style.visibility = 'visible'; - $('port-path-settings').style.visibility = 'hidden'; - $('sep-right').style.visibility = 'visible'; - $('sep-left').style.visibility = 'hidden'; - $('cor-left').style.visibility = 'visible'; - $('cor-right').style.visibility = 'hidden'; - } - }; - - $('ppt').onclick = function() { - if($('port-path-tab').className === 'tab-unselect tab-left') { - $('wx-module-tab').className = 'tab-unselect tab-right'; - $('port-path-tab').className = 'tab-selected tab-left'; - $('wx-module-settings').style.visibility = 'hidden'; - $('port-path-settings').style.visibility = 'visible'; - $('sep-left').style.visibility = 'visible'; - $('sep-right').style.visibility = 'hidden'; - $('cor-right').style.visibility = 'visible'; - $('cor-left').style.visibility = 'hidden'; - } - }; + $('bpc-trace').onclick = function() { + verboseLogging = $('bpc-trace').checked; + }; + + // Enable/disable wireless (WX) port scanning; save setting + $('wx-allow').onclick = function() { + if($('wx-allow').checked) { + enableWX(); + } else { + disableWX(); + } + if(chrome.storage) { + chrome.storage.sync.set({'en_wx': $('wx-allow').checked}, function () {if (chrome.runtime.lastError) {storageError()}}); + } + }; + + $('wmt').onclick = function() { + if($('wx-module-tab').className === 'tab-unselect tab-right') { + $('wx-module-tab').className = 'tab-selected tab-right'; + $('port-path-tab').className = 'tab-unselect tab-left'; + $('wx-module-settings').style.visibility = 'visible'; + $('port-path-settings').style.visibility = 'hidden'; + $('sep-right').style.visibility = 'visible'; + $('sep-left').style.visibility = 'hidden'; + $('cor-left').style.visibility = 'visible'; + $('cor-right').style.visibility = 'hidden'; + } + }; + + $('ppt').onclick = function() { + if($('port-path-tab').className === 'tab-unselect tab-left') { + $('wx-module-tab').className = 'tab-unselect tab-right'; + $('port-path-tab').className = 'tab-selected tab-left'; + $('wx-module-settings').style.visibility = 'hidden'; + $('port-path-settings').style.visibility = 'visible'; + $('sep-left').style.visibility = 'visible'; + $('sep-right').style.visibility = 'hidden'; + $('cor-right').style.visibility = 'visible'; + $('cor-left').style.visibility = 'hidden'; + } + }; - //Connect automatically upon opening - setTimeout(connect, 500); + //Connect automatically upon opening + setTimeout(connect, 500); }); +function sm32bit() { +// Convert current subnet mask (string form) to a 32-bit (4-byte) value + return (parseInt($('sm0').value) << 24) + (parseInt($('sm1').value) << 16) + (parseInt($('sm2').value) << 8) + parseInt($('sm3').value); +} + +function storageError() { +// Log Chrome Storage error + log("Settings Error: " + chrome.runtime.lastError, mDbug); +} + function connect() { - //Connect via websocket to browser and enable wired and wireless port scanning +//Connect via websocket to browser and enable wired and wireless port scanning connect_ws($('bpc-port').value, $('bpc-url').value); enableW(); enableWX(); } function disconnect() { - //Disconnect from browser and disable wired and wireless port scanning +//Disconnect from browser and disable wired and wireless port scanning closeSockets(); disableW(); disableWX(); } function updateStatus(connected) { - if (connected) { - $('sys-waiting').style.opacity=0.0; - $('sys-connected').style.opacity=1.0; - log('BlocklyProp site connected'); - } else { - $('sys-waiting').style.opacity=1.0; - $('sys-connected').style.opacity=0.0; - log('BlocklyProp site disconnected'); - } + if (connected) { + $('sys-waiting').style.opacity=0.0; + $('sys-connected').style.opacity=1.0; + log('BlocklyProp site connected'); + } else { + $('sys-waiting').style.opacity=1.0; + $('sys-connected').style.opacity=0.0; + log('BlocklyProp site disconnected'); + } } function closeServer() { - wsServer.removeEventListener('request'); - server.close(); - isServer = false; + wsServer.removeEventListener('request'); + server.close(); + isServer = false; } function closeSockets() { @@ -261,81 +294,81 @@ function closeSockets() { } function connect_ws(ws_port, url_path) { - var port = parseInt(ws_port); //6010; -// commented out unused variable - if (http.Server && http.WebSocketServer && !isServer) { - // Listen for HTTP connections. - server.listen(port); - isServer = true; - - wsServer.addEventListener('request', function(req) { - var socket = req.accept(); - - socket.addEventListener('message', function(e) { - if (isJson(e.data)) { - var ws_msg = JSON.parse(e.data); - //Note: ws.msg.portPath is now really a "pathless" portName but kept named as-is for legacy support - // load the propeller - if (ws_msg.type === "load-prop") { - log('Received Propeller Application for ' + ws_msg.action); - setTimeout(function() {loadPropeller(socket, ws_msg.portPath, ws_msg.action, ws_msg.payload, ws_msg.debug)}, 10); // success is a JSON that the browser generates and expects back to know if the load was successful or not - // open or close the serial port for terminal/debug - } else if (ws_msg.type === "serial-terminal") { - serialTerminal(socket, ws_msg.action, ws_msg.portPath, ws_msg.baudrate, ws_msg.msg); // action is "open", "close" or "msg" - // send an updated port list - } else if (ws_msg.type === "port-list-request") { - // Send port list now and set up scanner to send port list on regular interval -// log("Browser requested port-list for socket " + socket.pSocket_.socketId, mDbug); - sendPortList(socket); - let s = setInterval(function() {sendPortList(socket)}, 5000); - portLister.push({socket: socket, scanner: s}); - // Handle unknown messages - } else if (ws_msg.type === "hello-browser") { - helloClient(socket, ws_msg.baudrate || 115200); - updateStatus(true); - // Handle clear-to-send - } else if (ws_msg.type === "debug-cts") { - //TODO Add clear-to-send handling code - // Handle unknown messages - } else { - log('Unknown JSON message: ' + e.data); - } - } else { - log('Unknown message type: ' + e.data); - } - }); + var port = parseInt(ws_port); - - // Browser socket closed; terminate its port scans and remove it from list of ports. - socket.addEventListener('close', function() { - log("Browser socket closing: " + socket.pSocket_.socketId, mDbug); - let Idx = portLister.findIndex(function(s) {return s.socket === socket}); - if (Idx > -1) { - clearInterval(portLister[Idx].scanner); - portLister.splice(Idx, 1); - } - ports.forEach(function(p) {if (p.bSocket === socket) {p.bSocket = null}}); - if (!portLister.length) { - updateStatus(false); - // chrome.app.window.current().drawAttention(); //Disabled to prevent unnecessary user interruption - } - }); - - return true; + if (http.Server && http.WebSocketServer && !isServer) { + // Listen for HTTP connections. + server.listen(port); + isServer = true; + + wsServer.addEventListener('request', function(req) { + var socket = req.accept(); + + socket.addEventListener('message', function(e) { + if (isJson(e.data)) { + var ws_msg = JSON.parse(e.data); + //Note: ws.msg.portPath is now really a "pathless" portName but kept named as-is for legacy support + + if (ws_msg.type === "load-prop") { + // load the propeller + log('Received Propeller Application for ' + ws_msg.action); + setTimeout(function() {loadPropeller(socket, ws_msg.portPath, ws_msg.action, ws_msg.payload, ws_msg.debug)}, 10); // success is a JSON that the browser generates and expects back to know if the load was successful or not + } else if (ws_msg.type === "serial-terminal") { + // open or close the serial port for terminal/debug + serialTerminal(socket, ws_msg.action, ws_msg.portPath, ws_msg.baudrate, ws_msg.msg); // action is "open", "close" or "msg" + } else if (ws_msg.type === "port-list-request") { + // send an updated port list (and continue on scheduled interval) +// log("Browser requested port-list for socket " + socket.pSocket_.socketId, mDbug); + sendPortList(socket); + portLister.push({socket: socket, scanner: setInterval(function() {sendPortList(socket)}, portListSendInterval)}); + } else if (ws_msg.type === "hello-browser") { + // handle unknown messages + helloClient(socket, ws_msg.baudrate || 115200); + updateStatus(true); + } else if (ws_msg.type === "debug-cts") { + // Handle clear-to-send + //TODO Add clear-to-send handling code + } else { + // Handle unknown messages + log('Unknown JSON message: ' + e.data); + } + } else { + // Handle unknown format + log('Unknown message type: ' + e.data); + } + }); + + + socket.addEventListener('close', function() { + // Browser socket closed; terminate its port scans and remove it from list of ports. + log("Browser socket closing: " + socket.pSocket_.socketId, mDbug); + let Idx = portLister.findIndex(function(s) {return s.socket === socket}); + if (Idx > -1) { + clearInterval(portLister[Idx].scanner); + portLister.splice(Idx, 1); + } + ports.forEach(function(p) {if (p.bSocket === socket) {p.bSocket = null}}); + if (!portLister.length) { + updateStatus(false); + // chrome.app.window.current().drawAttention(); //Disabled to prevent unnecessary user interruption + } + }); + + return true; }); } } function enableW() { - //Enable periodic wired port scanning +//Enable periodic wired port scanning if (!wScannerInterval) { scanWPorts(); - wScannerInterval = setInterval(scanWPorts, 6010); // 6010: Scan at different intervals than send processes + wScannerInterval = setInterval(scanWPorts, wDiscoverInterval); } } function disableW() { - //Disable wired port scanning +//Disable wired port scanning if(wScannerInterval) { clearInterval(wScannerInterval); wScannerInterval = null; @@ -343,17 +376,21 @@ function disableW() { } function enableWX() { - //Enable periodic wireless port scanning (if allowed) +//Enable periodic wireless port scanning (if allowed) + if (wxEnableDelay) { // Clear WX Enable delay, if any + clearInterval(wxEnableDelay); + wxEnableDelay = null; + } if ($('wx-allow').checked) { if (!wxScannerInterval) { scanWXPorts(); - wxScannerInterval = setInterval(scanWXPorts, 3500); + wxScannerInterval = setInterval(scanWXPorts, wxDiscoverInterval); } } } function disableWX() { - //Disable wireless port scanning +//Disable wireless port scanning if(wxScannerInterval) { clearInterval(wxScannerInterval); wxScannerInterval = null; @@ -362,6 +399,12 @@ function disableWX() { deleteAllWirelessPorts(); } +function resetWX() { +//Cycle WX scanning (off, then on again after delay to receive and clear possible in-progress responses) + disableWX(); + wxEnableDelay = setTimeout(enableWX, 500); +} + function scanWPorts() { // Generate list of current wired ports (filtered according to platform and type) chrome.serial.getDevices( @@ -402,62 +445,62 @@ function sendPortList(socket) { var msg_to_send = {type:'port-list',ports:wn.concat(wln)}; socket.send(JSON.stringify(msg_to_send)); if (chrome.runtime.lastError) { - console.log(chrome.runtime.lastError); - } + log(chrome.runtime.lastError, mDbug); + } } function helloClient(sock, baudrate) { - var msg_to_send = {type:'hello-client', version:clientVersion}; - sock.send(JSON.stringify(msg_to_send)); + var msg_to_send = {type:'hello-client', version:clientVersion}; + sock.send(JSON.stringify(msg_to_send)); } //TODO Check send results and act accordingly? //TODO refactor to combine usb and wx-based port code efficiently function serialTerminal(sock, action, portName, baudrate, msg) { - // Find port from portName - let port = findPort(byName, portName); - if (port) { - // Convert msg from string or buffer to an ArrayBuffer - if (typeof msg === 'string') { - msg = str2ab(msg); - } else { - if (msg instanceof ArrayBuffer === false) {msg = buf2ab(msg);} - } - if (action === "open") { - // Open port for terminal use - openPort(sock, port.name, baudrate, 'debug') - .then(function() {log('Connected terminal to ' + portName + ' at ' + baudrate + ' baud.');}) - .catch(function() { - log('Unable to connect terminal to ' + portName); - var msg_to_send = {type:'serial-terminal', msg:'Failed to connect.\rPlease close this terminal and select a connected port.'}; - sock.send(JSON.stringify(msg_to_send)); - }); - } else if (action === "close") { - /* Terminal closed. Keep wired port open because chrome.serial always toggles DTR upon closing (resetting the Propeller) which causes +// Find port from portName + let port = findPort(byName, portName); + if (port) { + // Convert msg from string or buffer to an ArrayBuffer + if (typeof msg === 'string') { + msg = str2ab(msg); + } else { + if (msg instanceof ArrayBuffer === false) {msg = buf2ab(msg);} + } + if (action === "open") { + // Open port for terminal use + openPort(sock, port.name, baudrate, 'debug') + .then(function() {log('Connected terminal to ' + portName + ' at ' + baudrate + ' baud.');}) + .catch(function() { + log('Unable to connect terminal to ' + portName); + var msg_to_send = {type:'serial-terminal', msg:'Failed to connect.\rPlease close this terminal and select a connected port.'}; + sock.send(JSON.stringify(msg_to_send)); + }); + } else if (action === "close") { + /* Terminal closed. Keep wired port open because chrome.serial always toggles DTR upon closing (resetting the Propeller) which causes lots of unnecessary confusion (especially if an older version of the user's app is in the Propeller's EEPROM). Instead, update the connection mode so that serial debug data halts.*/ - port.mode = 'none'; - } else if (action === "msg") { - // Message to send to the Propeller - if ((port.isWired && port.connId) || (port.isWireless && port.ptSocket)) { //Send only if port is open - send(port, msg, false); - } - } - } else { - var msg_to_send = {type:'serial-terminal', msg:'Port ' + portName + ' not found.\rPlease close this terminal and select an existing port.'}; - sock.send(JSON.stringify(msg_to_send)); - } + port.mode = 'none'; + } else if (action === "msg") { + // Message to send to the Propeller + if ((port.isWired && port.connId) || (port.isWireless && port.ptSocket)) { //Send only if port is open + send(port, msg, false); + } + } + } else { + var msg_to_send = {type:'serial-terminal', msg:'Port ' + portName + ' not found.\rPlease close this terminal and select an existing port.'}; + sock.send(JSON.stringify(msg_to_send)); + } } var ab2str = function(buf) { // Convert ArrayBuffer to String - var bufView = new Uint8Array(buf); - var unis = []; - for (var i = 0; i < bufView.length; i++) { - unis.push(bufView[i]); - } - return String.fromCharCode.apply(null, unis); + var bufView = new Uint8Array(buf); + var unis = []; + for (var i = 0; i < bufView.length; i++) { + unis.push(bufView[i]); + } + return String.fromCharCode.apply(null, unis); }; var str2ab = function(str, len = null) { @@ -485,26 +528,26 @@ var buf2ab = function (buffer) { var str2buf = function(str) { // Convert str to buffer - var buf = new ArrayBuffer(str.length); - var bufView = new Uint8Array(buf); - for (var i = 0; i < str.length; i++) { - bufView[i] = str.charCodeAt(i); - } - return bufView; + var buf = new ArrayBuffer(str.length); + var bufView = new Uint8Array(buf); + for (var i = 0; i < str.length; i++) { + bufView[i] = str.charCodeAt(i); + } + return bufView; }; function isNumber(n) { - return !isNaN(parseFloat(n)) && isFinite(n); + return !isNaN(parseFloat(n)) && isFinite(n); } // calculate the checksum of a Propeller program image: function checksumArray(arr, l) { - if (!l) l = arr.length; - var chksm = 236; - for (var a = 0; a < l; a++) { - chksm = arr[a] + chksm; - } - chksm = (256 - chksm) & 255; - return chksm; + if (!l) l = arr.length; + var chksm = 236; + for (var a = 0; a < l; a++) { + chksm = arr[a] + chksm; + } + chksm = (256 - chksm) & 255; + return chksm; } diff --git a/manifest.json b/manifest.json index 74ef375..29b2d9f 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "name": "BlocklyProp Launcher", "description": "A Chrome application that connects your Propeller-Powered Hardware to the BlocklyProp website.", - "version": "0.9.9", + "version": "0.10.0", "manifest_version": 2, "minimum_chrome_version": "45", diff --git a/package/blocklyproplauncher-installer.iss b/package/blocklyproplauncher-installer.iss index cb1a2a3..dbb965c 100644 --- a/package/blocklyproplauncher-installer.iss +++ b/package/blocklyproplauncher-installer.iss @@ -3,7 +3,7 @@ #define MyAppName "BlocklyProp Launcher" #define MyAppStartMenuName "BlocklyProp" -#define MyAppVersion "0.9.9" +#define MyAppVersion "0.10.0" #define MyAppPublisher "Parallax Inc." #define MyAppStartMenu "Parallax Inc" #define MyAppURL "http://blockly.parallax.com/" diff --git a/port.js b/port.js index 0ee919e..2ab5043 100644 --- a/port.js +++ b/port.js @@ -61,7 +61,7 @@ function addPort(alist) { updatePort(port, alist); } else { // else, add it as a new port record (all fields included; many with default values to be updated later) - log("Adding port: " + alist.path, mDbug); + log("Found port: " + alist.path, mDbug); ports.push({ name : makePortName(alist.path), /*[<>""] Friendly port name; never empty, does not include path*/ path : alist.path, /*[<>""] Wired port path+name, or wireless port's custom name, or fabricated name; never empty*/ @@ -183,7 +183,7 @@ function deletePort(type, clue) { byName / alphanumeric name (wired/wireless port identifier)*/ let idx = findPortIdx(type, clue); if (idx > -1) { - log("Deleting port: " + ports[idx].path, mDbug); + log("Removed port: " + ports[idx].path, mDbug); ports.splice(idx, 1); } } \ No newline at end of file diff --git a/wx.js b/wx.js index 13818de..67d4e01 100644 --- a/wx.js +++ b/wx.js @@ -28,8 +28,8 @@ function calcBroadcastAddr(mip) { function ip32bit(mip) { // convert an IP address to a single 32-bit (4-byte) chunk return String.fromCharCode(parseInt(mip[0])) + - String.fromCharCode(parseInt(mip[1])) + - String.fromCharCode(parseInt(mip[2])) + + String.fromCharCode(parseInt(mip[1])) + + String.fromCharCode(parseInt(mip[2])) + String.fromCharCode(parseInt(mip[3])); } @@ -108,9 +108,12 @@ document.addEventListener('DOMContentLoaded', function() { // Add found Wi-Fi Module's IP to the packet to prevent responses to subsequent packets. //!!! Need to reconsider this global operation disc_packet += ip32bit(ip.split('.')); - // Add (or update) it's port record; limit name to 32 characters without leading/trailing whitespace - addPort({path: wx_info.name.substr(0,32).replace(/(^\s+|\s+$)/g,''), mac: mac, ip: ip}); - displayWirelessPorts(); + // If allowed, add (or update) it's port record; limit name to 32 characters without leading/trailing whitespace + // Note: WX support could have been turned off during discovery operation- thus responses may arrive after communication was willfully ended + if ($('wx-allow').checked) { + addPort({path: wx_info.name.substr(0,32).replace(/(^\s+|\s+$)/g,''), mac: mac, ip: ip}); + displayWirelessPorts(); + } }); });