Browse Source

Better slip handling and sending, using events seems right....

craigsdennis 9 years ago
parent
commit
6c933f90e2
1 changed files with 90 additions and 35 deletions
  1. 90 35
      spike/flasher.js

+ 90 - 35
spike/flasher.js

@@ -30,13 +30,18 @@ const commands = {
     NO_COMMAND: 0xFF
 };
 
-// https://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol
+function commandToKey(command) {
+    // value to key
+    return Object.keys(commands).find((key) => commands[key] === command);
+}
 
+// FIXME: SlipUtils
+// https://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol
 const SLIP = {
-    frameEnd: "\xc0",
-    frameEscape: "\xdb",
-    transposedFrameEnd: "\xdc",
-    transposedFrameEscape: "\xdd"
+    frameEnd: 0xC0,
+    frameEscape: 0xDB,
+    transposedFrameEnd: 0xDC,
+    transposedFrameEscape: 0xDD
 }
 
 const SYNC_FRAME = new Buffer("\x07\x07\x12\x20" + "\x55".repeat(32));
@@ -80,53 +85,83 @@ class EspBoard {
                 debug("RTS off, DTR on", error, result);
             });
         }).then(() => {
-            return delay(50);
+            return delay(5);
         }).then(() => {
             this.port.set({dtr: false}, (error, result) => {
                 debug("DTR off", error, result);
+                this.port.resume();
             });
         });
     }
 }
 
 
-class EspComm extends EventEmitter {
+class EspComm {
     constructor(config) {
-        super();
+        this.emitter = new EventEmitter();
         if (config.debug) {
             debug = config.debug;
         }
-        this.port = this.initializePort(config);
+        this.port = new SerialPort(config.portName, {
+            baudRate: config.baudRate,
+            parity: 'none',
+            stopBits: 1,
+            xon: false,
+            xoff: false,
+            rtscts: false,
+            dsrdtr: false
+        }, false);
+        this.bindPort();
         var BoardFactory = config.BoardFactory ? config.BoardFactory : EspBoard;
         this.board = new BoardFactory(this.port);
         this.isOpen = false;
         this.config = config;
     }
     
-    initializePort(config) {
-        var port = new SerialPort(config.portName, {
-            baudRate: config.baudRate
-        }, false);
-        port.on('error', (error) => debug("PORT ERROR", error));
-        port.on('data', (buffer) => {
+    bindPort() {
+        this.port.on('error', (error) => debug("PORT ERROR", error));
+        this.port.on('data', (buffer) => {
             debug("Data received", buffer.length, buffer);
+            // FIXME:csd - SlipUtils.findSlipMessages
             let slipStart = buffer.indexOf(SLIP.frameEnd);
             while (slipStart >= 0) {
                 debug("Suspected SLIP response", slipStart);
                 let slipEnd = buffer.indexOf(SLIP.frameEnd, slipStart + 1);
                 if (slipEnd > slipStart) {
+                    debug("Suspicion confirmed");
                     let slipped = buffer.slice(slipStart, slipEnd);
-                    this.emit("responseReceived", slipped);
+                    this.emitter.emit("responseReceived", slipped);
                     slipStart = buffer.indexOf(SLIP.frameEnd, slipEnd + 1);
                 } else {
                     slipStart = -1;
                 }   
             }
         });
-        this.on("responseReceived", (slipped) => {
-            debug("SLIP found", slipped.length, slipped); 
+        this.emitter.on("responseReceived", (slipped) => {
+            // Will report a little longer due to escaping
+            // FIXME:csd - SlipUtils.decode
+            let response = new Buffer(slipped.length);
+            let responseLength = 0;
+            for (let index = 0; index < slipped.length; index++) {
+                let val = slipped[index];
+                if (val === SLIP.frameEscape) {
+                    // Move one past the escape char
+                    index++;
+                    if (slipped[index] === SLIP.transposedFrameEnd) {
+                        val = SLIP.frameEnd;    
+                    } else if (slipped[index] === SLIP.transposedFrameEscape) {
+                        val = SLIP.frameEscape;
+                    }
+                }
+                response[responseLength++] = val;
+            }
+            var header = bufferpack.unpack(formats.bootloader_packet_header, response.slice(0, 8));
+            // TODO:csd Verify checksum and direction
+            let commandName = commandToKey(header.command);
+            let body = response.slice(8, header.length + 8);
+            debug("Emitting", commandName, body);
+            this.emitter.emit(commandName, body);    
         });
-        return port;
     }
 
     open() {
@@ -163,14 +198,24 @@ class EspComm extends EventEmitter {
         debug("Syncing");
         // FIXME:csd - How to send break?
         // https://github.com/igrr/esptool-ck/blob/master/serialport/serialport.c#L234
-        return this.sendCommand(commands.SYNC_FRAME, SYNC_FRAME);
+        return this.sendCommand(commands.SYNC_FRAME, SYNC_FRAME).then((response) => {
+            debug("Sync response completed!", response);
+        });
     }
     
     connect() {
+        return new Promise((resolve, reject) => {
+            this._connectAttempt()
+                .then(() => resolve());
+               
+        });
+    }
+    
+    _connectAttempt() {
+        // Python does a 5x loop here
         return this.board.resetIntoBootLoader()
             .then(() => {
-                return delay(100)
-            }).then(() => {
+                // And a 5x loop here
                 return new Promise((resolve, reject) => {
                     this.port.flush((error) => {
                         if (error) {
@@ -180,30 +225,31 @@ class EspComm extends EventEmitter {
                         resolve();
                     });
                 });
-            }).then(() => {
-                this.sync();
-            });
+            }).then(() => this.sync());
     }
     
     /**
+     * FIXME:csd SlipUtils.encode
      * Writes a SLIP packet to the port
      */
     write(packet) {
         // Probably larger than this due to escaping
-        var slipped = new Buffer(packet.length + 2);
-        slipped.write(SLIP.frameEnd);
+        let slipped = new Buffer(packet.length + 2 + 100);
+        let slippedIndex = 0;
+        slipped[slippedIndex++] = SLIP.frameEnd;
         for (var i = 0; i < packet.length; i++) {
             if (packet[i] === SLIP.frameEnd) {
-                slipped.write(SLIP.frameEscape);
-                slipped.write(SLIP.transposedFrameEnd);
+                slipped[slippedIndex++] = SLIP.frameEscape;
+                slipped[slippedIndex++] = SLIP.transposedFrameEnd;
             } else if (packet[i] === SLIP.frameEscape) {
-                slipped.write(SLIP.frameEscape);
-                slipped.write(SLIP.transposedFrameEscape);
+                slipped[slippedIndex++] = SLIP.frameEscape;
+                slipped[slippedIndex++] = SLIP.transposedFrameEscape;
             } else {
-                slipped.write(packet[i]);
+                slipped[slippedIndex++] = packet[i];
             }
         }
-        slipped.write(SLIP.frameEnd);
+        slipped[slippedIndex++] = SLIP.frameEnd;
+        slipped = slipped.slice(0, slippedIndex);
         this.port.write(slipped, (err, result) => {
             debug("Wrote", slipped.length, slipped, result);
         });
@@ -222,15 +268,24 @@ class EspComm extends EventEmitter {
                     checksum = this.calculateChecksum(data);
                 }
                 var sendHeader = bufferpack.pack(formats.bootloader_packet_header, [0x00, command, length, checksum]);
-                this.write(sendHeader + data);
+                this.write(Buffer.concat([sendHeader, data], sendHeader.length + data.length));
             }
             
             delay(5).then(() => {
                 this.port.drain((err, res) => {
                     debug("Draining", err, res);
-                    resolve();  
                 });
             });
+            let commandName = commandToKey(command);
+            if (this.emitter.listeners(commandName).length === 0) {
+                debug("Listening once", commandName);
+                this.emitter.once(commandName, (response) => {
+                    resolve(response);    
+                });    
+            } else {
+                debug("Someone is already awaiting", commandName);
+            }
+            
         });
     }
 }