浏览代码

Merge branch 'master' into flash-spike

craigsdennis 9 年之前
父节点
当前提交
394827a37d
共有 5 个文件被更改,包括 183 次插入50 次删除
  1. 0 4
      .idea/watcherTasks.xml
  2. 0 11
      back-end/available_serial_ports.js
  3. 98 0
      back-end/serial_scanner.js
  4. 24 35
      front-end/js/app.js
  5. 61 0
      front-end/js/port_select.js

+ 0 - 4
.idea/watcherTasks.xml

@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="ProjectTasksOptions" suppressed-tasks="Babel" />
-</project>

+ 0 - 11
back-end/available_serial_ports.js

@@ -1,11 +0,0 @@
-var serialport = require("serialport");
-
-module.exports = function getAvailablePorts(){
-    return new Promise(function(resolve, reject){
-        serialport.list(function (err, ports) {
-            if(err) reject(err);
-            else if(ports.length === 0) reject(new Error("No serial ports detected."));
-            else resolve(ports.map(p => { return p.comName }));
-        });
-  });
-};

+ 98 - 0
back-end/serial_scanner.js

@@ -0,0 +1,98 @@
+"use strict";
+
+const serialport = require("serialport");
+const EventEmitter = require("events");
+
+module.exports = class SerialScanner extends EventEmitter {
+    /**
+     * Scans for ports and emits a "ports" event with an array of
+     */
+    scan() {
+        serialport.list(
+            (err, ports) => {
+                this._listWithCallback(err,ports, () => {
+                    this.ports = ports.map(this._portMap);
+                    this.emit("ports", this.ports);
+                });
+            }
+        )
+    }
+
+    /**
+     * Checks for changes after initial scan.
+     * Emits deviceAdded for each device added and
+     * deviceRemoved for each device removed;
+     */
+    checkForChanges() {
+        serialport.list(
+            (err, ports) => {
+                this._listWithCallback(err, ports, () => {
+                    let newPorts = ports.map(this._portMap);
+                    this.checkDeviceRemoved(newPorts);
+                    this.checkDeviceAdded(newPorts);
+                    this.ports = newPorts;
+                });
+            }
+        )
+    }
+
+    /**
+     * Compares the previous scan's port list with the current port list.
+     * Emits deviceAdded for each new device added.
+     * @param newPorts an array of string representation of ports
+     */
+    checkDeviceAdded(newPorts){
+        this._comparePortsWithEmittion(newPorts, this.ports, "deviceAdded");
+    }
+
+    /**
+     * Compares the previous scan's port list with the current port list.
+     * Emits deviceRemoved for each device removed.
+     * @param newPorts an array of string representation of ports
+     */
+    checkDeviceRemoved(newPorts) {
+        this._comparePortsWithEmittion(this.ports, newPorts, "deviceRemoved");
+    }
+
+    /**
+     * Helper function to compare arrays and emit events.
+     * @param arrayA
+     * @param arrayB
+     * @param event
+     * @private
+     */
+    _comparePortsWithEmittion(arrayA,arrayB, event) {
+        arrayA.forEach((port) => {
+            if(arrayB.indexOf(port) === -1) {
+                this.emit(event, port);
+            }
+        });
+    }
+
+    /**
+     * Emits the error of err.
+     * @param err
+     * @private
+     */
+    _emitError(err) {
+        this.emit("error", err);
+    }
+
+    _listWithCallback(err, ports, callback) {
+        if(err) {
+            this._emitError(err);
+        }
+        else if(ports.length === 0) {
+            this._emitError(new Error("No serial ports detected."));
+        }
+        else {
+            callback();
+        }
+    }
+
+    _portMap(port) {
+        return port.comName;
+    }
+
+
+};

+ 24 - 35
front-end/js/app.js

@@ -1,50 +1,39 @@
-const availableSerialPorts = require("../back-end/available_serial_ports");
+"use strict";
+
+//Relative to index.html not app.js
+const SerialScanner = require("../back-end/serial_scanner");
+const PortSelect = require("./js/port_select");
 
 function $(id) { return document.getElementById(id) }
 
 const flashButton = $("flash-button");
 const appStatus = $("status");
-const portsSelect = $("ports");
+const portsSelect = new PortSelect($("ports"));
+const serialScanner = new SerialScanner();
+const pollTime = 1000; // One second
+
 var last_notification = "";
 
 flashButton.addEventListener("click", event => {
     var notification = new Notification("Flash Finished!");
 });
 
+serialScanner.on("ports", (ports) => {
+    portsSelect.addAll(ports);
+    readyToFlash();
+});
 
-function checkPorts() {
-    availableSerialPorts()
-        .then(addPortsToSelect)
-        .then(readyToFlash)
-        .catch(onError);
-
-}
+serialScanner.on("deviceAdded", (port) => {
+    portsSelect.add(port);
+    new Notification(`Added: ${port}!`);
+});
 
-/**
- * Removes existing comment, adds ports to the serial port SELECT element.
- * @param ports An Array of strings.
- */
-function addPortsToSelect(ports) {
-    //Gets currently selected
-    const previousValue = portsSelect.value;
-    //Empty Select
-    portsSelect.innerHTML = "";
-    ports.forEach(port => {
-        appendPortToSelect(port, previousValue)
-    });
-}
+serialScanner.on("deviceRemoved", (port ) => {
+    portsSelect.remove(port);
+    new Notification(`Removed: ${port}!`);
+});
 
-/**
- * Appends a single port to the end of serial port SELECT element.
- * @param port
- */
-function appendPortToSelect(port, previousValue){
-    const option = document.createElement("option");
-    option.textContent = port;
-    option.value = port;
-    option.selected = previousValue === port;
-    portsSelect.appendChild(option);
-}
+serialScanner.on("error", onError);
 
 /**
  * Updates UI to say it's ready
@@ -78,8 +67,8 @@ function onError(error){
  * Sets up UI
  */
 function init() {
-    checkPorts();
-    setInterval(checkPorts, 1000);
+    serialScanner.scan();
+    setInterval(serialScanner.checkForChanges.bind(serialScanner), pollTime);
 }
 
 init();

+ 61 - 0
front-end/js/port_select.js

@@ -0,0 +1,61 @@
+"use strict";
+
+module.exports = class PortSelect {
+    constructor(selectElement) {
+        this.selectElement = selectElement;
+        this.map = {}; // Cache matching the text value of a port to OPTION element.
+    }
+
+    /**
+     * Appends a single port to the end of serial port SELECT element.
+     * Adds port to map.
+     * @param port
+     */
+    add(port) {
+        const option = this.createOption(port);
+        this.map[port] = option;
+        this.selectElement.appendChild(option);
+    }
+
+    /**
+     * Removed single port from the serial port SELECT element.
+     * Removes port from map.
+     * @param port
+     */
+    remove(port) {
+        this.selectElement.removeChild(this.map[port]);
+        delete this.map[port];
+    }
+
+    /**
+     * Removes existing comment, adds ports to the serial port SELECT element.
+     * @param ports. An Array of strings.
+     */
+    addAll(ports) {
+        ports.forEach(port => {
+            this.add(port);
+        });
+    }
+
+
+    /**
+     * Creates option with the port text and value.
+     * @param port
+     * @returns {Element}
+     */
+    createOption(port) {
+        const option = document.createElement("option");
+        option.textContent = port;
+        option.value = port;
+        return option;
+    }
+
+    /**
+     * Pass through.
+     * Updates the disabled attribute on the SELECT element.
+     * @param value
+     */
+    set disabled (value) {
+        this.selectElement.disabled = value;
+    }
+}