diff --git a/loader.js b/loader.js index 9303219..d2330eb 100644 --- a/loader.js +++ b/loader.js @@ -17,7 +17,7 @@ // Programming metrics let postResetDelay = null; //Delay after reset and before serial stream; Post-Reset Delay is set by loadPropeller() -let autoAdjust = 20; //Amount to adjust postResetDelay upon each failure +let autoAdjust = 30; //Amount to adjust postResetDelay upon each failure let txData; //Data to transmit to the Propeller (size/contents created later) const defaultClockSpeed = 80000000; @@ -140,17 +140,21 @@ function loadPropeller(sock, portPath, action, payload, debug) { //Set postResetDelay based on platform; ideal Post-Reset Delay = 100 ms; adjust downward according to typically-busy operating systems postResetDelay = (platform === pfWin) ? 60 : 100; if (port.connId) { - // Connection exists, prep to reuse it - originalBaudrate = port.baud; - updatePort(port, {mode: "programming", bSocket: sock}); - connect = function() {return changeBaudrate(port, initialBaudrate)} + // Connection exists, prep to close it first (to reset it), then open it (fresh) + originalBaudrate = initialBaudrate; + connect = function() {return closePort(port).then(function() {return openPort(sock, portPath, initialBaudrate, "programming")}).catch(function(e) {return Promise.reject(e)})} +// The following temporarily removed (and replaced above) to intentionally close and reopen port in hopes it eliminates the CrOS v67+ failed download problem +// // Connection exists, prep to reuse it +// originalBaudrate = port.baud; +// updatePort(port, {mode: "programming", bSocket: sock}); +// connect = function() {return changeBaudrate(port, initialBaudrate)} } else { // No connection yet, prep to create one originalBaudrate = initialBaudrate; connect = function() {return openPort(sock, portPath, initialBaudrate, "programming")} } } else { - //Virtually-clear postResetDelay (it's controlled by wireless device) + //Nearly-clear the postResetDelay (it's controlled by wireless device) postResetDelay = 1; //TODO Retrieve actual current baudrate originalBaudrate = initialBaudrate; @@ -180,9 +184,11 @@ function loadPropeller(sock, portPath, action, payload, debug) { log(e.message, mAll, sock); log(notice(neDownloadFailed), mAll, sock); updatePort(port, {mode: "none"}); - if ((port.isWired && port.connId) || port.isWireless) {changeBaudrate(port, originalBaudrate)} - if (port.isWireless) {closePort(port, false)} - }); + if ((port.isWired && port.connId) || port.isWireless) {return changeBaudrate(port, originalBaudrate)} + }) + .catch(function(e) {log(e.message, mAll, sock)}) + .then(function() {if (port.isWireless) return closePort(port, false)}) + .catch(function(e) {log(e.message, mAll, sock);}); } else { // Port not found log(notice(neCanNotFindPort, [portPath]), mAll, sock); @@ -304,7 +310,9 @@ function talkToProp(sock, port, binImage, toEEPROM) { .catch(function(e) { //Error! if (noticeCode(e.message) === nePropellerNotFound && --attempts) { // Retry (if "Propeller not found" and more attempts available) log("Propeller not found: retrying...", mDeep); - postResetDelay = Math.max(postResetDelay - autoAdjust, 1); // Shorten Post Reset Delay upon every attempt (min 1) + if (platform === pfWin) { // If Windows platform, + postResetDelay = Math.max(postResetDelay - autoAdjust, 1); // Shorten Post Reset Delay upon every attempt (min 1) + } return sendLoader(); // note: sendLoader does not return execution below (promises continue at next .then/.catch) } return reject(e); // Or if other error (or out of retry attempts), reject with message @@ -429,15 +437,15 @@ function talkToProp(sock, port, binImage, toEEPROM) { var next; /* Calculate expected Micro Boot Loader and User Application delivery times - = 300 [>max post-reset-delay] + ((10 [bits per byte] * (data bytes [transmitting] + 20 silence bytes [MBL waiting] + 8 MBL "ready" bytes [MBL responding])) / - initial baud rate) * 1,000 [to scale ms to integer] + 1 [to always round up] + 500 [Rx hardware to OS slack time] */ - var mblDeliveryTime = 300+((10*(txData.byteLength+20+8))/initialBaudrate)*1000+1 + (port.isWireless) ? 1500 : 250; + = 210 [max post-reset-delay] + ((10 [bits per byte] * (data bytes [transmitting] + 20 silence bytes [MBL waiting] + 8 MBL "ready" bytes [MBL responding])) / + initial baud rate) * 1,000 [to scale ms to integer] + 1 [to always round up] + 250 or 1500 [Rx hardware or Network to OS slack time] */ + var mblDeliveryTime = Math.trunc(210+((10*(txData.byteLength+20+8))/initialBaudrate)*1000+1 + ((port.isWired) ? 250 : 1500)); //=((10 [bits per byte] * [max packet size]) / final baud rate) * 1,000 [to scale ms to integer] + 1 [to always round up] + 1500 or 250 [Network or Rx hardware to OS slack time] - var userDeliveryTime = ((10*maxDataSize)/finalBaudrate)*1000+1 + (port.isWireless) ? 1500 : 250; + var userDeliveryTime = Math.trunc(((10*maxDataSize)/finalBaudrate)*1000+1 + ((port.isWired) ? 250 : 1500)); - //Set for limited retry attempts (multiple when wired to try various post-reset timing) - var attempts = (port.isWired) ? Math.trunc(postResetDelay / autoAdjust) + 1 : 1; + //Set for limited retry attempts (multiple when wired; potentially trying various post-reset timing) + var attempts = (port.isWired) ? ((platform === pfWin) ? Math.max(Math.trunc(postResetDelay / autoAdjust), 1) : 1) : 1; Promise.resolve() .then(function() {return sendLoader();}) //Get Propeller's attention and send initial application (Micro Boot Loader) diff --git a/manifest.json b/manifest.json index 9fa5841..b433faf 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.2", + "version": "0.9.4", "manifest_version": 2, "minimum_chrome_version": "45", diff --git a/serial.js b/serial.js index ae75fd4..c801eca 100644 --- a/serial.js +++ b/serial.js @@ -49,8 +49,9 @@ function openPort(sock, portPath, baudrate, connMode) { function (openInfo) { if (!chrome.runtime.lastError) { // No error; update serial port object - updatePort(port, {connId: openInfo.connectionId, bSocket: sock, mode: connMode, baud: baudrate}); - log("Port " + portPath + " open with ID " + openInfo.connectionId, mStat); + updatePort(port, {connId: openInfo.connectionId, bSocket: sock, mode: connMode}); + port.baud = baudrate; //Update baud; does not use updatePort() to avoid unnecessary port activity + log("Port " + portPath + " open with ID " + openInfo.connectionId + " at " + baudrate + " baud", mDbug); resolve(); } else { // Error @@ -108,11 +109,11 @@ function closePort(port, command) { function socketClose(socket) { // Nullify port's HTTP or Telnet socket reference let sID = port[socket]; - updatePort(port, {[socket]: null}); if (sID) { - log("Closing socket", mDbug); + updatePort(port, {[socket]: null}); // Disconnect and/or close socket (if necessary) chrome.sockets.tcp.getInfo(sID, function(info) { + log("Closed socket " + sID, mDbug); if (info.connected) { chrome.sockets.tcp.disconnect(sID, function() { chrome.sockets.tcp.close(sID, function() { @@ -126,7 +127,6 @@ function closePort(port, command) { } }); } else { - log("Not closing socket", mDbug); reject(Error(notice(neCanNotClosePort, [port.path]))); } } @@ -137,12 +137,12 @@ function closePort(port, command) { if (port.connId) { chrome.serial.disconnect(port.connId, function (closeResult) { if (closeResult) { - log("Closed port " + port.path + " (id " + port.connId + ")", mStat); + log("Closed port " + port.path + " (id " + port.connId + ")", mDbug); // Clear connection id to indicate port is closed updatePort(port, {connId: null}); - resolve(); + setTimeout(resolve, 250); //Delay resolve() to prevent future openPort() calls from arriving too soon to accommodate } else { - log("Could not close port " + port.path + " (id " + port.connId + ")", mStat); + log("Could not close port " + port.path + " (id " + port.connId + ")", mDbug); reject(Error(notice(neCanNotClosePort, [port.path]))); } }); @@ -170,7 +170,7 @@ function changeBaudrate(port, baudrate) { if (port.isWired) { chrome.serial.update(port.connId, {'bitrate': baudrate}, function (updateResult) { if (updateResult) { - port.baud = baudrate; //Update baud; does not use updatePort() because of circular reference //!!! + port.baud = baudrate; //Update baud; does not use updatePort() to avoid circular reference resolve(); } else { reject(Error(notice(neCanNotSetBaudrate, [port.path, baudrate]))); @@ -315,9 +315,15 @@ function debugErrorReceiver(info) { // log("Error: PortID "+info.connectionId+" "+info.error, mDeep); } else { switch (info.resultCode) { - case -100: //port closed + case -100: //Port closed + //Find port by Propeller Telnet ID or HTTP ID and clear record let port = findPort(byPTID, info.socketId); - if (!port) {port = findPort(byPHID, info.socketId)} + if (port) { + updatePort(port, {ptSocket: null}); + } else { + port = findPort(byPHID, info.socketId); + if (port) {updatePort(port, {phSocket: null})} + } if (port) { log("SocketID "+info.socketId+" connection closed" + ((port) ? " for port " + port.path + "." : "."), mDeep); }