From 5e9fb6b5a2f52c891b254ad80a055f49f9dcfc25 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Thu, 4 Jan 2018 13:18:26 -0800 Subject: [PATCH 01/44] Experimental promise code. --- serial.js | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/serial.js b/serial.js index dc8913a..a178b8d 100644 --- a/serial.js +++ b/serial.js @@ -2901,13 +2901,14 @@ function loadPropeller(sock, portPath, action, payload, debug) { postResetDelay = platform === pfWin ? 60 : 100; } - if (payload) { - //Extract Propeller Application from payload - var binImage = parseFile(payload); - if (binImage.message !== undefined) {log("Error: " + binImage.message); return;} - } else { +//!!! Temporarily disabled normal operation +// if (payload) { +// //Extract Propeller Application from payload +// var binImage = parseFile(payload); +// if (binImage.message !== undefined) {log("Error: " + binImage.message); return;} +// } else { var binImage = buffer2ArrayBuffer(bin); - } +// } // Look for an existing port var port = findPort(portPath); @@ -2964,6 +2965,30 @@ function talkToProp(sock, cid, binImage, toEEPROM) { return new Promise(function(resolve, reject) { +//!!! Experimental code + + function msgout(mess) { + return new Promise(function(resolve, reject) { + if (mess !== "") { + console.log(mess); + resolve(); + } else { + reject(Error("")); +// reject(); + } + }) + } + + Promise.resolve() + .then(function() {return msgout("This");}) + .then(function() {return msgout("");}) + .then(function() {return msgout("test");}) +// .catch(function() {}); + .catch(function(e) {console.log(e.message);}); + return; + +//!!! End Experimental code + function sendLoader(waittime) { // Return a promise that waits for waittime then sends communication package including loader. return new Promise(function(resolve, reject) { From ed6f64f979b6d9a352c75fcab7fc100f7fb734b3 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Thu, 4 Jan 2018 14:56:51 -0800 Subject: [PATCH 02/44] 2nd experiments. --- serial.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/serial.js b/serial.js index a178b8d..5ef6d5e 100644 --- a/serial.js +++ b/serial.js @@ -2967,7 +2967,11 @@ function talkToProp(sock, cid, binImage, toEEPROM) { //!!! Experimental code - function msgout(mess) { + var p1 = function() {return msgout("This");}; + var p2 = function() {return msgout("");}; + var p3 = function() {return msgout("test");}; + + function msgout(mess, nextp) { return new Promise(function(resolve, reject) { if (mess !== "") { console.log(mess); @@ -2980,9 +2984,9 @@ function talkToProp(sock, cid, binImage, toEEPROM) { } Promise.resolve() - .then(function() {return msgout("This");}) - .then(function() {return msgout("");}) - .then(function() {return msgout("test");}) + .then(p1) + .then(p2) + .then(p3) // .catch(function() {}); .catch(function(e) {console.log(e.message);}); return; From 1bae465156709eba7edf0c07b26bf8e0942685b5 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Thu, 4 Jan 2018 15:25:11 -0800 Subject: [PATCH 03/44] 3rd experiment: separately-chained promises via named-variables. --- serial.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/serial.js b/serial.js index 5ef6d5e..6e7ce10 100644 --- a/serial.js +++ b/serial.js @@ -2967,15 +2967,19 @@ function talkToProp(sock, cid, binImage, toEEPROM) { //!!! Experimental code - var p1 = function() {return msgout("This");}; - var p2 = function() {return msgout("");}; var p3 = function() {return msgout("test");}; + var p2 = function() {return msgout("is a", p3);}; + var p1 = function() {return msgout("This", p2);}; function msgout(mess, nextp) { return new Promise(function(resolve, reject) { if (mess !== "") { console.log(mess); - resolve(); + if (nextp) { + resolve(nextp()); + } else { + resolve(); + } } else { reject(Error("")); // reject(); @@ -2983,6 +2987,11 @@ function talkToProp(sock, cid, binImage, toEEPROM) { }) } + Promise.resolve() + .then(p1) + .catch(function(e) {console.log(e.message);}); + return +/* Promise.resolve() .then(p1) .then(p2) @@ -2990,7 +2999,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { // .catch(function() {}); .catch(function(e) {console.log(e.message);}); return; - +*/ //!!! End Experimental code function sendLoader(waittime) { From a49d77b3879cc20ab8354a941d0323745911d072 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Fri, 5 Jan 2018 13:57:20 -0800 Subject: [PATCH 04/44] 4th experiment - Create promise chain with out-of-order responses. --- serial.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/serial.js b/serial.js index 6e7ce10..611b612 100644 --- a/serial.js +++ b/serial.js @@ -2967,6 +2967,25 @@ function talkToProp(sock, cid, binImage, toEEPROM) { //!!! Experimental code + function delayedResult(mess, delay, succeedFail) { + console.log("Creating delayed promise for: " + mess); + return new Promise(function(resolve, reject) { + setTimeout(function() { + console.log(mess); + if (succeedFail) {resolve()} else {reject(Error("Failed"))} + }, delay); + }) + } + + Promise.resolve() + .then(function() {return delayedResult("Second", 1500, true);}) + .then(function() {return delayedResult("First", 1000, true);}) + .then(function() {return delayedResult("Third", 2000, false);}) + .then(function() {return delayedResult("Forth", 2500, true);}) + .catch(function(e) {console.log(e.message);}); + return + +/* var p3 = function() {return msgout("test");}; var p2 = function() {return msgout("is a", p3);}; var p1 = function() {return msgout("This", p2);}; @@ -2991,6 +3010,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { .then(p1) .catch(function(e) {console.log(e.message);}); return +*/ /* Promise.resolve() .then(p1) From ee3960cff91376a5d431d61e8722af43f9dcf2d3 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 8 Jan 2018 11:22:35 -0800 Subject: [PATCH 05/44] 5th experiment - Create deferred promise (resolved/rejected outside of its constructor and pass that promise to another function (which just happens to also be a promise also) to be resolved/rejected. --- serial.js | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/serial.js b/serial.js index 611b612..5ef3b9d 100644 --- a/serial.js +++ b/serial.js @@ -2967,22 +2967,55 @@ function talkToProp(sock, cid, binImage, toEEPROM) { //!!! Experimental code - function delayedResult(mess, delay, succeedFail) { + //This code creates a deferred promise (resolved or rejected outside of its constructor) and demonstrates that the promise + //can be passed to other functions (delayedResult) and even resolved/rejected within them. + + function delayedResult(mess, delay, succeedFail, otherPromise) { console.log("Creating delayed promise for: " + mess); return new Promise(function(resolve, reject) { setTimeout(function() { console.log(mess); + if (otherPromise) {otherPromise.resolve();} if (succeedFail) {resolve()} else {reject(Error("Failed"))} }, delay); }) } + // Credit: http://lea.verou.me/2016/12/resolve-promises-externally-with-this-one-weird-trick/ + function deferredPromise() { + /*Create promise with externally-accessible resolve/reject functions*/ + + var res, rej; + + //Create promise and expose its constructor's resolve/reject functions (normally only accessible within the constructor) + var promise = new Promise((resolve, reject) => { + res = resolve; + rej = reject; + }); + + //Update promise to provide external-accessible resolve/reject functions + promise.resolve = res; + promise.reject = rej; + + return promise; + } + + //Create new promise that will be resolved by another function at a later time (a deferred promise) + let p1 = deferredPromise(); + + //Define promise chain of this deferred promise + p1 + .then(function() {console.log("p1 resolved")}) + .catch(function() {console.log("p1 rejected")}); + + //Create another normal-pattern promise chain, that, as a matter of demonstration, passes in the deferred promise in a specific step Promise.resolve() - .then(function() {return delayedResult("Second", 1500, true);}) .then(function() {return delayedResult("First", 1000, true);}) + .then(function() {return delayedResult("Second", 1500, true, p1);}) .then(function() {return delayedResult("Third", 2000, false);}) .then(function() {return delayedResult("Forth", 2500, true);}) .catch(function(e) {console.log(e.message);}); + return /* From 238f48b311995c4719182577ede53287e1acd4b3 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 8 Jan 2018 16:32:30 -0800 Subject: [PATCH 06/44] Created deferredPromise() in support functions, started converting propComm.handshake into promise, and functions that rely on it to watch for promise fullfillment. --- serial.js | 82 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/serial.js b/serial.js index 5ef3b9d..c2170b4 100644 --- a/serial.js +++ b/serial.js @@ -52,7 +52,7 @@ let mblRespAB = new ArrayBuffer(8); //Buffer for Micro Boot Load const propCommStart = { //propCommStart is used to initialize propComm stage : sgHandshake, //Propeller Protocol Stage rxCount : 0, //Current count of receive bytes (for stage) - handshake : stValidating, //ROM-resident boot loader RxHandshake response validity + handshake : deferredPromise(), //ROM-resident boot loader RxHandshake response validity version : stValidating, //ROM-resident boot loader Propeller version number response validity ramCheck : stValidating, //ROM-resident boot loader RAM Checksum response validity mblResponse : stValidating, //Micro Boot Loader response format validity @@ -228,16 +228,6 @@ function send(cid, data) { }); } -function buffer2ArrayBuffer(buffer) { -// Convert buffer to ArrayBuffer - var buf = new ArrayBuffer(buffer.length); - var bufView = new Uint8Array(buf); - for (var i = 0; i < buffer.length; i++) { - bufView[i] = buffer[i]; - } - return buf; -} - chrome.serial.onReceive.addListener(function(info) { // Permanent serial receive listener- routes debug data from Propeller to connected browser when necessary let port = findPort(info.connectionId); @@ -389,6 +379,40 @@ function findPort(cidOrPath) { } } +/*********************************************************** + * Support Functions * + ***********************************************************/ + +function buffer2ArrayBuffer(buffer) { +// Convert buffer to ArrayBuffer + var buf = new ArrayBuffer(buffer.length); + var bufView = new Uint8Array(buf); + for (var i = 0; i < buffer.length; i++) { + bufView[i] = buffer[i]; + } + return buf; +} + +function deferredPromise() { +/* Create promise with externally-accessible resolve/reject functions + Credit: http://lea.verou.me/2016/12/resolve-promises-externally-with-this-one-weird-trick/ +*/ + + var res, rej; + + //Create promise and expose its constructor's resolve/reject functions (normally only accessible within the constructor) + var promise = new Promise((resolve, reject) => { + res = resolve; + rej = reject; + }); + + //Update promise to provide externally-accessible resolve/reject functions + promise.resolve = res; + promise.reject = rej; + + //Return the enhanced promise (deferred promise) + return promise; +} /*********************************************************** * Propeller Programming Functions * @@ -2966,7 +2990,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { return new Promise(function(resolve, reject) { //!!! Experimental code - +/* //This code creates a deferred promise (resolved or rejected outside of its constructor) and demonstrates that the promise //can be passed to other functions (delayedResult) and even resolved/rejected within them. @@ -2981,25 +3005,6 @@ function talkToProp(sock, cid, binImage, toEEPROM) { }) } - // Credit: http://lea.verou.me/2016/12/resolve-promises-externally-with-this-one-weird-trick/ - function deferredPromise() { - /*Create promise with externally-accessible resolve/reject functions*/ - - var res, rej; - - //Create promise and expose its constructor's resolve/reject functions (normally only accessible within the constructor) - var promise = new Promise((resolve, reject) => { - res = resolve; - rej = reject; - }); - - //Update promise to provide external-accessible resolve/reject functions - promise.resolve = res; - promise.reject = rej; - - return promise; - } - //Create new promise that will be resolved by another function at a later time (a deferred promise) let p1 = deferredPromise(); @@ -3017,7 +3022,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { .catch(function(e) {console.log(e.message);}); return - +*/ /* var p3 = function() {return msgout("test");}; var p2 = function() {return msgout("is a", p3);}; @@ -3077,7 +3082,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { function verifier() { log("Verifying package delivery", mDeep); //Check handshake and version - if (propComm.handshake === stValidating || propComm.handshake === stInvalid || propComm.version === stValidating) {reject(Error(notice(nePropellerNotFound))); return;} +//!!! if (propComm.handshake === stValidating || propComm.handshake === stInvalid || propComm.version === stValidating) {reject(Error(notice(nePropellerNotFound))); return;} //Check for proper version if (propComm.version !== 1) {reject(Error(notice(neUnknownPropellerVersion, [propComm.version]))); return;} //Check RAM checksum @@ -3089,7 +3094,10 @@ function talkToProp(sock, cid, binImage, toEEPROM) { resolve(); } log("Waiting " + Math.trunc(waittime) + " ms for package delivery", mDeep); - setTimeout(verifier, waittime); + + propComm.handshake + .then(function() {setTimeout(verifier, waittime);}) + .catch(function(e) {return reject(e);}); }); } @@ -3279,15 +3287,15 @@ function hearFromProp(info) { if (stream[sIdx++] === rxHandshake[propComm.rxCount++]) { //Handshake matches so far... if (propComm.rxCount === rxHandshake.length) { - //Entire handshake matches! Note valid and prep for next stage - propComm.handshake = stValid; + //Entire handshake matches! Note resolved and prep for next stage + propComm.handshake.resolve(); propComm.rxCount = 0; propComm.stage = sgVersion; break; } } else { //Handshake failure! Ignore the rest - propComm.handshake = stInvalid; + propComm.handshake.reject(Error(notice(nePropellerNotFound))); propComm.stage = sgIdle; break; } From 60f6481516463af5c81b7e67b91c2227e261f392 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 8 Jan 2018 20:13:29 -0800 Subject: [PATCH 07/44] Now handshake, version, and ramCheck are all verified via promises. --- serial.js | 57 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/serial.js b/serial.js index c2170b4..a97bb1a 100644 --- a/serial.js +++ b/serial.js @@ -52,9 +52,10 @@ let mblRespAB = new ArrayBuffer(8); //Buffer for Micro Boot Load const propCommStart = { //propCommStart is used to initialize propComm stage : sgHandshake, //Propeller Protocol Stage rxCount : 0, //Current count of receive bytes (for stage) - handshake : deferredPromise(), //ROM-resident boot loader RxHandshake response validity - version : stValidating, //ROM-resident boot loader Propeller version number response validity - ramCheck : stValidating, //ROM-resident boot loader RAM Checksum response validity + handshake : null, //ROM-resident boot loader RxHandshake response validity (Promise) + version : null, //ROM-resident boot loader Propeller version number response validity (Promise) + firmver : 0, //Propeller firmware version number + ramCheck : null, //ROM-resident boot loader RAM Checksum response validity (Promise) mblResponse : stValidating, //Micro Boot Loader response format validity mblRespBuf : new Uint8Array(mblRespAB), //Micro Boot Loader responses data (unsigned byte format) mblPacketId : new Int32Array(mblRespAB, 0, 1), //Micro Boot Loader requested next packet id (32-bit signed int format) @@ -2973,6 +2974,7 @@ function listen(engage) { engage = true to add listener; false to remove listener.*/ if (engage) { //Add programming protocol serial receive handler + resetPropComm(); chrome.serial.onReceive.addListener(hearFromProp); } else { //Remove programming protocol serial receive handler @@ -2980,6 +2982,14 @@ function listen(engage) { } } +function resetPropComm() { +/*Reset propComm object to default values*/ + Object.assign(propComm, propCommStart); //Reset propComm object + propComm.handshake = deferredPromise(); //Create new deferred promise for handshake + propComm.version = deferredPromise(); //Create new deferred promise for version + propComm.ramCheck = deferredPromise(); //Create new deferred promise for RAM check +} + function talkToProp(sock, cid, binImage, toEEPROM) { /* Return promise to deliver Propeller Application (binImage) to Propeller sock is the websocket to direct mUser messages at @@ -3084,19 +3094,24 @@ function talkToProp(sock, cid, binImage, toEEPROM) { //Check handshake and version //!!! if (propComm.handshake === stValidating || propComm.handshake === stInvalid || propComm.version === stValidating) {reject(Error(notice(nePropellerNotFound))); return;} //Check for proper version - if (propComm.version !== 1) {reject(Error(notice(neUnknownPropellerVersion, [propComm.version]))); return;} +//!!! if (propComm.version !== 1) {reject(Error(notice(neUnknownPropellerVersion, [propComm.version]))); return;} //Check RAM checksum - if (propComm.ramCheck === stValidating) {reject(Error(notice(neCommunicationLost))); return;} - if (propComm.ramCheck === stInvalid) {reject(Error(notice(neCommunicationFailed))); return;} +//!!! if (propComm.ramCheck === stValidating) {reject(Error(notice(neCommunicationLost))); return;} +//!!! if (propComm.ramCheck === stInvalid) {reject(Error(notice(neCommunicationFailed))); return;} //Check Micro Boot Loader Ready Signal if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) {reject(Error(notice(neLoaderFailed))); return;} log(notice(000, ["Found Propeller"]), mUser+mStat, sock); resolve(); } - log("Waiting " + Math.trunc(waittime) + " ms for package delivery", mDeep); +//!!! log("Waiting " + Math.trunc(waittime) + " ms for package delivery", mDeep); propComm.handshake - .then(function() {setTimeout(verifier, waittime);}) + .then(function() {console.log("handshake");}) + .then(function() {return propComm.version;}) + .then(function() {console.log("version");}) + .then(function() {return propComm.ramCheck;}) + .then(function() {console.log("ram check");}) + // .then(function() {setTimeout(verifier, waittime);}) .catch(function(e) {return reject(e);}); }); } @@ -3241,7 +3256,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { var next; Promise.resolve() - .then(function() { Object.assign(propComm, propCommStart);} ) //Reset propComm object + .then(function() { resetPropComm();} ) //Reset propComm object .then(function() { log("Generating reset signal", mDeep);} ) .then(function() {return setControl(cid, {dtr: false});} ) //Start Propeller Reset Signal .then(function() {return flush(cid);} ) //Flush transmit/receive buffers (during Propeller reset) @@ -3294,7 +3309,7 @@ function hearFromProp(info) { break; } } else { - //Handshake failure! Ignore the rest + //Handshake failure! Note rejected; Ignore the rest propComm.handshake.reject(Error(notice(nePropellerNotFound))); propComm.stage = sgIdle; break; @@ -3306,16 +3321,18 @@ function hearFromProp(info) { if (propComm.stage === sgVersion) { while (sIdx < stream.length && propComm.rxCount < 4) { //More data to decode into Propeller version (4 bytes, 2 data bits per byte) - propComm.version = (propComm.version >> 2 & 0x3F) | ((stream[sIdx] & 0x01) << 6) | ((stream[sIdx] & 0x20) << 2); + propComm.firmver = (propComm.firmver >> 2 & 0x3F) | ((stream[sIdx] & 0x01) << 6) | ((stream[sIdx] & 0x20) << 2); sIdx++; if (++propComm.rxCount === 4) { //Received all 4 bytes - if (propComm.version === 1) { - //Version matches expected value! Prep for next stage + if (propComm.firmver === 1) { + //Version matches expected value! Note resolved and prep for next stage + propComm.version.resolve(); propComm.rxCount = 0; propComm.stage = sgRAMChecksum; } else { - //Unexpected version! Ignore the rest + //Unexpected version! Note rejected; Ignore the rest + propComm.version.reject(Error(notice(neUnknownPropellerVersion, [propComm.firmver]))); propComm.stage = sgIdle; } break; @@ -3326,10 +3343,16 @@ function hearFromProp(info) { // Receive RAM Checksum if (propComm.stage === sgRAMChecksum && sIdx < stream.length) { //Received RAM Checksum response? - propComm.ramCheck = stream[sIdx++] === 0xFE ? stValid : stInvalid; - //Set next stage according to result + if (stream[sIdx++] === 0xFE) { + //RAM Checksum valid; Note resolved and prep for next stage + propComm.ramCheck.resolve(); + propComm.stage = sgMBLResponse; + } else { + //RAM Checksum invalid; Note rejected; Ignore the rest + propComm.ramCheck.reject(Error(notice(neCommunicationFailed))); + propComm.stage = sgIdle; + } propComm.rxCount = 0; - propComm.stage = propComm.ramCheck ? sgMBLResponse : sgIdle; } // Receive Micro Boot Loader's "Ready" Signal From 610a4bbc83c536c87a2f0049eae177c6b911cb7a Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Thu, 11 Jan 2018 19:41:55 -0800 Subject: [PATCH 08/44] Major rework to support active-promise asynchrnous responses from Propeller. More work to do yet. --- serial.js | 112 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 58 insertions(+), 54 deletions(-) diff --git a/serial.js b/serial.js index a97bb1a..61782ff 100644 --- a/serial.js +++ b/serial.js @@ -42,26 +42,26 @@ const sgHandshake = 0; const sgVersion = 1; const sgRAMChecksum = 2; const sgMBLResponse = 3; -//const sgEEProgram = 3; -//const sgEEChecksum = 4; +//!!! const sgEEProgram = 3; +//!!! const sgEEChecksum = 4; // Propeller Communication (propComm) status; categorizes Propeller responses -let propComm = {}; //Holds current status -let mblRespAB = new ArrayBuffer(8); //Buffer for Micro Boot Loader responses - -const propCommStart = { //propCommStart is used to initialize propComm - stage : sgHandshake, //Propeller Protocol Stage - rxCount : 0, //Current count of receive bytes (for stage) - handshake : null, //ROM-resident boot loader RxHandshake response validity (Promise) - version : null, //ROM-resident boot loader Propeller version number response validity (Promise) - firmver : 0, //Propeller firmware version number - ramCheck : null, //ROM-resident boot loader RAM Checksum response validity (Promise) - mblResponse : stValidating, //Micro Boot Loader response format validity - mblRespBuf : new Uint8Array(mblRespAB), //Micro Boot Loader responses data (unsigned byte format) - mblPacketId : new Int32Array(mblRespAB, 0, 1), //Micro Boot Loader requested next packet id (32-bit signed int format) - mblTransId : new Int32Array(mblRespAB, 4, 1) //Micro Boot Loader transmission id (32-bit signed int format) -// eeProg : stValidating, -// eeCheck : stValidating +let propComm = {}; //Holds current status +let mblRespAB = new ArrayBuffer(8); //Buffer for Micro Boot Loader actual responses +let mblExpdAB = new ArrayBuffer(8); //Buffer for Micro Boot Loader expected responses + +const propCommStart = { //propCommStart is used to initialize propComm + stage : sgHandshake, //Propeller Protocol Stage + response : null, //Micro Boot Loader response signal (Promise) + rxCount : 0, //Current count of receive bytes (for stage) + version : 0, //Propeller firmware version number + mblRespBuf : new Uint8Array(mblRespAB), //Micro Boot Loader response data (unsigned byte format) + mblRPacketId : new Int32Array(mblRespAB, 0, 1), //Micro Boot Loader requested next packet id (32-bit signed int format) + mblRTransId : new Int32Array(mblRespAB, 4, 1), //Micro Boot Loader response-to transmission id (32-bit signed int format) + mblEPacketId : new Int32Array(mblExpdAB, 0, 1), //Micro Boot Loader expected next packet id (32-bit signed int format) + mblETransId : new Int32Array(mblExpdAB, 4, 1) //Micro Boot Loader expected transmission id (32-bit signed int format) +//!!! eeProg : stValidating, +//!!! eeCheck : stValidating }; //Loader type; used for generateLoaderPacket() @@ -2985,9 +2985,7 @@ function listen(engage) { function resetPropComm() { /*Reset propComm object to default values*/ Object.assign(propComm, propCommStart); //Reset propComm object - propComm.handshake = deferredPromise(); //Create new deferred promise for handshake - propComm.version = deferredPromise(); //Create new deferred promise for version - propComm.ramCheck = deferredPromise(); //Create new deferred promise for RAM check + propComm.response = deferredPromise(); //Create new deferred promise for micro boot loader response } function talkToProp(sock, cid, binImage, toEEPROM) { @@ -3089,8 +3087,8 @@ function talkToProp(sock, cid, binImage, toEEPROM) { Error is "Propeller not found" unless handshake received (and proper) and version received; error is more specific thereafter.*/ return new Promise(function(resolve, reject) { - function verifier() { - log("Verifying package delivery", mDeep); +//!!! function verifier() { +//!!! log("Verifying package delivery", mDeep); //Check handshake and version //!!! if (propComm.handshake === stValidating || propComm.handshake === stInvalid || propComm.version === stValidating) {reject(Error(notice(nePropellerNotFound))); return;} //Check for proper version @@ -3099,26 +3097,25 @@ function talkToProp(sock, cid, binImage, toEEPROM) { //!!! if (propComm.ramCheck === stValidating) {reject(Error(notice(neCommunicationLost))); return;} //!!! if (propComm.ramCheck === stInvalid) {reject(Error(notice(neCommunicationFailed))); return;} //Check Micro Boot Loader Ready Signal - if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) {reject(Error(notice(neLoaderFailed))); return;} - log(notice(000, ["Found Propeller"]), mUser+mStat, sock); - resolve(); - } -//!!! log("Waiting " + Math.trunc(waittime) + " ms for package delivery", mDeep); +//!!! if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) {reject(Error(notice(neLoaderFailed))); return;} - propComm.handshake - .then(function() {console.log("handshake");}) - .then(function() {return propComm.version;}) - .then(function() {console.log("version");}) - .then(function() {return propComm.ramCheck;}) - .then(function() {console.log("ram check");}) +//!!! resolve(); +//!!! } +//!!! log("Waiting " + Math.trunc(waittime) + " ms for package delivery", mDeep); + //Ready for expected packetID:transmissionId response (Micro-Boot-Loader's "Ready" signal) + propComm.mblEPacketId = packetId; + propComm.mblETransId = transmissionId; + //Set up for asynchronous Micro-Boot-Loader "Ready" response + propComm.response + .then(function() {log(notice(000, ["Found Propeller"]), mUser+mStat, sock);}) // .then(function() {setTimeout(verifier, waittime);}) .catch(function(e) {return reject(e);}); }); } - +//!!! function prepForMBLResponse() { // Set propComm to prep for another Micro Boot Loader response. - propComm.mblResponse = stValidating; + propComm.response = deferredPromise(); //Create new deferred promise for micro boot loader response propComm.stage = sgMBLResponse; propComm.rxCount = 0; } @@ -3158,9 +3155,9 @@ function talkToProp(sock, cid, binImage, toEEPROM) { function verifier() { log("Verifying loader acknowledgement " + (totalPackets-packetId+0) + " of " + totalPackets, mDeep); //Check Micro Boot Loader response - if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) { - reject(Error(notice(neCommunicationFailed))); return - } +//!!! if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) { +//!!! reject(Error(notice(neCommunicationFailed))); return +//!!! } log("Packet delivered.", mDeep); resolve(); } @@ -3212,9 +3209,9 @@ function talkToProp(sock, cid, binImage, toEEPROM) { function verifier() { log("Verifying loader acknowledgement", mDeep); //Check Micro Boot Loader response (values checked by value only, not value+type) - if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) { - reject(Error(next.value.recvErr)); return; - } +//!!! if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) { +//!!! reject(Error(next.value.recvErr)); return; +//!!! } //Resolve and indicate there's more to come log("Packet accepted.", mDeep); resolve(true); @@ -3302,15 +3299,14 @@ function hearFromProp(info) { if (stream[sIdx++] === rxHandshake[propComm.rxCount++]) { //Handshake matches so far... if (propComm.rxCount === rxHandshake.length) { - //Entire handshake matches! Note resolved and prep for next stage - propComm.handshake.resolve(); + //Entire handshake matches! Prep for next stage propComm.rxCount = 0; propComm.stage = sgVersion; break; } } else { //Handshake failure! Note rejected; Ignore the rest - propComm.handshake.reject(Error(notice(nePropellerNotFound))); + propComm.response.reject(Error(notice(nePropellerNotFound))); propComm.stage = sgIdle; break; } @@ -3321,18 +3317,17 @@ function hearFromProp(info) { if (propComm.stage === sgVersion) { while (sIdx < stream.length && propComm.rxCount < 4) { //More data to decode into Propeller version (4 bytes, 2 data bits per byte) - propComm.firmver = (propComm.firmver >> 2 & 0x3F) | ((stream[sIdx] & 0x01) << 6) | ((stream[sIdx] & 0x20) << 2); + propComm.version = (propComm.version >> 2 & 0x3F) | ((stream[sIdx] & 0x01) << 6) | ((stream[sIdx] & 0x20) << 2); sIdx++; if (++propComm.rxCount === 4) { //Received all 4 bytes - if (propComm.firmver === 1) { - //Version matches expected value! Note resolved and prep for next stage - propComm.version.resolve(); + if (propComm.version === 1) { + //Version matches expected value! Prep for next stage propComm.rxCount = 0; propComm.stage = sgRAMChecksum; } else { //Unexpected version! Note rejected; Ignore the rest - propComm.version.reject(Error(notice(neUnknownPropellerVersion, [propComm.firmver]))); + propComm.response.reject(Error(notice(neUnknownPropellerVersion, [propComm.version]))); propComm.stage = sgIdle; } break; @@ -3344,25 +3339,34 @@ function hearFromProp(info) { if (propComm.stage === sgRAMChecksum && sIdx < stream.length) { //Received RAM Checksum response? if (stream[sIdx++] === 0xFE) { - //RAM Checksum valid; Note resolved and prep for next stage - propComm.ramCheck.resolve(); + //RAM Checksum valid; Prep for next stage propComm.stage = sgMBLResponse; } else { //RAM Checksum invalid; Note rejected; Ignore the rest - propComm.ramCheck.reject(Error(notice(neCommunicationFailed))); + propComm.response.reject(Error(notice(neCommunicationFailed))); propComm.stage = sgIdle; } propComm.rxCount = 0; } - // Receive Micro Boot Loader's "Ready" Signal + // Receive Micro Boot Loader's response. The first is its "Ready" signal; the rest are packet responses. if (propComm.stage === sgMBLResponse) { while (sIdx < stream.length && propComm.rxCount < propComm.mblRespBuf.byteLength) { propComm.mblRespBuf[propComm.rxCount++] = stream[sIdx++]; //Finish stage when expected response size received if (propComm.rxCount === propComm.mblRespBuf.byteLength) { propComm.stage = sgIdle; + if ((propComm.mblRPacketId[0] === propComm.mblEPacketId[0]) && (propComm.mblRTransId[0] === propComm.mblETransId[0])) { + //MBL Response is perfect; Note resolved + propComm.response.resolve(); + propComm.stage = sgIdle; + } else { + //MBL Response invalid; Note rejected; Ignore the rest + reject(Error(notice(neLoaderFailed))); + propComm.stage = sgIdle; + } //Valid if end of stream, otherwise something's wrong (invalid response) +//!!! propComm.mblResponse = stream.length === sIdx ? stValid : stInvalid; } } From 4056fe7052767a9dfa9289606d12ccbd617484a2 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Fri, 12 Jan 2018 09:27:15 -0800 Subject: [PATCH 09/44] Fixed a couple typos. --- serial.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/serial.js b/serial.js index 61782ff..f51f4cd 100644 --- a/serial.js +++ b/serial.js @@ -3102,10 +3102,10 @@ function talkToProp(sock, cid, binImage, toEEPROM) { //!!! resolve(); //!!! } //!!! log("Waiting " + Math.trunc(waittime) + " ms for package delivery", mDeep); - //Ready for expected packetID:transmissionId response (Micro-Boot-Loader's "Ready" signal) - propComm.mblEPacketId = packetId; - propComm.mblETransId = transmissionId; - //Set up for asynchronous Micro-Boot-Loader "Ready" response + //Prep for expected packetID:transmissionId response (Micro-Boot-Loader's "Ready" signal) + propComm.mblEPacketId[0] = packetId; + propComm.mblETransId[0] = transmissionId; + //Set up for asynchronous responses from ROM-Resident Boot Loader and finally Micro Boot Loader propComm.response .then(function() {log(notice(000, ["Found Propeller"]), mUser+mStat, sock);}) // .then(function() {setTimeout(verifier, waittime);}) @@ -3362,7 +3362,7 @@ function hearFromProp(info) { propComm.stage = sgIdle; } else { //MBL Response invalid; Note rejected; Ignore the rest - reject(Error(notice(neLoaderFailed))); + propComm.response.reject(Error(notice(neLoaderFailed))); propComm.stage = sgIdle; } //Valid if end of stream, otherwise something's wrong (invalid response) From 51893f4f660cc5a837fb327f8a4c099e0cfa7d19 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Wed, 24 Jan 2018 15:45:30 -0800 Subject: [PATCH 10/44] Added messages, tested, and determined that it works properly all the way through IsLoaderReady(). --- serial.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/serial.js b/serial.js index f51f4cd..59c3dd1 100644 --- a/serial.js +++ b/serial.js @@ -2986,6 +2986,7 @@ function resetPropComm() { /*Reset propComm object to default values*/ Object.assign(propComm, propCommStart); //Reset propComm object propComm.response = deferredPromise(); //Create new deferred promise for micro boot loader response + } function talkToProp(sock, cid, binImage, toEEPROM) { @@ -3106,7 +3107,9 @@ function talkToProp(sock, cid, binImage, toEEPROM) { propComm.mblEPacketId[0] = packetId; propComm.mblETransId[0] = transmissionId; //Set up for asynchronous responses from ROM-Resident Boot Loader and finally Micro Boot Loader + log("Waiting for propComm.response", mDeep); //!!! propComm.response + .then(function() {log("received propComm.response", mDeep);}) //!!! .then(function() {log(notice(000, ["Found Propeller"]), mUser+mStat, sock);}) // .then(function() {setTimeout(verifier, waittime);}) .catch(function(e) {return reject(e);}); @@ -3300,6 +3303,7 @@ function hearFromProp(info) { //Handshake matches so far... if (propComm.rxCount === rxHandshake.length) { //Entire handshake matches! Prep for next stage + log("passed handshake", mDeep); //!!! propComm.rxCount = 0; propComm.stage = sgVersion; break; @@ -3323,6 +3327,7 @@ function hearFromProp(info) { //Received all 4 bytes if (propComm.version === 1) { //Version matches expected value! Prep for next stage + log("passed version", mDeep); //!!! propComm.rxCount = 0; propComm.stage = sgRAMChecksum; } else { @@ -3340,6 +3345,7 @@ function hearFromProp(info) { //Received RAM Checksum response? if (stream[sIdx++] === 0xFE) { //RAM Checksum valid; Prep for next stage + log("passed RAM checksum", mDeep); //!!! propComm.stage = sgMBLResponse; } else { //RAM Checksum invalid; Note rejected; Ignore the rest @@ -3358,6 +3364,7 @@ function hearFromProp(info) { propComm.stage = sgIdle; if ((propComm.mblRPacketId[0] === propComm.mblEPacketId[0]) && (propComm.mblRTransId[0] === propComm.mblETransId[0])) { //MBL Response is perfect; Note resolved + log("passed response", mDeep); //!!! propComm.response.resolve(); propComm.stage = sgIdle; } else { From b35bd3b96a67d2292930a2e19d573ff0045b56c4 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Wed, 24 Jan 2018 17:46:45 -0800 Subject: [PATCH 11/44] Set isLoaderReady to resolve and sendUA to set the next packetId and transmissionId for propComm. Still doesn't successfully finish download. --- serial.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/serial.js b/serial.js index 59c3dd1..b6fdecd 100644 --- a/serial.js +++ b/serial.js @@ -3111,6 +3111,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { propComm.response .then(function() {log("received propComm.response", mDeep);}) //!!! .then(function() {log(notice(000, ["Found Propeller"]), mUser+mStat, sock);}) + .then(function() {return resolve()}) // .then(function() {setTimeout(verifier, waittime);}) .catch(function(e) {return reject(e);}); }); @@ -3141,6 +3142,10 @@ function talkToProp(sock, cid, binImage, toEEPROM) { txData = new ArrayBuffer(txPacketLength * 4); //Set packet length (in longs)} txView = new Uint8Array(txData); transmissionId = Math.floor(Math.random()*4294967296); //Create next random Transmission ID + + propComm.mblEPacketId[0] = packetId; + propComm.mblETransId[0] = transmissionId; + (new DataView(txData, 0, 4)).setUint32(0, packetId, true); //Store Packet ID (new DataView(txData, 4, 4)).setUint32(0, transmissionId, true); //Store random Transmission ID txView.set((new Uint8Array(binImage)).slice(pIdx * 4, pIdx * 4 + (txPacketLength - 2) * 4), 8); //Store section of binary image From 24621836250789b1bfced1141b77a682d677cf59 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Fri, 26 Jan 2018 16:58:48 -0800 Subject: [PATCH 12/44] Fixed PacketID bug, enhanced FinalizeDelivery. Still doesn't run the target application. --- serial.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/serial.js b/serial.js index b6fdecd..4a5f8e6 100644 --- a/serial.js +++ b/serial.js @@ -3143,7 +3143,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { txView = new Uint8Array(txData); transmissionId = Math.floor(Math.random()*4294967296); //Create next random Transmission ID - propComm.mblEPacketId[0] = packetId; + propComm.mblEPacketId[0] = packetId-1; propComm.mblETransId[0] = transmissionId; (new DataView(txData, 0, 4)).setUint32(0, packetId, true); //Store Packet ID @@ -3174,7 +3174,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { }); } sendUA() - .then(function() {return loaderAcknowledged(600+((10*(txData.byteLength+2+8))/port.baud)*1000+1);}) + .then(function() {return propComm.response;}) .then(function() {if (packetId > 0) {return sendUserApp()}}) .then(function() {return resolve()}) .catch(function(e) {return reject(e)}); @@ -3204,8 +3204,12 @@ function talkToProp(sock, cid, binImage, toEEPROM) { generateLoaderPacket(next.value.type, packetId); //Generate VerifyRAM executable packet transmissionId = Math.floor(Math.random()*4294967296); //Create next random Transmission ID (new DataView(txData, 4, 4)).setUint32(0, transmissionId, true); //Store random Transmission ID - send(cid, txData); //Transmit packet + packetId = next.value.nextId; //Ready next Packet ID + propComm.mblEPacketId[0] = packetId; + propComm.mblETransId[0] = transmissionId; + + send(cid, txData); //Transmit packet resolve(next.value.type !== ltLaunchNow); //Resolve and indicate if there's more to come }); } @@ -3232,6 +3236,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { sendInstructionPacket() .then(function(ack) {if (ack) {return loaderAcknowledged(next.value.recvTime+((10*(txData.byteLength+2+8))/port.baud)*1000+1)}}) .then(function(ack) {if (ack) {return finalizeDelivery()}}) + .then(function() {return new Promise(function(resolve) {setTimeout(resolve, 100)})}) .then(function() {return resolve()}) .catch(function(e) {return reject(e)}); }); @@ -3367,6 +3372,8 @@ function hearFromProp(info) { //Finish stage when expected response size received if (propComm.rxCount === propComm.mblRespBuf.byteLength) { propComm.stage = sgIdle; + log("Response PacketId: "+ propComm.mblRPacketId+ " TransId: "+ propComm.mblRTransId, mDeep); //!!! + log("Expected PacketId: "+ propComm.mblEPacketId+ " TransId: "+ propComm.mblETransId, mDeep); //!!! if ((propComm.mblRPacketId[0] === propComm.mblEPacketId[0]) && (propComm.mblRTransId[0] === propComm.mblETransId[0])) { //MBL Response is perfect; Note resolved log("passed response", mDeep); //!!! From d80d0623a0a2b1fbfb6e191b3475309d14a8a714 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 29 Jan 2018 14:59:37 -0800 Subject: [PATCH 13/44] Working of finishing finalization part of download. --- serial.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/serial.js b/serial.js index 4a5f8e6..cf805cd 100644 --- a/serial.js +++ b/serial.js @@ -3209,8 +3209,12 @@ function talkToProp(sock, cid, binImage, toEEPROM) { propComm.mblEPacketId[0] = packetId; propComm.mblETransId[0] = transmissionId; - send(cid, txData); //Transmit packet - resolve(next.value.type !== ltLaunchNow); //Resolve and indicate if there's more to come + send(cid, txData); //Transmit packet + propComm.response //If response + .then(function() {if (next.value.type !== ltLaunchNow) {return sendInstructionPacket()}}) // is success; send next packet (if any) and + .then(function() {return resolve()}) // resolve +// .then(function() {return resolve(next.value.type !== ltLaunchNow);}) // is success; resolve and indicate if there's more to come + .catch(function(e) {return rejects(e)}); // is failure; return the error }); } function loaderAcknowledged(waittime) { @@ -3234,9 +3238,10 @@ function talkToProp(sock, cid, binImage, toEEPROM) { } sendInstructionPacket() - .then(function(ack) {if (ack) {return loaderAcknowledged(next.value.recvTime+((10*(txData.byteLength+2+8))/port.baud)*1000+1)}}) - .then(function(ack) {if (ack) {return finalizeDelivery()}}) - .then(function() {return new Promise(function(resolve) {setTimeout(resolve, 100)})}) +// .then(function(ack) {if (ack) {return loaderAcknowledged(next.value.recvTime+((10*(txData.byteLength+2+8))/port.baud)*1000+1)}}) +// .then(function(ack) {return propComm.response.then(function() {if (ack) {return finalizeDelivery()}}).catch(function(e) {return reject(e)})}) +// .then(function(ack) {if (ack) {return finalizeDelivery()}}) + .then(function() {return new Promise(function(resolve) {setTimeout(resolve, 1000)})}) .then(function() {return resolve()}) .catch(function(e) {return reject(e)}); }); From 1554e2a4d65ae0a04d388a0143d81a758f252e4c Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Thu, 1 Feb 2018 17:00:20 -0800 Subject: [PATCH 14/44] Downloads successfully, but breaks the promise chain at finalizeDelivery(). --- serial.js | 54 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/serial.js b/serial.js index cf805cd..e32c6ea 100644 --- a/serial.js +++ b/serial.js @@ -433,13 +433,13 @@ function loadPropeller(sock, portPath, action, payload, debug) { //Temporary hard-coded Propeller Application for development testing //Blink P26 - const bin = [ + /*const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0x61, 0x10, 0x00, 0x30, 0x00, 0x38, 0x00, 0x18, 0x00, 0x3C, 0x00, 0x20, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x38, 0x1A, 0x3D, 0xD6, 0x1C, 0x38, 0x1A, 0x3D, 0xD4, 0x47, 0x35, 0xC0, 0x37, 0x00, 0xF6, 0x3F, 0x91, 0xEC, 0x23, 0x04, 0x70, 0x32, 0x00, 0x00 - ]; + ];*/ //Clock Demo PABWX (adjusted for P20 through P27) - /* const bin = [ + const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0x01, 0x10, 0x00, 0x1C, 0x02, 0x50, 0x02, 0x3E, 0x00, 0x54, 0x02, 0xBC, 0x00, 0x04, 0x01, 0x2E, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x28, 0x00, 0x6B, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x6E, 0x00, 0x6F, 0x00, @@ -474,7 +474,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0x0F, 0x42, 0x40, 0xF6, 0x64, 0xF4, 0x39, 0x01, 0x7D, 0xE4, 0x42, 0xCC, 0x23, 0x32, 0x35, 0xC0, 0x39, 0x03, 0xE8, 0xF6, 0x64, 0xF4, 0x39, 0x01, 0x7D, 0xE4, 0x42, 0xCC, 0x23, 0x32, 0x35, 0xC0, 0x64, 0xF4, 0x39, 0x01, 0x7D, 0xE4, 0x42, 0xCC, 0x23, 0x32, 0x00, 0x00 - ];*/ + ]; //FloatMathDemoPABWX.spin /* const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0xE7, 0x10, 0x00, 0x98, 0x19, 0x8C, 0x50, 0x4C, 0x00, 0x94, 0x50, @@ -3175,8 +3175,8 @@ function talkToProp(sock, cid, binImage, toEEPROM) { } sendUA() .then(function() {return propComm.response;}) - .then(function() {if (packetId > 0) {return sendUserApp()}}) - .then(function() {return resolve()}) + .then(function() {if (packetId > 0) {return sendUserApp()} else {return resolve()}}) +// .then(function() {return resolve()}) .catch(function(e) {return reject(e)}); }); } @@ -3200,21 +3200,37 @@ function talkToProp(sock, cid, binImage, toEEPROM) { return new Promise(function(resolve, reject) { next = instPacket.next(); log(next.value.sendLog, mAll, sock); - prepForMBLResponse(); - generateLoaderPacket(next.value.type, packetId); //Generate VerifyRAM executable packet + + generateLoaderPacket(next.value.type, packetId); //Generate next executable packet transmissionId = Math.floor(Math.random()*4294967296); //Create next random Transmission ID (new DataView(txData, 4, 4)).setUint32(0, transmissionId, true); //Store random Transmission ID - packetId = next.value.nextId; //Ready next Packet ID - propComm.mblEPacketId[0] = packetId; - propComm.mblETransId[0] = transmissionId; - send(cid, txData); //Transmit packet - propComm.response //If response - .then(function() {if (next.value.type !== ltLaunchNow) {return sendInstructionPacket()}}) // is success; send next packet (if any) and - .then(function() {return resolve()}) // resolve -// .then(function() {return resolve(next.value.type !== ltLaunchNow);}) // is success; resolve and indicate if there's more to come - .catch(function(e) {return rejects(e)}); // is failure; return the error + if (next.value.type !== ltLaunchNow) { //Response expected from MBL? + prepForMBLResponse(); // Prepare to receive next MBL response + packetId = next.value.nextId; // Ready next Packet ID + propComm.mblEPacketId[0] = packetId; // Note expected response + propComm.mblETransId[0] = transmissionId; + } + + send(cid, txData); //Transmit packet + + if (next.value.type !== ltLaunchNow) { //If not last instruction packet... + propComm.response // When response... + .then(function() { + log("sendInstructionPacket got response", mDeep); + return sendInstructionPacket(); + return resolve(); + }) // is success; send next packet (if any) and + // .then(function() {log("sendInstructionPacket resolving", mDeep); return resolve();}) // resolve + // .then(function() {return resolve(next.value.type !== ltLaunchNow);}) // is success; resolve and indicate if there's more to come + .catch(function(e) { + return reject(e) + }); // is failure; return the error + } else { //Else, last packet sent; success + log("sendInstructionPacket resolved", mDeep); + return resolve(); //Success; User App Launched! + } }); } function loaderAcknowledged(waittime) { @@ -3241,8 +3257,8 @@ function talkToProp(sock, cid, binImage, toEEPROM) { // .then(function(ack) {if (ack) {return loaderAcknowledged(next.value.recvTime+((10*(txData.byteLength+2+8))/port.baud)*1000+1)}}) // .then(function(ack) {return propComm.response.then(function() {if (ack) {return finalizeDelivery()}}).catch(function(e) {return reject(e)})}) // .then(function(ack) {if (ack) {return finalizeDelivery()}}) - .then(function() {return new Promise(function(resolve) {setTimeout(resolve, 1000)})}) - .then(function() {return resolve()}) +// .then(function() {log("finalizeDelivery delaying resolve", mDeep); return new Promise(function() {setTimeout(resolve, 1000)});}) + .then(function() {log("finalizeDelivery resolved", mDeep); return resolve();}) .catch(function(e) {return reject(e)}); }); } From 47c6150bfe0f0fc5f6b8f66858685fc016e4a318 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Fri, 2 Feb 2018 15:39:19 -0800 Subject: [PATCH 15/44] finalizeDelivery()'s promise chain was broken because sendInstructionPacket() needed to resolve within another link in it's promise chain after all calls back to sendInstructionPacket(). This was very hard to find! --- serial.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/serial.js b/serial.js index e32c6ea..36c5623 100644 --- a/serial.js +++ b/serial.js @@ -3220,8 +3220,8 @@ function talkToProp(sock, cid, binImage, toEEPROM) { .then(function() { log("sendInstructionPacket got response", mDeep); return sendInstructionPacket(); - return resolve(); }) // is success; send next packet (if any) and + .then(function() {return resolve()}) // .then(function() {log("sendInstructionPacket resolving", mDeep); return resolve();}) // resolve // .then(function() {return resolve(next.value.type !== ltLaunchNow);}) // is success; resolve and indicate if there's more to come .catch(function(e) { @@ -3229,7 +3229,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { }); // is failure; return the error } else { //Else, last packet sent; success log("sendInstructionPacket resolved", mDeep); - return resolve(); //Success; User App Launched! + resolve(); //Success; User App Launched! } }); } From 62cabfb3468bf03ea0b8cc47406153284a027424 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Fri, 2 Feb 2018 15:57:22 -0800 Subject: [PATCH 16/44] Removed loaderAcknowledged() and cleaned up finalizeDelivery promise chains. --- serial.js | 41 +++++------------------------------------ 1 file changed, 5 insertions(+), 36 deletions(-) diff --git a/serial.js b/serial.js index 36c5623..92795a4 100644 --- a/serial.js +++ b/serial.js @@ -3191,7 +3191,6 @@ function talkToProp(sock, cid, binImage, toEEPROM) { yield {type: ltLaunchNow, nextId: -1, sendLog: notice(000, ["Launching"]), recvTime: 0, recvErr: ""}; } - //TODO lower waittime function finalizeDelivery() { // Return a promise that sends the final packets (special executable packets) that verifies RAM, programs and verifies EEPROM, and launches user code. return new Promise(function(resolve, reject) { @@ -3217,46 +3216,16 @@ function talkToProp(sock, cid, binImage, toEEPROM) { if (next.value.type !== ltLaunchNow) { //If not last instruction packet... propComm.response // When response... - .then(function() { - log("sendInstructionPacket got response", mDeep); - return sendInstructionPacket(); - }) // is success; send next packet (if any) and - .then(function() {return resolve()}) - // .then(function() {log("sendInstructionPacket resolving", mDeep); return resolve();}) // resolve - // .then(function() {return resolve(next.value.type !== ltLaunchNow);}) // is success; resolve and indicate if there's more to come - .catch(function(e) { - return reject(e) - }); // is failure; return the error - } else { //Else, last packet sent; success - log("sendInstructionPacket resolved", mDeep); - resolve(); //Success; User App Launched! - } - }); - } - function loaderAcknowledged(waittime) { - /* Did Micro Boot Loader acknowledge the packet? - Return a promise that waits for waittime then validates that the Micro Boot Loader acknowledged the packet. - Rejects if error occurs. Micro Boot Loader must respond with next Packet ID (plus Transmission ID) for success (resolve).*/ - return new Promise(function(resolve, reject) { - function verifier() { - log("Verifying loader acknowledgement", mDeep); - //Check Micro Boot Loader response (values checked by value only, not value+type) -//!!! if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) { -//!!! reject(Error(next.value.recvErr)); return; -//!!! } - //Resolve and indicate there's more to come - log("Packet accepted.", mDeep); - resolve(true); + .then(function() {return sendInstructionPacket()}) // is success; send next packet (if any) and + .then(function() {return resolve()}) // resolve + .catch(function(e) {return reject(e)}); // is failure; reject (return the error) + } else { //Else, last instruction packet sent; success + resolve(); // Success; User App Launched! } - log("Waiting " + Math.trunc(waittime) + " ms for acknowledgement", mDeep); - setTimeout(verifier, waittime); }); } sendInstructionPacket() -// .then(function(ack) {if (ack) {return loaderAcknowledged(next.value.recvTime+((10*(txData.byteLength+2+8))/port.baud)*1000+1)}}) -// .then(function(ack) {return propComm.response.then(function() {if (ack) {return finalizeDelivery()}}).catch(function(e) {return reject(e)})}) -// .then(function(ack) {if (ack) {return finalizeDelivery()}}) // .then(function() {log("finalizeDelivery delaying resolve", mDeep); return new Promise(function() {setTimeout(resolve, 1000)});}) .then(function() {log("finalizeDelivery resolved", mDeep); return resolve();}) .catch(function(e) {return reject(e)}); From 02b3c4dfc6f646d61313863896b701dd35be9447 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Fri, 2 Feb 2018 16:58:21 -0800 Subject: [PATCH 17/44] Made same change to sendUserApp() as previous commit; resolves as separate link of promise chain to handle multiple user app packet transmissions and responses. --- serial.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/serial.js b/serial.js index 92795a4..95719d4 100644 --- a/serial.js +++ b/serial.js @@ -439,7 +439,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0xD4, 0x47, 0x35, 0xC0, 0x37, 0x00, 0xF6, 0x3F, 0x91, 0xEC, 0x23, 0x04, 0x70, 0x32, 0x00, 0x00 ];*/ //Clock Demo PABWX (adjusted for P20 through P27) - const bin = [ + /* const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0x01, 0x10, 0x00, 0x1C, 0x02, 0x50, 0x02, 0x3E, 0x00, 0x54, 0x02, 0xBC, 0x00, 0x04, 0x01, 0x2E, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x28, 0x00, 0x6B, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x6E, 0x00, 0x6F, 0x00, @@ -474,9 +474,9 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0x0F, 0x42, 0x40, 0xF6, 0x64, 0xF4, 0x39, 0x01, 0x7D, 0xE4, 0x42, 0xCC, 0x23, 0x32, 0x35, 0xC0, 0x39, 0x03, 0xE8, 0xF6, 0x64, 0xF4, 0x39, 0x01, 0x7D, 0xE4, 0x42, 0xCC, 0x23, 0x32, 0x35, 0xC0, 0x64, 0xF4, 0x39, 0x01, 0x7D, 0xE4, 0x42, 0xCC, 0x23, 0x32, 0x00, 0x00 - ]; + ];*/ //FloatMathDemoPABWX.spin - /* const bin = [ + const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0xE7, 0x10, 0x00, 0x98, 0x19, 0x8C, 0x50, 0x4C, 0x00, 0x94, 0x50, 0xC8, 0x00, 0x02, 0x03, 0x3C, 0x00, 0x04, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x98, 0x17, 0xAC, 0x36, 0x08, 0x14, 0xAC, 0x36, 0xDB, 0x0F, 0x49, 0x40, 0xF3, 0x04, 0xB5, 0x3F, 0xF3, 0x04, 0x35, 0x3F, @@ -887,7 +887,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0x27, 0xE5, 0x6D, 0x6C, 0x36, 0xF9, 0x0A, 0x0D, 0x37, 0x1E, 0x70, 0x36, 0xE2, 0xEC, 0x71, 0x6C, 0xE6, 0x72, 0x42, 0x6E, 0x18, 0x68, 0x37, 0x24, 0xE3, 0x6C, 0x38, 0x17, 0xE3, 0xEA, 0x70, 0x38, 0x09, 0xE2, 0xEA, 0x33, 0x32, 0x00, 0x00, 0x00 - ];*/ + ]; //LargeSpinCodeFlip.spin /* const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0x86, 0x10, 0x00, 0xC0, 0x7E, 0xA8, 0x7F, 0xD0, 0x79, 0xB0, 0x7F, @@ -3176,7 +3176,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { sendUA() .then(function() {return propComm.response;}) .then(function() {if (packetId > 0) {return sendUserApp()} else {return resolve()}}) -// .then(function() {return resolve()}) + .then(function() {return resolve()}) .catch(function(e) {return reject(e)}); }); } @@ -3215,7 +3215,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { send(cid, txData); //Transmit packet if (next.value.type !== ltLaunchNow) { //If not last instruction packet... - propComm.response // When response... + propComm.response // When response (promise)... .then(function() {return sendInstructionPacket()}) // is success; send next packet (if any) and .then(function() {return resolve()}) // resolve .catch(function(e) {return reject(e)}); // is failure; reject (return the error) From 0072d66496c4af8f1f5d3f5719c0b958cad028a5 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 5 Feb 2018 18:36:46 -0800 Subject: [PATCH 18/44] Removed dead code from old method of timing, simplified some code, and started work on including all error messages in download process. This version downloads properly to RAM and EEPROM. --- manifest.json | 2 +- serial.js | 121 ++++++++++++++++++++++++-------------------------- 2 files changed, 59 insertions(+), 64 deletions(-) diff --git a/manifest.json b/manifest.json index ac9a122..70f6ada 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.7.5", + "version": "0.7.6", "manifest_version": 2, "minimum_chrome_version": "45", diff --git a/serial.js b/serial.js index 95719d4..6c228a5 100644 --- a/serial.js +++ b/serial.js @@ -476,7 +476,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0x64, 0xF4, 0x39, 0x01, 0x7D, 0xE4, 0x42, 0xCC, 0x23, 0x32, 0x00, 0x00 ];*/ //FloatMathDemoPABWX.spin - const bin = [ + /*const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0xE7, 0x10, 0x00, 0x98, 0x19, 0x8C, 0x50, 0x4C, 0x00, 0x94, 0x50, 0xC8, 0x00, 0x02, 0x03, 0x3C, 0x00, 0x04, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x98, 0x17, 0xAC, 0x36, 0x08, 0x14, 0xAC, 0x36, 0xDB, 0x0F, 0x49, 0x40, 0xF3, 0x04, 0xB5, 0x3F, 0xF3, 0x04, 0x35, 0x3F, @@ -887,9 +887,9 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0x27, 0xE5, 0x6D, 0x6C, 0x36, 0xF9, 0x0A, 0x0D, 0x37, 0x1E, 0x70, 0x36, 0xE2, 0xEC, 0x71, 0x6C, 0xE6, 0x72, 0x42, 0x6E, 0x18, 0x68, 0x37, 0x24, 0xE3, 0x6C, 0x38, 0x17, 0xE3, 0xEA, 0x70, 0x38, 0x09, 0xE2, 0xEA, 0x33, 0x32, 0x00, 0x00, 0x00 - ]; + ];*/ //LargeSpinCodeFlip.spin - /* const bin = [ + const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0x86, 0x10, 0x00, 0xC0, 0x7E, 0xA8, 0x7F, 0xD0, 0x79, 0xB0, 0x7F, 0x70, 0x7A, 0x03, 0x01, 0xC0, 0x79, 0x04, 0x00, 0x15, 0x7A, 0x04, 0x00, 0x70, 0x7A, 0x04, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, @@ -2918,7 +2918,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0x38, 0xDF, 0xE8, 0xEC, 0x38, 0x27, 0x6C, 0x38, 0x38, 0xFA, 0xF4, 0xEC, 0x6D, 0x6C, 0x34, 0xFA, 0x6C, 0x68, 0xF9, 0xF0, 0x0A, 0x06, 0x60, 0x68, 0xF4, 0x6C, 0xEC, 0x61, 0x04, 0x53, 0x68, 0x38, 0x0A, 0xFC, 0x64, 0x80, 0x38, 0x2D, 0xFC, 0xF0, 0x0A, 0x03, 0x60, 0xE6, 0x61, 0x32, 0x00, 0x00 - ];*/ + ]; //Set and/or adjust postResetDelay based on platform if (!postResetDelay) { @@ -3072,51 +3072,34 @@ function talkToProp(sock, cid, binImage, toEEPROM) { function sendLoader(waittime) { // Return a promise that waits for waittime then sends communication package including loader. return new Promise(function(resolve, reject) { - log("Waiting " + Math.trunc(waittime) + " ms to deliver Micro Boot Loader package", mDeep); + log("Waiting " + Math.trunc(waittime), mDeep); setTimeout(function() { - log("Transmitting package", mDeep); + log("Transmitting Micro Boot Loader package", mDeep); send(cid, txData); resolve(); }, waittime); }); } - function isLoaderReady(packetId, waittime) { + function isLoaderReady(packetId) { /* Is Micro Boot Loader delivered and Ready? - Return a promise that waits for waittime then validates the responding Propeller Handshake, Version, and that the Micro Boot Loader delivery succeeded. + Return a promise that waits for the responding Propeller Handshake, Version, and successful Micro Boot Loader delivery. Rejects if any error occurs. Micro Boot Loader must respond with Packet ID (plus Transmission ID) for success (resolve). - Error is "Propeller not found" unless handshake received (and proper) and version received; error is more specific thereafter.*/ + Error is "Propeller not found" unless handshake received (and proper) and version received; error is more specific thereafter.*/ //!!! return new Promise(function(resolve, reject) { -//!!! function verifier() { -//!!! log("Verifying package delivery", mDeep); - //Check handshake and version -//!!! if (propComm.handshake === stValidating || propComm.handshake === stInvalid || propComm.version === stValidating) {reject(Error(notice(nePropellerNotFound))); return;} - //Check for proper version -//!!! if (propComm.version !== 1) {reject(Error(notice(neUnknownPropellerVersion, [propComm.version]))); return;} - //Check RAM checksum -//!!! if (propComm.ramCheck === stValidating) {reject(Error(notice(neCommunicationLost))); return;} -//!!! if (propComm.ramCheck === stInvalid) {reject(Error(notice(neCommunicationFailed))); return;} - //Check Micro Boot Loader Ready Signal -//!!! if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) {reject(Error(notice(neLoaderFailed))); return;} - -//!!! resolve(); -//!!! } -//!!! log("Waiting " + Math.trunc(waittime) + " ms for package delivery", mDeep); //Prep for expected packetID:transmissionId response (Micro-Boot-Loader's "Ready" signal) propComm.mblEPacketId[0] = packetId; propComm.mblETransId[0] = transmissionId; //Set up for asynchronous responses from ROM-Resident Boot Loader and finally Micro Boot Loader - log("Waiting for propComm.response", mDeep); //!!! propComm.response - .then(function() {log("received propComm.response", mDeep);}) //!!! +//!!! .then(function() {log("received propComm.response", mDeep);}) //!!! .then(function() {log(notice(000, ["Found Propeller"]), mUser+mStat, sock);}) .then(function() {return resolve()}) - // .then(function() {setTimeout(verifier, waittime);}) .catch(function(e) {return reject(e);}); }); } -//!!! + function prepForMBLResponse() { // Set propComm to prep for another Micro Boot Loader response. propComm.response = deferredPromise(); //Create new deferred promise for micro boot loader response @@ -3155,24 +3138,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { resolve(); }); } - function loaderAcknowledged(waittime) { - /* Did Micro Boot Loader acknowledge the packet? - Return a promise that waits for waittime then validates that the Micro Boot Loader acknowledged the packet. - Rejects if error occurs. Micro Boot Loader must respond with next Packet ID (plus Transmission ID) for success (resolve).*/ - return new Promise(function(resolve, reject) { - function verifier() { - log("Verifying loader acknowledgement " + (totalPackets-packetId+0) + " of " + totalPackets, mDeep); - //Check Micro Boot Loader response -//!!! if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) { -//!!! reject(Error(notice(neCommunicationFailed))); return -//!!! } - log("Packet delivered.", mDeep); - resolve(); - } - log("Waiting " + Math.trunc(waittime) + " ms for acknowledgement", mDeep); - setTimeout(verifier, waittime); - }); - } + sendUA() .then(function() {return propComm.response;}) .then(function() {if (packetId > 0) {return sendUserApp()} else {return resolve()}}) @@ -3218,7 +3184,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { propComm.response // When response (promise)... .then(function() {return sendInstructionPacket()}) // is success; send next packet (if any) and .then(function() {return resolve()}) // resolve - .catch(function(e) {return reject(e)}); // is failure; reject (return the error) + .catch(function(e) {return reject(Error(next.value.recvErr))}); // is failure; reject (return the specific error) } else { //Else, last instruction packet sent; success resolve(); // Success; User App Launched! } @@ -3226,8 +3192,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { } sendInstructionPacket() -// .then(function() {log("finalizeDelivery delaying resolve", mDeep); return new Promise(function() {setTimeout(resolve, 1000)});}) - .then(function() {log("finalizeDelivery resolved", mDeep); return resolve();}) + .then(function() {return resolve();}) .catch(function(e) {return reject(e)}); }); } @@ -3246,11 +3211,6 @@ function talkToProp(sock, cid, binImage, toEEPROM) { //Pre-generate communication and loader package (saves time during during initial communication) generateLoaderPacket(ltCore, packetId, defaultClockSpeed, defaultClockMode); - //Calculate expected max package delivery time - //=300 [>max post-reset-delay] + ((10 [bits per byte] * (data bytes [transmitting] + silence bytes [MBL waiting] + - // MBL "ready" bytes [MBL responding])) / baud rate) * 1,000 [to scale ms to integer] + 1 [to always round up] - var deliveryTime = 300+((10*(txData.byteLength+20+8))/port.baud)*1000+1; - //Prep packetGenerator iterator and next object var instPacket = packetGenerator(); var next; @@ -3262,7 +3222,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { .then(function() {return flush(cid);} ) //Flush transmit/receive buffers (during Propeller reset) .then(function() {return setControl(cid, {dtr: true});} ) //End Propeller Reset .then(function() {return sendLoader(postResetDelay);} ) //After Post-Reset-Delay, send package: Calibration Pulses+Handshake through Micro Boot Loader application+RAM Checksum Polls - .then(function() {return isLoaderReady(packetId, deliveryTime);} ) //Verify package accepted + .then(function() {return isLoaderReady(packetId);} ) //Verify package accepted .then(function() {return changeBaudrate(cid, finalBaudrate);} ) //Bump up to faster finalBaudrate .then(function() {return sendUserApp();} ) //Send user application .then(function() {return finalizeDelivery();} ) //Finalize delivery and launch user application @@ -3295,6 +3255,23 @@ function hearFromProp(info) { var stream = ab2num(info.data); var sIdx = 0; + + +//!!! function verifier() { +//!!! log("Verifying package delivery", mDeep); + //Check handshake and version +//!!! if (propComm.handshake === stValidating || propComm.handshake === stInvalid || propComm.version === stValidating) {reject(Error(notice(nePropellerNotFound))); return;} + //Check for proper version +//!!! if (propComm.version !== 1) {reject(Error(notice(neUnknownPropellerVersion, [propComm.version]))); return;} + //Check RAM checksum +//!!! if (propComm.ramCheck === stValidating) {reject(Error(notice(neCommunicationLost))); return;} +//!!! if (propComm.ramCheck === stInvalid) {reject(Error(notice(neCommunicationFailed))); return;} + //Check Micro Boot Loader Ready Signal +//!!! if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) {reject(Error(notice(neLoaderFailed))); return;} + + + + // Validate rxHandshake if (propComm.stage === sgHandshake) { while (sIdx < stream.length && propComm.rxCount < rxHandshake.length) { @@ -3303,7 +3280,7 @@ function hearFromProp(info) { //Handshake matches so far... if (propComm.rxCount === rxHandshake.length) { //Entire handshake matches! Prep for next stage - log("passed handshake", mDeep); //!!! +//!!! log("passed handshake", mDeep); //!!! propComm.rxCount = 0; propComm.stage = sgVersion; break; @@ -3327,7 +3304,7 @@ function hearFromProp(info) { //Received all 4 bytes if (propComm.version === 1) { //Version matches expected value! Prep for next stage - log("passed version", mDeep); //!!! +//!!! log("passed version", mDeep); //!!! propComm.rxCount = 0; propComm.stage = sgRAMChecksum; } else { @@ -3340,12 +3317,31 @@ function hearFromProp(info) { } } + //Check handshake and version +//!!! if (propComm.handshake === stValidating || propComm.handshake === stInvalid || propComm.version === stValidating) {reject(Error(notice(nePropellerNotFound))); return;} + //Check for proper version +//!!! if (propComm.version !== 1) {reject(Error(notice(neUnknownPropellerVersion, [propComm.version]))); return;} + //Check RAM checksum +//!!! if (propComm.ramCheck === stValidating) {reject(Error(notice(neCommunicationLost))); return;} +//!!! if (propComm.ramCheck === stInvalid) {reject(Error(notice(neCommunicationFailed))); return;} + //Check Micro Boot Loader Ready Signal +//!!! if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) {reject(Error(notice(neLoaderFailed))); return;} + + +//!!! SendUserApp + //Check Micro Boot Loader response +//!!! if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) { +//!!! reject(Error(notice(neCommunicationFailed))); return +//!!! } + + + // Receive RAM Checksum if (propComm.stage === sgRAMChecksum && sIdx < stream.length) { //Received RAM Checksum response? if (stream[sIdx++] === 0xFE) { //RAM Checksum valid; Prep for next stage - log("passed RAM checksum", mDeep); //!!! +//!!! log("passed RAM checksum", mDeep); //!!! propComm.stage = sgMBLResponse; } else { //RAM Checksum invalid; Note rejected; Ignore the rest @@ -3362,18 +3358,17 @@ function hearFromProp(info) { //Finish stage when expected response size received if (propComm.rxCount === propComm.mblRespBuf.byteLength) { propComm.stage = sgIdle; - log("Response PacketId: "+ propComm.mblRPacketId+ " TransId: "+ propComm.mblRTransId, mDeep); //!!! - log("Expected PacketId: "+ propComm.mblEPacketId+ " TransId: "+ propComm.mblETransId, mDeep); //!!! +//!!! log("Response PacketId: "+ propComm.mblRPacketId+ " TransId: "+ propComm.mblRTransId, mDeep); //!!! +//!!! log("Expected PacketId: "+ propComm.mblEPacketId+ " TransId: "+ propComm.mblETransId, mDeep); //!!! if ((propComm.mblRPacketId[0] === propComm.mblEPacketId[0]) && (propComm.mblRTransId[0] === propComm.mblETransId[0])) { //MBL Response is perfect; Note resolved - log("passed response", mDeep); //!!! +//!!! log("passed response", mDeep); //!!! propComm.response.resolve(); - propComm.stage = sgIdle; } else { //MBL Response invalid; Note rejected; Ignore the rest propComm.response.reject(Error(notice(neLoaderFailed))); - propComm.stage = sgIdle; } + propComm.stage = sgIdle; //Valid if end of stream, otherwise something's wrong (invalid response) //!!! propComm.mblResponse = stream.length === sIdx ? stValid : stInvalid; From aedabde250e6ac7b605bfd4491cf900434084331 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 5 Feb 2018 18:45:36 -0800 Subject: [PATCH 19/44] Version bumped to 0.7.6 (in previous commit). Moved some comments related to extra error messages. --- serial.js | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/serial.js b/serial.js index 6c228a5..4922447 100644 --- a/serial.js +++ b/serial.js @@ -3080,7 +3080,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { }, waittime); }); } - + //TODO see if isLoaderReady can be combined with sendLoader function isLoaderReady(packetId) { /* Is Micro Boot Loader delivered and Ready? Return a promise that waits for the responding Propeller Handshake, Version, and successful Micro Boot Loader delivery. @@ -3096,7 +3096,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { //!!! .then(function() {log("received propComm.response", mDeep);}) //!!! .then(function() {log(notice(000, ["Found Propeller"]), mUser+mStat, sock);}) .then(function() {return resolve()}) - .catch(function(e) {return reject(e);}); + .catch(function(e) {return reject(e)}); }); } @@ -3107,7 +3107,6 @@ function talkToProp(sock, cid, binImage, toEEPROM) { propComm.rxCount = 0; } - //TODO lower waittime //TODO catch send() errors //TODO add transmitPacket function to auto-retry 3 times if needing to harden against flaky wireless connections //TODO determine if txPacketLength and idx can refer to bytes instead of longs to lessen iterative calculations @@ -3317,25 +3316,6 @@ function hearFromProp(info) { } } - //Check handshake and version -//!!! if (propComm.handshake === stValidating || propComm.handshake === stInvalid || propComm.version === stValidating) {reject(Error(notice(nePropellerNotFound))); return;} - //Check for proper version -//!!! if (propComm.version !== 1) {reject(Error(notice(neUnknownPropellerVersion, [propComm.version]))); return;} - //Check RAM checksum -//!!! if (propComm.ramCheck === stValidating) {reject(Error(notice(neCommunicationLost))); return;} -//!!! if (propComm.ramCheck === stInvalid) {reject(Error(notice(neCommunicationFailed))); return;} - //Check Micro Boot Loader Ready Signal -//!!! if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) {reject(Error(notice(neLoaderFailed))); return;} - - -//!!! SendUserApp - //Check Micro Boot Loader response -//!!! if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) { -//!!! reject(Error(notice(neCommunicationFailed))); return -//!!! } - - - // Receive RAM Checksum if (propComm.stage === sgRAMChecksum && sIdx < stream.length) { //Received RAM Checksum response? @@ -3351,6 +3331,16 @@ function hearFromProp(info) { propComm.rxCount = 0; } + + +//!!! SendUserApp + //Check Micro Boot Loader response +//!!! if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) { +//!!! reject(Error(notice(neCommunicationFailed))); return +//!!! } + + + // Receive Micro Boot Loader's response. The first is its "Ready" signal; the rest are packet responses. if (propComm.stage === sgMBLResponse) { while (sIdx < stream.length && propComm.rxCount < propComm.mblRespBuf.byteLength) { From 284df55cba266dafa90c461893d3b10f3f17a280 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 5 Feb 2018 19:05:40 -0800 Subject: [PATCH 20/44] Combined loaderReady() with sendLoader(). --- serial.js | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/serial.js b/serial.js index 4922447..7ee994a 100644 --- a/serial.js +++ b/serial.js @@ -3070,35 +3070,28 @@ function talkToProp(sock, cid, binImage, toEEPROM) { //!!! End Experimental code function sendLoader(waittime) { - // Return a promise that waits for waittime then sends communication package including loader. + /* Return a promise that waits for waittime milliseconds, then sends communication package including loader, then waits for the responding + Propeller Handshake, Version, and successful Micro Boot Loader delivery notice. + Rejects if any error occurs. Micro Boot Loader must respond with Packet ID (plus Transmission ID) for success (resolve). + Error is "Propeller not found" unless handshake received (and proper) and version received; error is more specific thereafter. //!!! + */ return new Promise(function(resolve, reject) { - log("Waiting " + Math.trunc(waittime), mDeep); + log("Waiting " + Math.trunc(waittime) + " ms", mDeep); setTimeout(function() { + //Prep for expected packetID:transmissionId response (Micro-Boot-Loader's "Ready" signal) + propComm.mblEPacketId[0] = packetId; + propComm.mblETransId[0] = transmissionId; + //Send Micro Boot Loader package log("Transmitting Micro Boot Loader package", mDeep); send(cid, txData); - resolve(); + //Wait for response + propComm.response + .then(function() {log(notice(000, ["Found Propeller"]), mUser+mDbug, sock);}) + .then(function() {return resolve()}) + .catch(function(e) {return reject(e)}); }, waittime); }); } - //TODO see if isLoaderReady can be combined with sendLoader - function isLoaderReady(packetId) { - /* Is Micro Boot Loader delivered and Ready? - Return a promise that waits for the responding Propeller Handshake, Version, and successful Micro Boot Loader delivery. - Rejects if any error occurs. Micro Boot Loader must respond with Packet ID (plus Transmission ID) for success (resolve). - Error is "Propeller not found" unless handshake received (and proper) and version received; error is more specific thereafter.*/ //!!! - - return new Promise(function(resolve, reject) { - //Prep for expected packetID:transmissionId response (Micro-Boot-Loader's "Ready" signal) - propComm.mblEPacketId[0] = packetId; - propComm.mblETransId[0] = transmissionId; - //Set up for asynchronous responses from ROM-Resident Boot Loader and finally Micro Boot Loader - propComm.response -//!!! .then(function() {log("received propComm.response", mDeep);}) //!!! - .then(function() {log(notice(000, ["Found Propeller"]), mUser+mStat, sock);}) - .then(function() {return resolve()}) - .catch(function(e) {return reject(e)}); - }); - } function prepForMBLResponse() { // Set propComm to prep for another Micro Boot Loader response. @@ -3220,8 +3213,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { .then(function() {return setControl(cid, {dtr: false});} ) //Start Propeller Reset Signal .then(function() {return flush(cid);} ) //Flush transmit/receive buffers (during Propeller reset) .then(function() {return setControl(cid, {dtr: true});} ) //End Propeller Reset - .then(function() {return sendLoader(postResetDelay);} ) //After Post-Reset-Delay, send package: Calibration Pulses+Handshake through Micro Boot Loader application+RAM Checksum Polls - .then(function() {return isLoaderReady(packetId);} ) //Verify package accepted + .then(function() {return sendLoader(postResetDelay);} ) //After Post-Reset-Delay, send package (Calibration Pulses+Handshake through Micro Boot Loader application+RAM Checksum Polls) and verify acceptance .then(function() {return changeBaudrate(cid, finalBaudrate);} ) //Bump up to faster finalBaudrate .then(function() {return sendUserApp();} ) //Send user application .then(function() {return finalizeDelivery();} ) //Finalize delivery and launch user application @@ -3332,7 +3324,7 @@ function hearFromProp(info) { } - + //!!! SendUserApp //Check Micro Boot Loader response //!!! if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) { From 83a82b402e4c419a82c5fe0b264df05553277fd1 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 5 Feb 2018 19:48:19 -0800 Subject: [PATCH 21/44] Found that conditional resolve() in sendUserApp was unnecessary. --- serial.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/serial.js b/serial.js index 7ee994a..0580f7e 100644 --- a/serial.js +++ b/serial.js @@ -889,7 +889,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0x09, 0xE2, 0xEA, 0x33, 0x32, 0x00, 0x00, 0x00 ];*/ //LargeSpinCodeFlip.spin - const bin = [ + const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0x86, 0x10, 0x00, 0xC0, 0x7E, 0xA8, 0x7F, 0xD0, 0x79, 0xB0, 0x7F, 0x70, 0x7A, 0x03, 0x01, 0xC0, 0x79, 0x04, 0x00, 0x15, 0x7A, 0x04, 0x00, 0x70, 0x7A, 0x04, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, @@ -3070,8 +3070,8 @@ function talkToProp(sock, cid, binImage, toEEPROM) { //!!! End Experimental code function sendLoader(waittime) { - /* Return a promise that waits for waittime milliseconds, then sends communication package including loader, then waits for the responding - Propeller Handshake, Version, and successful Micro Boot Loader delivery notice. + /* Return a promise that waits for waittime milliseconds, then sends communication package (Timing Pulses, Host Handshake, and Micro Boot Loader), + then waits for the responding Propeller Handshake, Version, and successful Micro Boot Loader delivery notice. Rejects if any error occurs. Micro Boot Loader must respond with Packet ID (plus Transmission ID) for success (resolve). Error is "Propeller not found" unless handshake received (and proper) and version received; error is more specific thereafter. //!!! */ @@ -3094,7 +3094,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { } function prepForMBLResponse() { - // Set propComm to prep for another Micro Boot Loader response. + // Set propComm to prep for another Micro Boot Loader response. propComm.response = deferredPromise(); //Create new deferred promise for micro boot loader response propComm.stage = sgMBLResponse; propComm.rxCount = 0; @@ -3131,11 +3131,11 @@ function talkToProp(sock, cid, binImage, toEEPROM) { }); } - sendUA() - .then(function() {return propComm.response;}) - .then(function() {if (packetId > 0) {return sendUserApp()} else {return resolve()}}) - .then(function() {return resolve()}) - .catch(function(e) {return reject(e)}); + sendUA() //Send user application packet + .then(function() {return propComm.response;}) //Wait for response + .then(function() {if (packetId > 0) {return sendUserApp()}}) //More packets? repeat + .then(function() {return resolve()}) //else, resolve + .catch(function(e) {return reject(e)}); //Error? return error message }); } From 66bb5dfbffae948799b26e4668635c4bfccaad4d Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Tue, 6 Feb 2018 11:02:09 -0800 Subject: [PATCH 22/44] Created propComm timer, timerError, and related code in hearFromProp() to handle communication timeouts. Next need to update talkToProp() to adjust the timer and error at other parts of the protocol. --- serial.js | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/serial.js b/serial.js index 0580f7e..8655d24 100644 --- a/serial.js +++ b/serial.js @@ -59,7 +59,9 @@ const propCommStart = { //propCommStart is used to mblRPacketId : new Int32Array(mblRespAB, 0, 1), //Micro Boot Loader requested next packet id (32-bit signed int format) mblRTransId : new Int32Array(mblRespAB, 4, 1), //Micro Boot Loader response-to transmission id (32-bit signed int format) mblEPacketId : new Int32Array(mblExpdAB, 0, 1), //Micro Boot Loader expected next packet id (32-bit signed int format) - mblETransId : new Int32Array(mblExpdAB, 4, 1) //Micro Boot Loader expected transmission id (32-bit signed int format) + mblETransId : new Int32Array(mblExpdAB, 4, 1), //Micro Boot Loader expected transmission id (32-bit signed int format) + timer : null, //Holds current timeout timer + timeoutError : "" //Error to issue at end of next timeout //!!! eeProg : stValidating, //!!! eeCheck : stValidating }; @@ -2986,7 +2988,20 @@ function resetPropComm() { /*Reset propComm object to default values*/ Object.assign(propComm, propCommStart); //Reset propComm object propComm.response = deferredPromise(); //Create new deferred promise for micro boot loader response + setPropCommTimer(0, notice(nePropellerNotFound)); //Default to "Propeller Not Found" error +} +function setPropCommTimer(timeout, timeoutError) { +/* Set timeout timer for Propeller Communication + timeout = timeout period (in ms) + timeoutError = string message to issue upon a timeout +*/ + propComm.timeoutError = timeoutError; + propComm.timer = setTimeout(function() { + log("Timed out!", mDbug); //!!! + propComm.response.reject(Error(propComm.timeoutError)); + propComm.timer = null; + }, timeout); } function talkToProp(sock, cid, binImage, toEEPROM) { @@ -3093,11 +3108,15 @@ function talkToProp(sock, cid, binImage, toEEPROM) { }); } - function prepForMBLResponse() { - // Set propComm to prep for another Micro Boot Loader response. + function prepForMBLResponse(timeout, timeoutError) { + /* Set propComm to prep for another Micro Boot Loader response. + timeout = timeout period (in ms) + timeoutError = string message to issue upon a timeout + */ propComm.response = deferredPromise(); //Create new deferred promise for micro boot loader response propComm.stage = sgMBLResponse; propComm.rxCount = 0; + setPropCommTimer(timeout, timeoutError); } //TODO catch send() errors @@ -3246,23 +3265,6 @@ function hearFromProp(info) { var stream = ab2num(info.data); var sIdx = 0; - - -//!!! function verifier() { -//!!! log("Verifying package delivery", mDeep); - //Check handshake and version -//!!! if (propComm.handshake === stValidating || propComm.handshake === stInvalid || propComm.version === stValidating) {reject(Error(notice(nePropellerNotFound))); return;} - //Check for proper version -//!!! if (propComm.version !== 1) {reject(Error(notice(neUnknownPropellerVersion, [propComm.version]))); return;} - //Check RAM checksum -//!!! if (propComm.ramCheck === stValidating) {reject(Error(notice(neCommunicationLost))); return;} -//!!! if (propComm.ramCheck === stInvalid) {reject(Error(notice(neCommunicationFailed))); return;} - //Check Micro Boot Loader Ready Signal -//!!! if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) {reject(Error(notice(neLoaderFailed))); return;} - - - - // Validate rxHandshake if (propComm.stage === sgHandshake) { while (sIdx < stream.length && propComm.rxCount < rxHandshake.length) { @@ -3278,6 +3280,7 @@ function hearFromProp(info) { } } else { //Handshake failure! Note rejected; Ignore the rest + clearTimeout(propComm.timer); propComm.response.reject(Error(notice(nePropellerNotFound))); propComm.stage = sgIdle; break; @@ -3296,10 +3299,13 @@ function hearFromProp(info) { if (propComm.version === 1) { //Version matches expected value! Prep for next stage //!!! log("passed version", mDeep); //!!! + //Found Propeller; update timeout for next possible error (if no RAM Checksum received or no Micro Boot Loader response received) + propComm.timeoutError(notice(neCommunicationLost)); propComm.rxCount = 0; propComm.stage = sgRAMChecksum; } else { //Unexpected version! Note rejected; Ignore the rest + clearTimeout(propComm.timer); propComm.response.reject(Error(notice(neUnknownPropellerVersion, [propComm.version]))); propComm.stage = sgIdle; } @@ -3317,6 +3323,7 @@ function hearFromProp(info) { propComm.stage = sgMBLResponse; } else { //RAM Checksum invalid; Note rejected; Ignore the rest + clearTimeout(propComm.timer); propComm.response.reject(Error(notice(neCommunicationFailed))); propComm.stage = sgIdle; } @@ -3339,6 +3346,7 @@ function hearFromProp(info) { propComm.mblRespBuf[propComm.rxCount++] = stream[sIdx++]; //Finish stage when expected response size received if (propComm.rxCount === propComm.mblRespBuf.byteLength) { + clearTimeout(propComm.timer); propComm.stage = sgIdle; //!!! log("Response PacketId: "+ propComm.mblRPacketId+ " TransId: "+ propComm.mblRTransId, mDeep); //!!! //!!! log("Expected PacketId: "+ propComm.mblEPacketId+ " TransId: "+ propComm.mblETransId, mDeep); //!!! @@ -3350,7 +3358,6 @@ function hearFromProp(info) { //MBL Response invalid; Note rejected; Ignore the rest propComm.response.reject(Error(notice(neLoaderFailed))); } - propComm.stage = sgIdle; //Valid if end of stream, otherwise something's wrong (invalid response) //!!! propComm.mblResponse = stream.length === sIdx ? stValid : stInvalid; From ab5eb6d8d732d754c2e79b586449fde3ddd38ac3 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Tue, 6 Feb 2018 20:23:09 -0800 Subject: [PATCH 23/44] Added timeout parameter for resetPropComm and noted need for arguments on prepForMBLResponse. --- serial.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/serial.js b/serial.js index 8655d24..e0bc1b9 100644 --- a/serial.js +++ b/serial.js @@ -2984,11 +2984,13 @@ function listen(engage) { } } -function resetPropComm() { -/*Reset propComm object to default values*/ +function resetPropComm(timeout) { +/*Reset propComm object to default values + timeout = period (in ms) for initial timeout +*/ Object.assign(propComm, propCommStart); //Reset propComm object propComm.response = deferredPromise(); //Create new deferred promise for micro boot loader response - setPropCommTimer(0, notice(nePropellerNotFound)); //Default to "Propeller Not Found" error + setPropCommTimer(timeout, notice(nePropellerNotFound)); //Default to "Propeller Not Found" error } function setPropCommTimer(timeout, timeoutError) { @@ -3130,7 +3132,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { return new Promise(function(resolve, reject) { log("Delivering user application packet " + (totalPackets-packetId+1) + " of " + totalPackets, mDbug); log(notice(nsDownloading), mUser, sock); - prepForMBLResponse(); + prepForMBLResponse(//###, notice(neCommunicationLost)); var txPacketLength = 2 + //Determine packet length (in longs); header + packet limit or remaining data length Math.min(Math.trunc(maxDataSize / 4) - 2, Math.trunc(binImage.byteLength / 4) - pIdx); txData = new ArrayBuffer(txPacketLength * 4); //Set packet length (in longs)} @@ -3183,7 +3185,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { if (next.value.type !== ltLaunchNow) { //Response expected from MBL? - prepForMBLResponse(); // Prepare to receive next MBL response + prepForMBLResponse(//!!!, error?); // Prepare to receive next MBL response packetId = next.value.nextId; // Ready next Packet ID propComm.mblEPacketId[0] = packetId; // Note expected response propComm.mblETransId[0] = transmissionId; @@ -3226,8 +3228,13 @@ function talkToProp(sock, cid, binImage, toEEPROM) { var instPacket = packetGenerator(); var next; + //Calculate expected max package delivery time + //=300 [>max post-reset-delay] + ((10 [bits per byte] * (data bytes [transmitting] + 20 silence bytes [MBL waiting] + + // 8 MBL "ready" bytes [MBL responding])) / baud rate) * 1,000 [to scale ms to integer] + 1 [to always round up] + var deliveryTime = 300+((10*(txData.byteLength+20+8))/port.baud)*1000+1; + Promise.resolve() - .then(function() { resetPropComm();} ) //Reset propComm object + .then(function() { resetPropComm(deliveryTime);} ) //Reset propComm object .then(function() { log("Generating reset signal", mDeep);} ) .then(function() {return setControl(cid, {dtr: false});} ) //Start Propeller Reset Signal .then(function() {return flush(cid);} ) //Flush transmit/receive buffers (during Propeller reset) @@ -3299,7 +3306,7 @@ function hearFromProp(info) { if (propComm.version === 1) { //Version matches expected value! Prep for next stage //!!! log("passed version", mDeep); //!!! - //Found Propeller; update timeout for next possible error (if no RAM Checksum received or no Micro Boot Loader response received) + //Found Propeller; update timeout for next possible error (if no RAM Checksum or Micro Boot Loader response received) propComm.timeoutError(notice(neCommunicationLost)); propComm.rxCount = 0; propComm.stage = sgRAMChecksum; From 1c5cc1dbe80284862e963a74e11150e692a15328 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Wed, 7 Feb 2018 17:40:13 -0800 Subject: [PATCH 24/44] Fixed bug, added timeout for user app packets and final packets. Need to optimize logs and timeout. --- messages.js | 2 +- serial.js | 29 +++++++++++++++++------------ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/messages.js b/messages.js index 0296ad8..15c5dc7 100644 --- a/messages.js +++ b/messages.js @@ -79,7 +79,7 @@ notices = { [neRAMChecksumFailed] : "RAM checksum failed", [neEEPROMVerifyFailed] : "EEPROM verify failed", [neCommunicationLost] : "Communication lost", /*No response*/ - [neLoaderFailed] : "Loader failed", + [neLoaderFailed] : "Loader failed", /*Response invalid*/ [neCommunicationFailed] : "Communication failed" /*Response unexpected*/ }; diff --git a/serial.js b/serial.js index e0bc1b9..065ca01 100644 --- a/serial.js +++ b/serial.js @@ -2976,7 +2976,6 @@ function listen(engage) { engage = true to add listener; false to remove listener.*/ if (engage) { //Add programming protocol serial receive handler - resetPropComm(); chrome.serial.onReceive.addListener(hearFromProp); } else { //Remove programming protocol serial receive handler @@ -2999,8 +2998,9 @@ function setPropCommTimer(timeout, timeoutError) { timeoutError = string message to issue upon a timeout */ propComm.timeoutError = timeoutError; + clearTimeout(propComm.timer); propComm.timer = setTimeout(function() { - log("Timed out!", mDbug); //!!! + log("Timed out in " + timeout, mDbug); //!!! propComm.response.reject(Error(propComm.timeoutError)); propComm.timer = null; }, timeout); @@ -3129,10 +3129,11 @@ function talkToProp(sock, cid, binImage, toEEPROM) { return new Promise(function(resolve, reject) { function sendUA() { + return new Promise(function(resolve, reject) { - log("Delivering user application packet " + (totalPackets-packetId+1) + " of " + totalPackets, mDbug); + log((totalPackets-packetId+1) + " of " + totalPackets, mDbug); log(notice(nsDownloading), mUser, sock); - prepForMBLResponse(//###, notice(neCommunicationLost)); + prepForMBLResponse(userDeliveryTime, notice(neCommunicationLost)); var txPacketLength = 2 + //Determine packet length (in longs); header + packet limit or remaining data length Math.min(Math.trunc(maxDataSize / 4) - 2, Math.trunc(binImage.byteLength / 4) - pIdx); txData = new ArrayBuffer(txPacketLength * 4); //Set packet length (in longs)} @@ -3185,7 +3186,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { if (next.value.type !== ltLaunchNow) { //Response expected from MBL? - prepForMBLResponse(//!!!, error?); // Prepare to receive next MBL response + prepForMBLResponse(userDeliveryTime, notice(neCommunicationLost)); // Prepare to receive next MBL response packetId = next.value.nextId; // Ready next Packet ID propComm.mblEPacketId[0] = packetId; // Note expected response propComm.mblETransId[0] = transmissionId; @@ -3228,23 +3229,26 @@ function talkToProp(sock, cid, binImage, toEEPROM) { var instPacket = packetGenerator(); var next; - //Calculate expected max package delivery time + //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])) / baud rate) * 1,000 [to scale ms to integer] + 1 [to always round up] - var deliveryTime = 300+((10*(txData.byteLength+20+8))/port.baud)*1000+1; + // 8 MBL "ready" bytes [MBL responding])) / initial baud rate) * 1,000 [to scale ms to integer] + 1 [to always round up] + var mblDeliveryTime = 300+((10*(txData.byteLength+20+8))/initialBaudrate)*100000+1; + + //=((10 [bits per byte] * [max packet size]) / final baud rate) * 1,000 [to scale ms to integer] + 1 [to always round up] + var userDeliveryTime = ((10*maxDataSize)/finalBaudrate)*100000+1; Promise.resolve() - .then(function() { resetPropComm(deliveryTime);} ) //Reset propComm object + .then(function() { resetPropComm(mblDeliveryTime);} ) //Reset propComm object .then(function() { log("Generating reset signal", mDeep);} ) .then(function() {return setControl(cid, {dtr: false});} ) //Start Propeller Reset Signal .then(function() {return flush(cid);} ) //Flush transmit/receive buffers (during Propeller reset) .then(function() {return setControl(cid, {dtr: true});} ) //End Propeller Reset .then(function() {return sendLoader(postResetDelay);} ) //After Post-Reset-Delay, send package (Calibration Pulses+Handshake through Micro Boot Loader application+RAM Checksum Polls) and verify acceptance .then(function() {return changeBaudrate(cid, finalBaudrate);} ) //Bump up to faster finalBaudrate - .then(function() {return sendUserApp();} ) //Send user application + .then(function() {log("Delivering user application packets", mDbug); return sendUserApp();} ) //Send user application .then(function() {return finalizeDelivery();} ) //Finalize delivery and launch user application .then(function() {return resolve();} ) //Success! - .catch(function(e) {reject(e)} ); //Catch errors, pass them on + .catch(function(e) {clearTimeout(propComm.timer); reject(e);} ); //Catch errors, pass them on }); } @@ -3307,7 +3311,7 @@ function hearFromProp(info) { //Version matches expected value! Prep for next stage //!!! log("passed version", mDeep); //!!! //Found Propeller; update timeout for next possible error (if no RAM Checksum or Micro Boot Loader response received) - propComm.timeoutError(notice(neCommunicationLost)); + propComm.timeoutError = notice(neCommunicationLost); propComm.rxCount = 0; propComm.stage = sgRAMChecksum; } else { @@ -3363,6 +3367,7 @@ function hearFromProp(info) { propComm.response.resolve(); } else { //MBL Response invalid; Note rejected; Ignore the rest + clearTimeout(propComm.timer); propComm.response.reject(Error(notice(neLoaderFailed))); } //Valid if end of stream, otherwise something's wrong (invalid response) From 23940a479b2905b1751efb201e56fca8cf7e1b97 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Thu, 8 Feb 2018 13:20:34 -0800 Subject: [PATCH 25/44] Re-added resetPropComm call in listen() but with no timeout which now means to start in idle state with no promise or timeout timer. Optimized setPropCommTimer code. Optimized timeout delays for mblDeliveryTime and userDeliveryTime. --- serial.js | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/serial.js b/serial.js index 065ca01..b9e7631 100644 --- a/serial.js +++ b/serial.js @@ -51,7 +51,7 @@ let mblRespAB = new ArrayBuffer(8); //Buffer for Micro Boot Loa let mblExpdAB = new ArrayBuffer(8); //Buffer for Micro Boot Loader expected responses const propCommStart = { //propCommStart is used to initialize propComm - stage : sgHandshake, //Propeller Protocol Stage + stage : sgIdle, //Propeller Protocol Stage response : null, //Micro Boot Loader response signal (Promise) rxCount : 0, //Current count of receive bytes (for stage) version : 0, //Propeller firmware version number @@ -2976,6 +2976,7 @@ function listen(engage) { engage = true to add listener; false to remove listener.*/ if (engage) { //Add programming protocol serial receive handler + resetPropComm(); chrome.serial.onReceive.addListener(hearFromProp); } else { //Remove programming protocol serial receive handler @@ -2985,11 +2986,14 @@ function listen(engage) { function resetPropComm(timeout) { /*Reset propComm object to default values - timeout = period (in ms) for initial timeout + timeout = [optional] period (in ms) for initial timeout. If provided, sets stage to sgHandshake, creates deferred promise, and creates timeout timer. */ - Object.assign(propComm, propCommStart); //Reset propComm object - propComm.response = deferredPromise(); //Create new deferred promise for micro boot loader response - setPropCommTimer(timeout, notice(nePropellerNotFound)); //Default to "Propeller Not Found" error + Object.assign(propComm, propCommStart); //Reset propComm object + if (timeout) { //If timeout provided + propComm.stage = sgHandshake; //Ready for handshake + propComm.response = deferredPromise(); //Create new deferred promise for micro boot loader response + setPropCommTimer(timeout, notice(nePropellerNotFound)); //Default to "Propeller Not Found" error + }; } function setPropCommTimer(timeout, timeoutError) { @@ -2997,10 +3001,11 @@ function setPropCommTimer(timeout, timeoutError) { timeout = timeout period (in ms) timeoutError = string message to issue upon a timeout */ - propComm.timeoutError = timeoutError; clearTimeout(propComm.timer); + propComm.timeoutError = timeoutError; + timeout = Math.trunc(timeout); propComm.timer = setTimeout(function() { - log("Timed out in " + timeout, mDbug); //!!! + log("Timed out in " + timeout + " ms", mDbug); //!!! propComm.response.reject(Error(propComm.timeoutError)); propComm.timer = null; }, timeout); @@ -3229,13 +3234,13 @@ function talkToProp(sock, cid, binImage, toEEPROM) { var instPacket = packetGenerator(); 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] - var mblDeliveryTime = 300+((10*(txData.byteLength+20+8))/initialBaudrate)*100000+1; + /* 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] */ + var mblDeliveryTime = 300+((10*(txData.byteLength+20+8))/initialBaudrate)*1000+1; - //=((10 [bits per byte] * [max packet size]) / final baud rate) * 1,000 [to scale ms to integer] + 1 [to always round up] - var userDeliveryTime = ((10*maxDataSize)/finalBaudrate)*100000+1; + //=((10 [bits per byte] * [max packet size]) / final baud rate) * 1,000 [to scale ms to integer] + 1 [to always round up] + 750 [Rx hardware to OS slack time] + var userDeliveryTime = ((10*maxDataSize)/finalBaudrate)*1000+1+500; Promise.resolve() .then(function() { resetPropComm(mblDeliveryTime);} ) //Reset propComm object From 272a96c6bcc413c15094cf1689a421807d38ea39 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Thu, 8 Feb 2018 13:40:13 -0800 Subject: [PATCH 26/44] Set finalizeDelivery() to use variable timeouts depending on instructional packet type. --- serial.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/serial.js b/serial.js index b9e7631..4da9270 100644 --- a/serial.js +++ b/serial.js @@ -441,7 +441,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0xD4, 0x47, 0x35, 0xC0, 0x37, 0x00, 0xF6, 0x3F, 0x91, 0xEC, 0x23, 0x04, 0x70, 0x32, 0x00, 0x00 ];*/ //Clock Demo PABWX (adjusted for P20 through P27) - /* const bin = [ + const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0x01, 0x10, 0x00, 0x1C, 0x02, 0x50, 0x02, 0x3E, 0x00, 0x54, 0x02, 0xBC, 0x00, 0x04, 0x01, 0x2E, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x28, 0x00, 0x6B, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x6E, 0x00, 0x6F, 0x00, @@ -476,7 +476,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0x0F, 0x42, 0x40, 0xF6, 0x64, 0xF4, 0x39, 0x01, 0x7D, 0xE4, 0x42, 0xCC, 0x23, 0x32, 0x35, 0xC0, 0x39, 0x03, 0xE8, 0xF6, 0x64, 0xF4, 0x39, 0x01, 0x7D, 0xE4, 0x42, 0xCC, 0x23, 0x32, 0x35, 0xC0, 0x64, 0xF4, 0x39, 0x01, 0x7D, 0xE4, 0x42, 0xCC, 0x23, 0x32, 0x00, 0x00 - ];*/ + ]; //FloatMathDemoPABWX.spin /*const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0xE7, 0x10, 0x00, 0x98, 0x19, 0x8C, 0x50, 0x4C, 0x00, 0x94, 0x50, @@ -891,7 +891,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0x09, 0xE2, 0xEA, 0x33, 0x32, 0x00, 0x00, 0x00 ];*/ //LargeSpinCodeFlip.spin - const bin = [ + /*const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0x86, 0x10, 0x00, 0xC0, 0x7E, 0xA8, 0x7F, 0xD0, 0x79, 0xB0, 0x7F, 0x70, 0x7A, 0x03, 0x01, 0xC0, 0x79, 0x04, 0x00, 0x15, 0x7A, 0x04, 0x00, 0x70, 0x7A, 0x04, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, @@ -2920,7 +2920,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0x38, 0xDF, 0xE8, 0xEC, 0x38, 0x27, 0x6C, 0x38, 0x38, 0xFA, 0xF4, 0xEC, 0x6D, 0x6C, 0x34, 0xFA, 0x6C, 0x68, 0xF9, 0xF0, 0x0A, 0x06, 0x60, 0x68, 0xF4, 0x6C, 0xEC, 0x61, 0x04, 0x53, 0x68, 0x38, 0x0A, 0xFC, 0x64, 0x80, 0x38, 0x2D, 0xFC, 0xF0, 0x0A, 0x03, 0x60, 0xE6, 0x61, 0x32, 0x00, 0x00 - ]; + ];*/ //Set and/or adjust postResetDelay based on platform if (!postResetDelay) { @@ -3168,11 +3168,11 @@ function talkToProp(sock, cid, binImage, toEEPROM) { function* packetGenerator() { //Packet specification generator; generates details for the next packet - yield {type: ltVerifyRAM, nextId: -checksum, sendLog: notice(nsVerifyingRAM), recvTime: 800, recvErr: notice(neRAMChecksumFailed)}; + yield {type: ltVerifyRAM, nextId: -checksum, sendLog: notice(nsVerifyingRAM), recvTime: userDeliveryTime, recvErr: notice(neRAMChecksumFailed)}; if (toEEPROM) { - yield {type: ltProgramEEPROM, nextId: -checksum*2, sendLog: notice(nsVerifyingEEPROM), recvTime: 4500, recvErr: notice(neEEPROMVerifyFailed)}; + yield {type: ltProgramEEPROM, nextId: -checksum*2, sendLog: notice(nsVerifyingEEPROM), recvTime: userDeliveryTime+4000, recvErr: notice(neEEPROMVerifyFailed)}; } - yield {type: ltReadyToLaunch, nextId: packetId-1, sendLog: notice(000, ["Ready for Launch"]), recvTime: 800, recvErr: notice(neCommunicationLost)}; + yield {type: ltReadyToLaunch, nextId: packetId-1, sendLog: notice(000, ["Ready for Launch"]), recvTime: userDeliveryTime, recvErr: notice(neCommunicationLost)}; yield {type: ltLaunchNow, nextId: -1, sendLog: notice(000, ["Launching"]), recvTime: 0, recvErr: ""}; } @@ -3191,7 +3191,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { if (next.value.type !== ltLaunchNow) { //Response expected from MBL? - prepForMBLResponse(userDeliveryTime, notice(neCommunicationLost)); // Prepare to receive next MBL response + prepForMBLResponse(next.value.recvTime, notice(neCommunicationLost)); // Prepare to receive next MBL response packetId = next.value.nextId; // Ready next Packet ID propComm.mblEPacketId[0] = packetId; // Note expected response propComm.mblETransId[0] = transmissionId; From bc9b89441355ba6e64251ca41ce15e5c1676d90d Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Thu, 8 Feb 2018 14:13:49 -0800 Subject: [PATCH 27/44] Added continuous progress indicator for finalizeDelivery() so that extra time for RAM Checksum and especially EEPROM verification don't leave user wondering if anything is happening. --- serial.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/serial.js b/serial.js index 4da9270..145dcc3 100644 --- a/serial.js +++ b/serial.js @@ -441,7 +441,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0xD4, 0x47, 0x35, 0xC0, 0x37, 0x00, 0xF6, 0x3F, 0x91, 0xEC, 0x23, 0x04, 0x70, 0x32, 0x00, 0x00 ];*/ //Clock Demo PABWX (adjusted for P20 through P27) - const bin = [ + /* const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0x01, 0x10, 0x00, 0x1C, 0x02, 0x50, 0x02, 0x3E, 0x00, 0x54, 0x02, 0xBC, 0x00, 0x04, 0x01, 0x2E, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x28, 0x00, 0x6B, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x6E, 0x00, 0x6F, 0x00, @@ -476,7 +476,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0x0F, 0x42, 0x40, 0xF6, 0x64, 0xF4, 0x39, 0x01, 0x7D, 0xE4, 0x42, 0xCC, 0x23, 0x32, 0x35, 0xC0, 0x39, 0x03, 0xE8, 0xF6, 0x64, 0xF4, 0x39, 0x01, 0x7D, 0xE4, 0x42, 0xCC, 0x23, 0x32, 0x35, 0xC0, 0x64, 0xF4, 0x39, 0x01, 0x7D, 0xE4, 0x42, 0xCC, 0x23, 0x32, 0x00, 0x00 - ]; + ];*/ //FloatMathDemoPABWX.spin /*const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0xE7, 0x10, 0x00, 0x98, 0x19, 0x8C, 0x50, 0x4C, 0x00, 0x94, 0x50, @@ -891,7 +891,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0x09, 0xE2, 0xEA, 0x33, 0x32, 0x00, 0x00, 0x00 ];*/ //LargeSpinCodeFlip.spin - /*const bin = [ + const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0x86, 0x10, 0x00, 0xC0, 0x7E, 0xA8, 0x7F, 0xD0, 0x79, 0xB0, 0x7F, 0x70, 0x7A, 0x03, 0x01, 0xC0, 0x79, 0x04, 0x00, 0x15, 0x7A, 0x04, 0x00, 0x70, 0x7A, 0x04, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, @@ -2920,7 +2920,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0x38, 0xDF, 0xE8, 0xEC, 0x38, 0x27, 0x6C, 0x38, 0x38, 0xFA, 0xF4, 0xEC, 0x6D, 0x6C, 0x34, 0xFA, 0x6C, 0x68, 0xF9, 0xF0, 0x0A, 0x06, 0x60, 0x68, 0xF4, 0x6C, 0xEC, 0x61, 0x04, 0x53, 0x68, 0x38, 0x0A, 0xFC, 0x64, 0x80, 0x38, 0x2D, 0xFC, 0xF0, 0x0A, 0x03, 0x60, 0xE6, 0x61, 0x32, 0x00, 0x00 - ];*/ + ]; //Set and/or adjust postResetDelay based on platform if (!postResetDelay) { @@ -3210,9 +3210,12 @@ function talkToProp(sock, cid, binImage, toEEPROM) { }); } + //Set up continuous progress indicator during this phase + progress = setInterval(function() {log(notice(nsDownloading), mUser, sock)}, 1000); + sendInstructionPacket() - .then(function() {return resolve();}) - .catch(function(e) {return reject(e)}); + .then(function() {clearInterval(progress); return resolve();}) + .catch(function(e) {clearInterval(progress); return reject(e);}); }); } From 96a2b5577803da37df25868003252e1ee150104f Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Thu, 8 Feb 2018 15:02:24 -0800 Subject: [PATCH 28/44] Enhanced resetPropComm() to clear old timer if it exists, in preparation for multi-try graceful recovery download attempts. --- serial.js | 1 + 1 file changed, 1 insertion(+) diff --git a/serial.js b/serial.js index 145dcc3..0627745 100644 --- a/serial.js +++ b/serial.js @@ -2988,6 +2988,7 @@ function resetPropComm(timeout) { /*Reset propComm object to default values timeout = [optional] period (in ms) for initial timeout. If provided, sets stage to sgHandshake, creates deferred promise, and creates timeout timer. */ + if (propComm.timeout) {clearTimeout(propComm.timer)} //Clear old timer, if any Object.assign(propComm, propCommStart); //Reset propComm object if (timeout) { //If timeout provided propComm.stage = sgHandshake; //Ready for handshake From df7694b54ead66ad1ebe2f23a212211c1cb0f734 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Thu, 8 Feb 2018 15:45:33 -0800 Subject: [PATCH 29/44] Moved reset generation into sendLoader() to move towards multi-try graceful recovery. --- serial.js | 54 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/serial.js b/serial.js index 0627745..1de3278 100644 --- a/serial.js +++ b/serial.js @@ -3092,27 +3092,38 @@ function talkToProp(sock, cid, binImage, toEEPROM) { */ //!!! End Experimental code - function sendLoader(waittime) { - /* Return a promise that waits for waittime milliseconds, then sends communication package (Timing Pulses, Host Handshake, and Micro Boot Loader), - then waits for the responding Propeller Handshake, Version, and successful Micro Boot Loader delivery notice. + function sendLoader() { + /* Return a promise that generates the reset signal, waits the post-reset delay time, then sends the communication package (Timing Pulses, + Host Handshake, and Micro Boot Loader), then waits for the responding Propeller Handshake, Version, and successful Micro Boot Loader delivery notice. Rejects if any error occurs. Micro Boot Loader must respond with Packet ID (plus Transmission ID) for success (resolve). - Error is "Propeller not found" unless handshake received (and proper) and version received; error is more specific thereafter. //!!! + Error is "Propeller not found" (generated by hearFromProp) unless handshake received (and proper) and version received; error is more specific thereafter. */ return new Promise(function(resolve, reject) { - log("Waiting " + Math.trunc(waittime) + " ms", mDeep); - setTimeout(function() { - //Prep for expected packetID:transmissionId response (Micro-Boot-Loader's "Ready" signal) - propComm.mblEPacketId[0] = packetId; - propComm.mblETransId[0] = transmissionId; - //Send Micro Boot Loader package - log("Transmitting Micro Boot Loader package", mDeep); - send(cid, txData); - //Wait for response - propComm.response - .then(function() {log(notice(000, ["Found Propeller"]), mUser+mDbug, sock);}) - .then(function() {return resolve()}) - .catch(function(e) {return reject(e)}); - }, waittime); + + function sendMBL() { + setTimeout(function() { + //Prep for expected packetID:transmissionId response (Micro-Boot-Loader's "Ready" signal) + propComm.mblEPacketId[0] = packetId; + propComm.mblETransId[0] = transmissionId; + //Send Micro Boot Loader package + log("Transmitting Micro Boot Loader package", mDeep); + send(cid, txData); + //Wait for response + propComm.response + .then(function() {log(notice(000, ["Found Propeller"]), mUser+mDbug, sock);}) + .then(function() {return resolve()}) + .catch(function(e) {return reject(e)}); + }, postResetDelay); + }; + + Promise.resolve() + .then(function() { resetPropComm(mblDeliveryTime);} ) //Reset propComm object + .then(function() { log("Generating reset signal", mDeep);} ) + .then(function() {return setControl(cid, {dtr: false});} ) //Start Propeller Reset Signal + .then(function() {return flush(cid);} ) //Flush transmit/receive buffers (during Propeller reset) + .then(function() {return setControl(cid, {dtr: true});} ) //End Propeller Reset + .then(function() {log("Waiting " + Math.trunc(postResetDelay) + " ms", mDeep);}) + .then(function() {sendMBL();} ); //Send whole comm package, including Micro Boot Loader; verify receipt }); } @@ -3247,12 +3258,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { var userDeliveryTime = ((10*maxDataSize)/finalBaudrate)*1000+1+500; Promise.resolve() - .then(function() { resetPropComm(mblDeliveryTime);} ) //Reset propComm object - .then(function() { log("Generating reset signal", mDeep);} ) - .then(function() {return setControl(cid, {dtr: false});} ) //Start Propeller Reset Signal - .then(function() {return flush(cid);} ) //Flush transmit/receive buffers (during Propeller reset) - .then(function() {return setControl(cid, {dtr: true});} ) //End Propeller Reset - .then(function() {return sendLoader(postResetDelay);} ) //After Post-Reset-Delay, send package (Calibration Pulses+Handshake through Micro Boot Loader application+RAM Checksum Polls) and verify acceptance + .then(function() {return sendLoader();} ) //Reset propeller, wait for Post-Reset-Delay, send package (Calibration Pulses+Handshake through Micro Boot Loader application+RAM Checksum Polls) and verify acceptance .then(function() {return changeBaudrate(cid, finalBaudrate);} ) //Bump up to faster finalBaudrate .then(function() {log("Delivering user application packets", mDbug); return sendUserApp();} ) //Send user application .then(function() {return finalizeDelivery();} ) //Finalize delivery and launch user application From 7852bcf24ce2cd4e9a943f8e623780ba1f838d65 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Thu, 8 Feb 2018 23:26:57 -0800 Subject: [PATCH 30/44] Wrapped sendMBL() in a promise. Returned sendMBL() and added resolv and reject promise chain items. It repeats properly, but somehow breaks the chain. --- serial.js | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/serial.js b/serial.js index 1de3278..55c05fe 100644 --- a/serial.js +++ b/serial.js @@ -3101,19 +3101,21 @@ function talkToProp(sock, cid, binImage, toEEPROM) { return new Promise(function(resolve, reject) { function sendMBL() { - setTimeout(function() { - //Prep for expected packetID:transmissionId response (Micro-Boot-Loader's "Ready" signal) - propComm.mblEPacketId[0] = packetId; - propComm.mblETransId[0] = transmissionId; - //Send Micro Boot Loader package - log("Transmitting Micro Boot Loader package", mDeep); - send(cid, txData); - //Wait for response - propComm.response - .then(function() {log(notice(000, ["Found Propeller"]), mUser+mDbug, sock);}) - .then(function() {return resolve()}) - .catch(function(e) {return reject(e)}); - }, postResetDelay); + return new Promise(function(resolve, reject) { + setTimeout(function() { + //Prep for expected packetID:transmissionId response (Micro-Boot-Loader's "Ready" signal) + propComm.mblEPacketId[0] = packetId; + propComm.mblETransId[0] = transmissionId; + //Send Micro Boot Loader package + log("Transmitting Micro Boot Loader package", mDeep); + send(cid, txData); + //Wait for response + propComm.response + .then(function() {log(notice(000, ["Found Propeller"]), mUser+mDbug, sock);}) + .then(function() {return resolve()}) + .catch(function(e) {return reject(e)}); + }, postResetDelay); + }); }; Promise.resolve() @@ -3123,7 +3125,10 @@ function talkToProp(sock, cid, binImage, toEEPROM) { .then(function() {return flush(cid);} ) //Flush transmit/receive buffers (during Propeller reset) .then(function() {return setControl(cid, {dtr: true});} ) //End Propeller Reset .then(function() {log("Waiting " + Math.trunc(postResetDelay) + " ms", mDeep);}) - .then(function() {sendMBL();} ); //Send whole comm package, including Micro Boot Loader; verify receipt + .then(function() {return sendMBL();} ) //Send whole comm package, including Micro Boot Loader; verify receipt + .then(function() {return resolve();} ) + .catch(function() {if (--attempts) {log("RETRYING: PROPELLER NOT FOUND", mDeep); return sendLoader()}} ) + .catch(function(e) {return reject(e);}) }); } @@ -3257,6 +3262,9 @@ function talkToProp(sock, cid, binImage, toEEPROM) { //=((10 [bits per byte] * [max packet size]) / final baud rate) * 1,000 [to scale ms to integer] + 1 [to always round up] + 750 [Rx hardware to OS slack time] var userDeliveryTime = ((10*maxDataSize)/finalBaudrate)*1000+1+500; + //Set for limited retry attemps + var attempts = 3; + Promise.resolve() .then(function() {return sendLoader();} ) //Reset propeller, wait for Post-Reset-Delay, send package (Calibration Pulses+Handshake through Micro Boot Loader application+RAM Checksum Polls) and verify acceptance .then(function() {return changeBaudrate(cid, finalBaudrate);} ) //Bump up to faster finalBaudrate From 0996b8be3968d27da3960d49d356c3739e5638d3 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 12 Feb 2018 14:39:04 -0800 Subject: [PATCH 31/44] Fixed sendLoader()'s malformed promise chain so that up to 2 retries happen when Propeller Not Found, but other errors are fatal immediately, and normal success behavior continues properly. --- messages.js | 9 +++++++-- serial.js | 26 ++++++++++++++++---------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/messages.js b/messages.js index 15c5dc7..d382441 100644 --- a/messages.js +++ b/messages.js @@ -87,8 +87,8 @@ function notice(noticeId = 0, values = []) { /* Notice (message) retriever. Returns textual message indicated by the noticeId, inserts the optional values into it, and prepends with the noticeId value in the form ###-. noticeId is the identifier of the notice; ex: nsDownloading. - values is an optional array of values to stuff into notice.*/ - //Retrieve notice; if undefined, + values is an optional array of values to stuff into notice, or if noticeId = 0, is a custom message.*/ + //Retrieve notice; if defined nMsg = notices[noticeId]; //Fill in variables if needed; if notice undefined, use first values element as notice. values.forEach(function(x){nMsg = (nMsg) ? nMsg.replace(/%s/, x) : x;}); @@ -97,3 +97,8 @@ function notice(noticeId = 0, values = []) { nMsg = noticeId.substr(noticeId.length-3) + '-' + nMsg; return nMsg; } + +function noticeCode(msg) { + /*Extracts and returns notice code from msg formatted in the form ###-. Returns "000" if none.*/ + return Number((results = msg.match(/[0-9]+/)) ? results[0] : "000"); +} diff --git a/serial.js b/serial.js index 55c05fe..bc61ff1 100644 --- a/serial.js +++ b/serial.js @@ -3119,16 +3119,22 @@ function talkToProp(sock, cid, binImage, toEEPROM) { }; Promise.resolve() - .then(function() { resetPropComm(mblDeliveryTime);} ) //Reset propComm object - .then(function() { log("Generating reset signal", mDeep);} ) - .then(function() {return setControl(cid, {dtr: false});} ) //Start Propeller Reset Signal - .then(function() {return flush(cid);} ) //Flush transmit/receive buffers (during Propeller reset) - .then(function() {return setControl(cid, {dtr: true});} ) //End Propeller Reset - .then(function() {log("Waiting " + Math.trunc(postResetDelay) + " ms", mDeep);}) - .then(function() {return sendMBL();} ) //Send whole comm package, including Micro Boot Loader; verify receipt - .then(function() {return resolve();} ) - .catch(function() {if (--attempts) {log("RETRYING: PROPELLER NOT FOUND", mDeep); return sendLoader()}} ) - .catch(function(e) {return reject(e);}) + .then(function() { resetPropComm(mblDeliveryTime);} ) //Reset propComm object + .then(function() { log("Generating reset signal", mDeep);} ) + .then(function() {return setControl(cid, {dtr: false});} ) //Start Propeller Reset Signal + .then(function() {return flush(cid);} ) //Flush transmit/receive buffers (during Propeller reset) + .then(function() {return setControl(cid, {dtr: true});} ) //End Propeller Reset + .then(function() {log("Waiting " + Math.trunc(postResetDelay) + " ms", mDeep);} ) + .then(function() {return sendMBL();} ) //Wait post-reset-delay and send whole comm package, including Micro Boot Loader; verify receipt + .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); + 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 + } ) + .then(function() {return resolve();} ) //Propeller found? Resolve + .catch(function(e) {return reject(e);} ) //Error! Reject with message }); } From 831c80332ee998d6154797332d0b264a57b04351 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 12 Feb 2018 14:55:42 -0800 Subject: [PATCH 32/44] Added helpful comments and cleaned up promise structures. --- serial.js | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/serial.js b/serial.js index bc61ff1..1098f67 100644 --- a/serial.js +++ b/serial.js @@ -3119,22 +3119,22 @@ function talkToProp(sock, cid, binImage, toEEPROM) { }; Promise.resolve() - .then(function() { resetPropComm(mblDeliveryTime);} ) //Reset propComm object - .then(function() { log("Generating reset signal", mDeep);} ) - .then(function() {return setControl(cid, {dtr: false});} ) //Start Propeller Reset Signal - .then(function() {return flush(cid);} ) //Flush transmit/receive buffers (during Propeller reset) - .then(function() {return setControl(cid, {dtr: true});} ) //End Propeller Reset - .then(function() {log("Waiting " + Math.trunc(postResetDelay) + " ms", mDeep);} ) - .then(function() {return sendMBL();} ) //Wait post-reset-delay and send whole comm package, including Micro Boot Loader; verify receipt - .catch(function(e) { //Error! - if (noticeCode(e.message) === nePropellerNotFound && --attempts) { // Retry (if "Propeller not found" and more attempts available) + .then(function() { resetPropComm(mblDeliveryTime);}) //Reset propComm object + .then(function() { log("Generating reset signal", mDeep);}) + .then(function() {return setControl(cid, {dtr: false});}) //Start Propeller Reset Signal + .then(function() {return flush(cid);}) //Flush transmit/receive buffers (during Propeller reset) + .then(function() {return setControl(cid, {dtr: true});}) //End Propeller Reset + .then(function() {log("Waiting " + Math.trunc(postResetDelay) + " ms", mDeep);}) + .then(function() {return sendMBL();}) //Wait post-reset-delay and send whole comm package, including Micro Boot Loader; verify receipt + .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); - return sendLoader(); // note: sendLoader does not return execution below (promises continue at next .then/.catch) + 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 - } ) - .then(function() {return resolve();} ) //Propeller found? Resolve - .catch(function(e) {return reject(e);} ) //Error! Reject with message + return reject(e); // Or if other error (or out of retry attempts), reject with message + }) + .then(function() {return resolve();}) //Propeller found? Resolve + .catch(function(e) {return reject(e);}) //Error! Reject with message }); } @@ -3183,7 +3183,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { sendUA() //Send user application packet .then(function() {return propComm.response;}) //Wait for response - .then(function() {if (packetId > 0) {return sendUserApp()}}) //More packets? repeat + .then(function() {if (packetId > 0) {return sendUserApp()}}) //More packets? repeat (note: sendUserApp does not return execution here (promises continue at next .then/.catch)) .then(function() {return resolve()}) //else, resolve .catch(function(e) {return reject(e)}); //Error? return error message }); @@ -3272,12 +3272,15 @@ function talkToProp(sock, cid, binImage, toEEPROM) { var attempts = 3; Promise.resolve() - .then(function() {return sendLoader();} ) //Reset propeller, wait for Post-Reset-Delay, send package (Calibration Pulses+Handshake through Micro Boot Loader application+RAM Checksum Polls) and verify acceptance - .then(function() {return changeBaudrate(cid, finalBaudrate);} ) //Bump up to faster finalBaudrate - .then(function() {log("Delivering user application packets", mDbug); return sendUserApp();} ) //Send user application - .then(function() {return finalizeDelivery();} ) //Finalize delivery and launch user application - .then(function() {return resolve();} ) //Success! - .catch(function(e) {clearTimeout(propComm.timer); reject(e);} ); //Catch errors, pass them on + .then(function() {return sendLoader();}) //Reset propeller, wait for Post-Reset-Delay, send package (Calibration Pulses+Handshake through Micro Boot Loader application+RAM Checksum Polls) and verify acceptance + .then(function() {return changeBaudrate(cid, finalBaudrate);}) //Bump up to faster finalBaudrate + .then(function() { //Send user application + log("Delivering user application packets", mDbug); + return sendUserApp(); + }) + .then(function() {return finalizeDelivery();}) //Finalize delivery and launch user application + .then(function() {return resolve();}) //Success! + .catch(function(e) {clearTimeout(propComm.timer); reject(e);}); //Catch errors, pass them on }); } From e2f5c5df097af495ea7dbddf5cbafb52e3a295dd Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 12 Feb 2018 15:40:55 -0800 Subject: [PATCH 33/44] Removed legacy propComm status values, stage values, and valid/invalid at end of hearFromProp(). --- serial.js | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/serial.js b/serial.js index 1098f67..a314b89 100644 --- a/serial.js +++ b/serial.js @@ -30,11 +30,6 @@ const defaultClockSpeed = 80000000; const defaultClockMode = 0x6F; const maxDataSize = 1392; //Max data packet size (for packets sent to running Micro Boot Loader) -// propComm status values -const stValidating = -1; -const stInvalid = 0; -const stValid = 1; - // propComm stage values const sgError = -2; const sgIdle = -1; @@ -42,8 +37,6 @@ const sgHandshake = 0; const sgVersion = 1; const sgRAMChecksum = 2; const sgMBLResponse = 3; -//!!! const sgEEProgram = 3; -//!!! const sgEEChecksum = 4; // Propeller Communication (propComm) status; categorizes Propeller responses let propComm = {}; //Holds current status @@ -62,8 +55,6 @@ const propCommStart = { //propCommStart is used to mblETransId : new Int32Array(mblExpdAB, 4, 1), //Micro Boot Loader expected transmission id (32-bit signed int format) timer : null, //Holds current timeout timer timeoutError : "" //Error to issue at end of next timeout -//!!! eeProg : stValidating, -//!!! eeCheck : stValidating }; //Loader type; used for generateLoaderPacket() @@ -3373,16 +3364,6 @@ function hearFromProp(info) { propComm.rxCount = 0; } - - -//!!! SendUserApp - //Check Micro Boot Loader response -//!!! if (propComm.mblResponse !== stValid || (propComm.mblPacketId[0]^packetId) + (propComm.mblTransId[0]^transmissionId) !== 0) { -//!!! reject(Error(notice(neCommunicationFailed))); return -//!!! } - - - // Receive Micro Boot Loader's response. The first is its "Ready" signal; the rest are packet responses. if (propComm.stage === sgMBLResponse) { while (sIdx < stream.length && propComm.rxCount < propComm.mblRespBuf.byteLength) { @@ -3402,9 +3383,6 @@ function hearFromProp(info) { clearTimeout(propComm.timer); propComm.response.reject(Error(notice(neLoaderFailed))); } - //Valid if end of stream, otherwise something's wrong (invalid response) -//!!! - propComm.mblResponse = stream.length === sIdx ? stValid : stInvalid; } } } From 8310c14fc26d28d67547e8a78a1a89e8f22660d4 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 12 Feb 2018 15:51:48 -0800 Subject: [PATCH 34/44] Removed unused debug code and enhanced propComm.timer to clear itself and reset propComm stage to Idle. --- serial.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/serial.js b/serial.js index a314b89..8af5928 100644 --- a/serial.js +++ b/serial.js @@ -2997,8 +2997,10 @@ function setPropCommTimer(timeout, timeoutError) { propComm.timeoutError = timeoutError; timeout = Math.trunc(timeout); propComm.timer = setTimeout(function() { - log("Timed out in " + timeout + " ms", mDbug); //!!! - propComm.response.reject(Error(propComm.timeoutError)); +// log("Timed out in " + timeout + " ms", mDbug); + clearTimeout(propComm.timer); //Clear timer + propComm.stage = sgIdle; //Reset propComm stage to Idle (ignore incoming data) + propComm.response.reject(Error(propComm.timeoutError)); //Reject with error propComm.timer = null; }, timeout); } @@ -3307,7 +3309,6 @@ function hearFromProp(info) { //Handshake matches so far... if (propComm.rxCount === rxHandshake.length) { //Entire handshake matches! Prep for next stage -//!!! log("passed handshake", mDeep); //!!! propComm.rxCount = 0; propComm.stage = sgVersion; break; @@ -3332,7 +3333,6 @@ function hearFromProp(info) { //Received all 4 bytes if (propComm.version === 1) { //Version matches expected value! Prep for next stage -//!!! log("passed version", mDeep); //!!! //Found Propeller; update timeout for next possible error (if no RAM Checksum or Micro Boot Loader response received) propComm.timeoutError = notice(neCommunicationLost); propComm.rxCount = 0; @@ -3353,7 +3353,6 @@ function hearFromProp(info) { //Received RAM Checksum response? if (stream[sIdx++] === 0xFE) { //RAM Checksum valid; Prep for next stage -//!!! log("passed RAM checksum", mDeep); //!!! propComm.stage = sgMBLResponse; } else { //RAM Checksum invalid; Note rejected; Ignore the rest @@ -3372,11 +3371,10 @@ function hearFromProp(info) { if (propComm.rxCount === propComm.mblRespBuf.byteLength) { clearTimeout(propComm.timer); propComm.stage = sgIdle; -//!!! log("Response PacketId: "+ propComm.mblRPacketId+ " TransId: "+ propComm.mblRTransId, mDeep); //!!! -//!!! log("Expected PacketId: "+ propComm.mblEPacketId+ " TransId: "+ propComm.mblETransId, mDeep); //!!! +// log("Response PacketId: "+ propComm.mblRPacketId+ " TransId: "+ propComm.mblRTransId, mDeep); +// log("Expected PacketId: "+ propComm.mblEPacketId+ " TransId: "+ propComm.mblETransId, mDeep); if ((propComm.mblRPacketId[0] === propComm.mblEPacketId[0]) && (propComm.mblRTransId[0] === propComm.mblETransId[0])) { //MBL Response is perfect; Note resolved -//!!! log("passed response", mDeep); //!!! propComm.response.resolve(); } else { //MBL Response invalid; Note rejected; Ignore the rest From c215a930c504d301c343a8d4aed4ffa31587ba01 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 12 Feb 2018 16:00:26 -0800 Subject: [PATCH 35/44] Added safety feature to remove lingering hearFromProp listener which may have been left over from previous uncaught promise error. --- serial.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/serial.js b/serial.js index 8af5928..3935810 100644 --- a/serial.js +++ b/serial.js @@ -2966,12 +2966,11 @@ function listen(engage) { /* Engage or disengage serial programming receive listener. engage = true to add listener; false to remove listener.*/ if (engage) { - //Add programming protocol serial receive handler resetPropComm(); - chrome.serial.onReceive.addListener(hearFromProp); + chrome.serial.onReceive.removeListener(hearFromProp); //Safety: Remove previous listener which may be left over from uncaught promise (rare) + chrome.serial.onReceive.addListener(hearFromProp); //Add programming protocol serial receive handler } else { - //Remove programming protocol serial receive handler - chrome.serial.onReceive.removeListener(hearFromProp); + chrome.serial.onReceive.removeListener(hearFromProp); //Remove programming protocol serial receive handler } } From 181e813995f5e767b1ccb401874cc6ef5a7694e2 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 12 Feb 2018 16:10:50 -0800 Subject: [PATCH 36/44] Removed experimental code, restored normal user application image processing, and resolved some warnings due to var declarations. --- serial.js | 100 ++++++++---------------------------------------------- 1 file changed, 15 insertions(+), 85 deletions(-) diff --git a/serial.js b/serial.js index 3935810..4a47411 100644 --- a/serial.js +++ b/serial.js @@ -882,7 +882,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0x09, 0xE2, 0xEA, 0x33, 0x32, 0x00, 0x00, 0x00 ];*/ //LargeSpinCodeFlip.spin - const bin = [ + /*const bin = [ 0x00, 0xB4, 0xC4, 0x04, 0x6F, 0x86, 0x10, 0x00, 0xC0, 0x7E, 0xA8, 0x7F, 0xD0, 0x79, 0xB0, 0x7F, 0x70, 0x7A, 0x03, 0x01, 0xC0, 0x79, 0x04, 0x00, 0x15, 0x7A, 0x04, 0x00, 0x70, 0x7A, 0x04, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, @@ -2911,7 +2911,7 @@ function loadPropeller(sock, portPath, action, payload, debug) { 0x38, 0xDF, 0xE8, 0xEC, 0x38, 0x27, 0x6C, 0x38, 0x38, 0xFA, 0xF4, 0xEC, 0x6D, 0x6C, 0x34, 0xFA, 0x6C, 0x68, 0xF9, 0xF0, 0x0A, 0x06, 0x60, 0x68, 0xF4, 0x6C, 0xEC, 0x61, 0x04, 0x53, 0x68, 0x38, 0x0A, 0xFC, 0x64, 0x80, 0x38, 0x2D, 0xFC, 0xF0, 0x0A, 0x03, 0x60, 0xE6, 0x61, 0x32, 0x00, 0x00 - ]; + ]; */ //Set and/or adjust postResetDelay based on platform if (!postResetDelay) { @@ -2919,20 +2919,21 @@ function loadPropeller(sock, portPath, action, payload, debug) { postResetDelay = platform === pfWin ? 60 : 100; } -//!!! Temporarily disabled normal operation -// if (payload) { -// //Extract Propeller Application from payload -// var binImage = parseFile(payload); -// if (binImage.message !== undefined) {log("Error: " + binImage.message); return;} -// } else { - var binImage = buffer2ArrayBuffer(bin); -// } + let binImage; + + if (payload) { + //Extract Propeller Application from payload + binImage = parseFile(payload); + if (binImage.message !== undefined) {log("Error: " + binImage.message); return;} + } else { + binImage = buffer2ArrayBuffer(bin); + } // Look for an existing port - var port = findPort(portPath); - var cid = port ? port.connId : null; - var connect; - var originalBaudrate; + let port = findPort(portPath); + let cid = port ? port.connId : null; + let connect; + let originalBaudrate; if (cid) { // Connection exists, prep to reuse it originalBaudrate = port.baud; @@ -3013,77 +3014,6 @@ function talkToProp(sock, cid, binImage, toEEPROM) { return new Promise(function(resolve, reject) { -//!!! Experimental code -/* - //This code creates a deferred promise (resolved or rejected outside of its constructor) and demonstrates that the promise - //can be passed to other functions (delayedResult) and even resolved/rejected within them. - - function delayedResult(mess, delay, succeedFail, otherPromise) { - console.log("Creating delayed promise for: " + mess); - return new Promise(function(resolve, reject) { - setTimeout(function() { - console.log(mess); - if (otherPromise) {otherPromise.resolve();} - if (succeedFail) {resolve()} else {reject(Error("Failed"))} - }, delay); - }) - } - - //Create new promise that will be resolved by another function at a later time (a deferred promise) - let p1 = deferredPromise(); - - //Define promise chain of this deferred promise - p1 - .then(function() {console.log("p1 resolved")}) - .catch(function() {console.log("p1 rejected")}); - - //Create another normal-pattern promise chain, that, as a matter of demonstration, passes in the deferred promise in a specific step - Promise.resolve() - .then(function() {return delayedResult("First", 1000, true);}) - .then(function() {return delayedResult("Second", 1500, true, p1);}) - .then(function() {return delayedResult("Third", 2000, false);}) - .then(function() {return delayedResult("Forth", 2500, true);}) - .catch(function(e) {console.log(e.message);}); - - return -*/ -/* - var p3 = function() {return msgout("test");}; - var p2 = function() {return msgout("is a", p3);}; - var p1 = function() {return msgout("This", p2);}; - - function msgout(mess, nextp) { - return new Promise(function(resolve, reject) { - if (mess !== "") { - console.log(mess); - if (nextp) { - resolve(nextp()); - } else { - resolve(); - } - } else { - reject(Error("")); -// reject(); - } - }) - } - - Promise.resolve() - .then(p1) - .catch(function(e) {console.log(e.message);}); - return -*/ -/* - Promise.resolve() - .then(p1) - .then(p2) - .then(p3) -// .catch(function() {}); - .catch(function(e) {console.log(e.message);}); - return; -*/ -//!!! End Experimental code - function sendLoader() { /* Return a promise that generates the reset signal, waits the post-reset delay time, then sends the communication package (Timing Pulses, Host Handshake, and Micro Boot Loader), then waits for the responding Propeller Handshake, Version, and successful Micro Boot Loader delivery notice. From f586c29962a1fbc4eb556ac6b030d578dd762c78 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 12 Feb 2018 16:19:34 -0800 Subject: [PATCH 37/44] Added 1/2 second Rx hardware-to-OS slack time in mblDeliveryTime timeout in order to wait long enough for slow reception of expected response. --- serial.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/serial.js b/serial.js index 4a47411..f9a1bee 100644 --- a/serial.js +++ b/serial.js @@ -3183,11 +3183,11 @@ function talkToProp(sock, cid, 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] */ - var mblDeliveryTime = 300+((10*(txData.byteLength+20+8))/initialBaudrate)*1000+1; + = 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+500; - //=((10 [bits per byte] * [max packet size]) / final baud rate) * 1,000 [to scale ms to integer] + 1 [to always round up] + 750 [Rx hardware to OS slack time] + //=((10 [bits per byte] * [max packet size]) / final baud rate) * 1,000 [to scale ms to integer] + 1 [to always round up] + 500 [Rx hardware to OS slack time] var userDeliveryTime = ((10*maxDataSize)/finalBaudrate)*1000+1+500; //Set for limited retry attemps From 82fb5b240777da0ef5627469d1bd527931128036 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 12 Feb 2018 16:47:43 -0800 Subject: [PATCH 38/44] Removed unused sgError. --- serial.js | 1 - 1 file changed, 1 deletion(-) diff --git a/serial.js b/serial.js index f9a1bee..3b2433d 100644 --- a/serial.js +++ b/serial.js @@ -31,7 +31,6 @@ const defaultClockMode = 0x6F; const maxDataSize = 1392; //Max data packet size (for packets sent to running Micro Boot Loader) // propComm stage values -const sgError = -2; const sgIdle = -1; const sgHandshake = 0; const sgVersion = 1; From 0ff3a434137ee6d1b594283eef26fa847b485e85 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Mon, 12 Feb 2018 19:38:33 -0800 Subject: [PATCH 39/44] Bumped mblDeliveryTime's Rx hardware-to-OS slack time down to 250 ms. --- serial.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serial.js b/serial.js index 3b2433d..68bf23c 100644 --- a/serial.js +++ b/serial.js @@ -3184,7 +3184,7 @@ function talkToProp(sock, cid, binImage, toEEPROM) { /* 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+500; + var mblDeliveryTime = 300+((10*(txData.byteLength+20+8))/initialBaudrate)*1000+1+250; //=((10 [bits per byte] * [max packet size]) / final baud rate) * 1,000 [to scale ms to integer] + 1 [to always round up] + 500 [Rx hardware to OS slack time] var userDeliveryTime = ((10*maxDataSize)/finalBaudrate)*1000+1+500; From 138e7d4cc24e124e307adca0de531a730a421a99 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Fri, 16 Feb 2018 13:46:14 -0800 Subject: [PATCH 40/44] Bumped to v0.7.7. Revised rxHandshake validation routine to gracefully handle un-related preceeding data ahead of the actual handshake data. Also removed timedPromise code (which never worked). --- manifest.json | 2 +- serial.js | 57 ++++++++++++++++++++++++++++----------------------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/manifest.json b/manifest.json index 70f6ada..cc2ca4f 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.7.6", + "version": "0.7.7", "manifest_version": 2, "minimum_chrome_version": "45", diff --git a/serial.js b/serial.js index 68bf23c..26ef5b0 100644 --- a/serial.js +++ b/serial.js @@ -3229,24 +3229,47 @@ function hearFromProp(info) { var stream = ab2num(info.data); var sIdx = 0; - // Validate rxHandshake + /* Validate rxHandshake + To find a received handshake, a few problems must be overcome: 1) data doesn't always arrive in it's entirety per any receive event; a few bytes may appear + at one event, then a few more on the following event, 2) data may "never" match; it may suddenly stop arriving during a partial match, or continuous data may + be absolutely unrelated, and 2) a serial port flush does not guarantee pristine data; the handshake may appear buried at the end of non-related serial data + streamed in from the previous Propeller App execution, received just after the flush event and just before the reset signal reaches the Propeller. To combat + all this, surprisingly simple techniques are employed. 1) Receive and match handshake as a state machine, 2) use an independent timeout (in this case the + propComm.timer event) to abort if necessary, and 3) pattern match using unique rxHandshake attributes. Item #3 is explained further next. + + (Item #3 Explanation) + The 2-bit per byte encoded rxHandshake begins with a unique 3-byte pattern (0xEE,0xCE,0xCE); that pattern does not appear anywhere else within it; however, + the first two bytes of that pattern do appear in multiple places. Using this knowledge, comparisons of a received stream against the rxHandshake, dumping + every unmatched byte (and realigning next received byte(s) to 3rd byte of rxHandshake), allows reception of a clean pattern, or an obscured pattern start, + or even a truncated matching pattern followed by a restarted full pattern, to be easily found and aligned to match. In addition, no received data need be + retained longer than each individual byte comparison. + + The match technique is as follows (start at first byte of rxHandshake): + A) compare two bytes (current byte in stream against current byte in rxHandshake, + B) if they match- index to next byte of each and repeat "A", + if they don't match- index stream (only if on 3rd byte of rxHandshake), reset to 3rd byte of rxHandshake, and repeat "A". + + Even though this technique sometimes skips a true comparison of the first two bytes of rxHandshake, all remaining 123 bytes are always matched perfectly. + Incredibly, in the case of receiving a partial match followed by a full handshake match, it gracefully recovers and re-aligns, even if the start of the full + happens to appear perfectly lined up with one of the seven deep places in rxHandshake that the first 2-byte pattern appears (0xEE,0xCE). Despite potentially + ignoring the first 2 bytes of rxHandshake, the chance of a false positive match is 1 in 2^984 (astronomically improbable). + */ if (propComm.stage === sgHandshake) { while (sIdx < stream.length && propComm.rxCount < rxHandshake.length) { //More data to match against rxHandshake... - if (stream[sIdx++] === rxHandshake[propComm.rxCount++]) { + if (stream[sIdx] === rxHandshake[propComm.rxCount]) { //Handshake matches so far... - if (propComm.rxCount === rxHandshake.length) { + sIdx++; + if (++propComm.rxCount === rxHandshake.length) { //Entire handshake matches! Prep for next stage propComm.rxCount = 0; propComm.stage = sgVersion; break; } } else { - //Handshake failure! Note rejected; Ignore the rest - clearTimeout(propComm.timer); - propComm.response.reject(Error(notice(nePropellerNotFound))); - propComm.stage = sgIdle; - break; + //Handshake mismatch; realign and retry + sIdx += (propComm.rxCount === 2); //Match failed; index to next received byte (only if already compared against 3rd rxHandshake byte) + propComm.rxCount = 2; //Prep to compare with 3rd rxHandshake byte (see "Item #3 Explanation," above) } } } @@ -3314,24 +3337,6 @@ function hearFromProp(info) { } } -//TODO Revisit timedPromise and make it work properly for optimized communication -/* -function timedPromise(promise, timeout){ -// Takes in a promise and returns it as a promise that rejects in timeout milliseconds if not resolved beforehand - var expired = function() { - return new Promise(function (resolve, reject) { - var id = setTimeout(function() { - log("Timed out!", mDbug); - clearTimeout(id); - reject(Error('Timed out in ' + timeout + ' ms.')); - }, timeout); - }) - }; - // Returns a promise race between passed-in promise and timeout promise - return Promise.race([promise(), expired()]) -} -*/ - function generateLoaderPacket(loaderType, packetId, clockSpeed, clockMode) { /*Generate a packet (in txData) containing the portion of the Micro Boot Loader (IP_Loader.spin) indicated by LoaderType. Initial call should use loaderType of ltCore and later calls use other loaderTypes; details described below. From 4b6ee2a8f27baab984650969743e6558f3d3ca1d Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Tue, 20 Feb 2018 13:57:24 -0800 Subject: [PATCH 41/44] Added upPause(), called during sendMBL(), to unpause the port as it sometimes is auto-paused by ChromeOS due to serial receive error. A paused port does not get any more onReceive events, thus the listener can't do it's job. --- serial.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/serial.js b/serial.js index 26ef5b0..2e80aed 100644 --- a/serial.js +++ b/serial.js @@ -205,6 +205,16 @@ function flush(cid) { }); } +function unPause(cid) { +/* Return a promise that unpauses the port + cid is the open port's connection identifier*/ + return new Promise(function(resolve) { + chrome.serial.setPaused(cid, false, function() { + resolve(); + }); + }); +} + //TODO Check send callback //TODO Promisify and return error object function send(cid, data) { @@ -3030,11 +3040,12 @@ function talkToProp(sock, cid, binImage, toEEPROM) { //Send Micro Boot Loader package log("Transmitting Micro Boot Loader package", mDeep); send(cid, txData); - //Wait for response - propComm.response - .then(function() {log(notice(000, ["Found Propeller"]), mUser+mDbug, sock);}) + //Get response + unPause(cid) //Unpause port; it may have been auto-paused by incoming data error + .then(function() {return propComm.response}) //Wait for response (may timeout with rejection) + .then(function() {log(notice(000, ["Found Propeller"]), mUser+mDbug, sock)}) //Succeeded! .then(function() {return resolve()}) - .catch(function(e) {return reject(e)}); + .catch(function(e) {return reject(e)}); //Failed! }, postResetDelay); }); }; From 2e2e835e00eea97ce51663b775a3229dcca4a96e Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Tue, 20 Feb 2018 14:11:29 -0800 Subject: [PATCH 42/44] Bumped version to 0.7.8. --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index cc2ca4f..1a73ad1 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.7.7", + "version": "0.7.8", "manifest_version": 2, "minimum_chrome_version": "45", From 7b7910d582fbe62064c75adda553ad3e0c54db71 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Tue, 20 Feb 2018 17:41:30 -0800 Subject: [PATCH 43/44] Removed extra lines. --- serial.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/serial.js b/serial.js index 2e80aed..597dea8 100644 --- a/serial.js +++ b/serial.js @@ -3099,10 +3099,8 @@ function talkToProp(sock, cid, binImage, toEEPROM) { txData = new ArrayBuffer(txPacketLength * 4); //Set packet length (in longs)} txView = new Uint8Array(txData); transmissionId = Math.floor(Math.random()*4294967296); //Create next random Transmission ID - propComm.mblEPacketId[0] = packetId-1; propComm.mblETransId[0] = transmissionId; - (new DataView(txData, 0, 4)).setUint32(0, packetId, true); //Store Packet ID (new DataView(txData, 4, 4)).setUint32(0, transmissionId, true); //Store random Transmission ID txView.set((new Uint8Array(binImage)).slice(pIdx * 4, pIdx * 4 + (txPacketLength - 2) * 4), 8); //Store section of binary image @@ -3144,7 +3142,6 @@ function talkToProp(sock, cid, binImage, toEEPROM) { transmissionId = Math.floor(Math.random()*4294967296); //Create next random Transmission ID (new DataView(txData, 4, 4)).setUint32(0, transmissionId, true); //Store random Transmission ID - if (next.value.type !== ltLaunchNow) { //Response expected from MBL? prepForMBLResponse(next.value.recvTime, notice(neCommunicationLost)); // Prepare to receive next MBL response packetId = next.value.nextId; // Ready next Packet ID From 0dc9408cc097e4015e9cff2380984b7d682c5f60 Mon Sep 17 00:00:00 2001 From: Jeff Martin Date: Tue, 20 Feb 2018 17:43:03 -0800 Subject: [PATCH 44/44] Bumped version to 0.8.0 --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 1a73ad1..eba8fd4 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.7.8", + "version": "0.8.0", "manifest_version": 2, "minimum_chrome_version": "45",