Commit 1972784a authored by Eric Jennings's avatar Eric Jennings

Initial import of pinoccio-chrome-app files into the repo

parent 89d4fca0
This diff is collapsed.
var DEBUG_MODE = false;
var timeout = 100;
var clientSock;
var myLog = Function.prototype.bind.call(console.log, console);
function debugLog() {
if (DEBUG_MODE) {
var args = Array.prototype.slice.call(arguments, 0);
myLog.apply(console, args);
}
}
chrome.app.runtime.onRestarted.addListener(function(data) {
console.log("We restarted");
});
chrome.runtime.onStartup.addListener(function(details) {
console.log("onStartup ", details);
});
chrome.runtime.onInstalled.addListener(function(details) {
console.log("Installed", details);
});
chrome.runtime.onSuspend.addListener(function() {
});
chrome.runtime.onMessageExternal.addListener(function(msg, sender, responder) {
if (chrome.serial.getDevices) {
PinoccioSerial = PinoccioSerial2;
}
/*
var device = new pinoccio.Device(port);
device.connect(portName, function() {
device.signOn(function() {
console.log("DONE READ");
return;
});
});
*/
var cmds = {
getManifest:function(){
responder(chrome.runtime.getManifest());
},
waitForUnplug:function() {
if (msg.cancel === true) {
pinoccio.cancelUSBPluggedIn();
return responder({msg:"Canceled the usb check."});
}
if (!msg.interval) {
return responder({error:"An interval must be specified"});
}
pinoccio.checkUSBPluggedIn(msg.interval, function() {
responder({unplugged:true, msg:"The device was unplugged"});
});
},
fetchAndProgramPort:function() {
var req = new XMLHttpRequest();
req.onload = function() {
console.log("Loaded ", typeof this.responseText);
var programHex = this.responseText;
var device = new pinoccio.Device();
device.connect(msg.port, function(err) {
if (err) {
responder({error:err});
return;
}
device.saveProgram(programHex.trim(), function(err) {
var resp = {};
if (err) resp.error = err;
responder(resp);
});
});
}
req.onError = function() {
console.error("ZOMG ", arguments);
responder({error:"Unable to fetch the program contents."});
};
console.log("Fetching ", msg.url);
req.open("get", msg.url, true);
req.send();
},
fetchAndProgram:function() {
var req = new XMLHttpRequest();
req.onload = function() {
console.log("Loaded ", typeof this.responseText);
var programHex = this.responseText;
pinoccio.findSerial(function(err, device) {
if (err) {
console.error(err);
return responder({error:err});
}
device.saveProgram(programHex.trim(), function(err) {
var resp = {};
if (err) resp.error = err;
responder(resp);
});
});
};
req.onError = function() {
console.error("ZOMG ", arguments);
responder({error:"Unable to fetch the program contents."});
};
console.log("Fetching ", msg.url);
req.open("get", msg.url, true);
req.send();
},
program:function() {
pinoccio.findSerial(function(err, device) {
if (err) {
console.error(err);
return;
}
device.saveProgram(msg.program, function(err) {
var resp = {};
if (err) {
resp.error = err;
}
console.log("Save done");
responder(resp);
});
});
},
detect:function() {
if (!msg.timeout) {
return responder({error:"A timeout must be specified when searching for the device."});
}
pinoccio.checkForDevice(msg.timeout, function(err, foundIt) {
var resp = {
found:foundIt === true ? true : false
};
if (err) resp.error = err;
pinoccio.findSerial(function(err, device) {
if (!err && device) {
resp.isOn = true;
resp.version = "1.0"; // We assume this for now until pinoccio.js allos other versions
} else {
resp.isOn = false;
}
responder(resp);
});
});
},
forget:function() {
pinoccio.forgetDevice(function(err){
var resp = {};
if (err) {
console.error(err);
res.error = err;
}
responder(resp);
});
},
close:function() {
pinoccio.closeAll(function() {
responder({});
});
},
bitlash:function() {
// TODO: Support timeout
pinoccio.findSerial(function(err, device) {
if (err) {
console.error(err);
return;
}
if (!device) {
console.error("Can't find the pinoccio");
return;
}
console.log("We got it!");
var conn = device.conn;
conn.flush(function() {
console.log("Going to run %s", msg.command.trim());
conn.unechoWrite(msg.command.trim() + "\n", function() {
// TODO Make this multiline aware
conn.readUntilPrompt("> ", function(err, data) {
var resp = {};
if (err) {
resp.error = err;
} else {
resp.result = data;
}
console.log("Result line is: ", resp);
responder(resp);
});
});
});
});
}
};
if (!cmds.hasOwnProperty(msg.op)) {
return responder({error:"Unknown op"});
}
cmds[msg.op]();
return true; // required if we want to respond after the listener
});
chrome.app.runtime.onLaunched.addListener(function(data) {
console.log("We launched");
var a = document.createElement('a');
a.href = "http://hq.pinocc.io";
a.target='_blank';
a.click();
});
This diff is collapsed.
var serial = chrome.serial;
var openSerialIDs = [];
(function(exports) {
function saveConnections(cbDone) {
chrome.storage.local.set({connections:openSerialIDs}, function() {
cbDone();
});
}
function SerialConnection() {
this.connectionId = -1;
this.callbacks = {};
this._flushOnWrite = false;
}
SerialConnection.prototype.connect = function(device, callback) {
serial.open(device, {bitrate:115200}, this.onOpen.bind(this))
this.callbacks.connect = callback;
};
SerialConnection.prototype.getControlSignals = function(callback) {
serial.getControlSignals(this.connectionId, callback);
}
SerialConnection.prototype.setControlSignals = function(options, callback) {
serial.setControlSignals(this.connectionId, options, callback);
}
SerialConnection.prototype.flush = function(callback) {
this.callbacks.flush = callback;
serial.flush(this.connectionId, this.onFlush.bind(this));
}
SerialConnection.prototype.readBytes = function(readlen, callback) {
var retData = "";
var self = this;
function processRead(readInfo) {
retData += self.ab2str(readInfo.data);
if (readInfo.bytesRead > 0 && readInfo.readlen - retData.length > 0) {
setTimeout(function() {
serial.read(this.connectionId, readlen - retData.length, processRead);
}, 10);
} else {
callback(retData);
}
}
serial.read(this.connectionId, readlen, processRead);
}
SerialConnection.prototype.read = function(readlen, callback) {
if (arguments.length == 1 && typeof readlen === "function") {
callback = readlen;
readlen = 1;
}
// Only works for open serial ports.
if (this.connectionId < 0) {
throw 'Invalid connection';
}
this.callbacks.read = callback;
serial.read(this.connectionId, readlen, this.onRead.bind(this));
};
SerialConnection.prototype.waitForPrompt = function(prompt, callback) {
var self = this;
setTimeout(function() {
self.readBytes(prompt.length, function(readData) {
if (prompt.trim() != readData.trim()) console.log("Mismatched prompts %s:%s", prompt, readData);
callback();
});
}, 1000);
}
SerialConnection.prototype.readUntilPrompt = function(prompt, callback) {
var self = this;
var readBuffer = "";
var emptyReadCount = 0;
function handleRead(readInfo) {
var readWait = 0;
//console.log(readInfo);
if (readInfo && readInfo.data) {
if (readInfo.bytesRead > 0) {
emptyReadCount = 0;
readBuffer += self.ab2str(readInfo.data);
// console.log("Read Buffer", readBuffer);
var tailPos = readBuffer.length - prompt.length;
if (readBuffer.substring(tailPos, tailPos + prompt.length) == prompt) {
return callback(null, readBuffer.substring(0, tailPos));
}
} else {
readWait = 50;
if (++emptyReadCount > 100) {
return callback("Could not read");
}
}
}
setTimeout(function() { self.read(handleRead); }, readWait);
}
this.read(handleRead);
};
SerialConnection.prototype.readUntil = function(marker, callback) {
var self = this;
// Only works for open serial ports.
if (this.connectionId < 0) {
throw 'Invalid connection';
}
var line = '';
// Keep reading bytes until we've found a newline.
var readLineHelper = function(readInfo) {
var char = self.ab2str(readInfo.data);
if (char == '') {
// Nothing in the buffer. Try reading again after a small timeout.
setTimeout(function() {
self.read(readLineHelper);
}.bind(self), timeout);
return;
}
if (char == marker) {
// End of line.
callback(line);
line = '';
return;
}
line += char;
self.read(readLineHelper)
}.bind(self)
this.read(readLineHelper);
};
SerialConnection.prototype.readLine = function(callback) {
return this.readUntil("\n", callback);
}
SerialConnection.prototype.write = function(msg, callback) {
// Only works for open serial ports.
if (this.connectionId < 0) {
throw 'Invalid connection';
}
this.callbacks.write = callback;
this._stringToArrayBuffer(msg, function(array) {
serial.write(this.connectionId, array, this.onWrite.bind(this));
}.bind(this));
};
SerialConnection.prototype.writeRaw = function(msg, callback) {
this.callbacks.write = callback;
serial.write(this.connectionId, msg, this.onWrite.bind(this));
}
SerialConnection.prototype.unechoWrite = function(msg, callback) {
var self = this;
this.flushedWrite(msg, function(writeInfo) {
// We have to add +1 for the newline here
self.readBytes(msg.length + 1, function(readMsg) {
if (readMsg.trim() != msg.trim()) {
console.log("Mismatch on echo strings: -%s:%s-", readMsg.trim(), msg.trim());
}
callback();
});
});
}
SerialConnection.prototype.close = function(callback) {
serial.close(this.connectionId, callback);
}
SerialConnection.prototype.flushedWrite = function(msg, callback) {
this._flushOnWrite = true;
this.write(msg, callback);
}
SerialConnection.prototype.onOpen = function(connectionInfo) {
openSerialIDs.push(connectionInfo.connectionId);
saveConnections(function() {});
this.connectionId = connectionInfo.connectionId;
if (this.callbacks.connect) {
this.callbacks.connect();
}
};
SerialConnection.prototype.onFlush = function() {
serial.read(this.connectionId, 4096, function() {
if (this.callbacks.flush) {
this.callbacks.flush();
}
}.bind(this));
};
SerialConnection.prototype.onRead = function(readInfo) {
if (this.callbacks.read) {
this.callbacks.read(readInfo);
}
};
SerialConnection.prototype.onWrite = function(writeInfo) {
if (this.callbacks.write) {
if (this._flushOnWrite) {
var self = this;
setTimeout(function() {
self._flushOnWrite = false;
serial.flush(self.connectionId, function() {
self.callbacks.write(writeInfo);
});
}, 500);
} else {
this.callbacks.write(writeInfo);
}
}
};
/** From tcp-client */
SerialConnection.prototype._arrayBufferToString = function(buf, callback) {
var blob = new Blob([buf]);
var f = new FileReader();
f.onload = function(e) {
callback(e.target.result)
}
f.readAsText(blob);
}
SerialConnection.prototype._stringToArrayBuffer = function(str, callback) {
var blob = new Blob([str]);
var f = new FileReader();
f.onload = function(e) {
callback(e.target.result);
}
f.readAsArrayBuffer(blob);
}
/* the arraybuffer is interpreted as an array of UTF-8 (1-byte Unicode chars) */
SerialConnection.prototype.ab2str = function(buf) {
var bufView=new Uint8Array(buf);
var unis=[];
for (var i=0; i<bufView.length; i++) {
unis.push(bufView[i]);
}
return String.fromCharCode.apply(null, unis);
};
window.PinoccioSerial = {
SerialConnection : SerialConnection,
closeAll : function(cbDone) {
debugLog("Closing all old connections");
chrome.storage.local.get(["connections"], function(items) {
if (!items || !items.connections || items.connections.length == 0) {
return setTimeout(cbDone, 0);
}
async.forEach(items.connections, function(connId, cbStep) {
debugLog("Closing ", connId);
chrome.serial.close(connId, function() {
cbStep()
});
}, function() {
chrome.storage.local.remove(["connections"], function() {
cbDone();
});
})
});
},
getDevices : function(cbDone) {
chrome.serial.getPorts(function(ports) {
cbDone(ports.map(function(port) { return {path:port}; }));
});
},
saveConnections : saveConnections }
})(window);
var serial = chrome.serial;
var serialConnections = {};
(function(exports) {
function handleRead(readInfo) {
var serialConn = serialConnections[readInfo.connectionId];
if (!serialConn) {
console.error("Blackholed read data", readInfo, serialConnections);
return;
}
var bufView = new Uint8Array(readInfo.data);
var unis = [];
for (var i=0; i<bufView.length; i++) {
unis.push(bufView[i]);
}
var chunk = String.fromCharCode.apply(null, unis);
//console.log("chunk ==%s==", chunk);
serialConn.readBuffer += chunk;
//console.log("Reabuffer :%s:", serialConn.readBuffer);
//console.log("handleRead ", readInfo, " buffer is now ", serialConn.readBuffer);
};
if (serial.onReceive) serial.onReceive.addListener(handleRead);
if (serial.onReceiveError) {
serial.onReceiveError.addListener(function(errorInfo) {
console.error("Receive error ", errorInfo);
});
}
function SerialConnection() {
this.connectionId = -1;
this.callbacks = {};
this._flushOnWrite = false;
this.readBuffer = "";
}
SerialConnection.prototype.connect = function(device, callback) {
console.log(serial);
var options = {
name:"Pinoccio",
bitrate:115200
};
serial.connect(device, options, this.onOpen.bind(this))
this.callbacks.connect = callback;
};
SerialConnection.prototype.getControlSignals = function(callback) {
serial.getControlSignals(this.connectionId, callback);
}
SerialConnection.prototype.setControlSignals = function(options, callback) {
serial.setControlSignals(this.connectionId, options, callback);
}
SerialConnection.prototype.flush = function(callback) {
this.readBuffer = "";
console.log("Flushing for ", this.readBuffer);
this.callbacks.flush = callback;
serial.flush(this.connectionId, this.onFlush.bind(this));
}
SerialConnection.prototype.readBytes = function(readlen, callback) {
var retData = "";
var self = this;
function processRead(readData) {
retData += readData;
if (readData.length > 0 && readlen - retData.length > 0) {
setTimeout(function() {
self.read(readlen - retData.length, processRead);
}, 10);
} else {
callback(retData);
}
}
this.read(readlen, processRead);
}
SerialConnection.prototype.read = function(readlen, callback) {
if (arguments.length == 1 && typeof readlen === "function") {
callback = readlen;
readlen = 1;
}
// Only works for open serial ports.
if (this.connectionId < 0) {
throw 'Invalid connection';
}
this.callbacks.read = callback;
if (this.readBuffer.length == 0) {
return this.onRead("");
}
var actualReadLen = Math.min(readlen, this.readBuffer.length);
//console.log("actualReadLen(%d)", actualReadLen);
var readData = this.readBuffer.slice(0, actualReadLen);
this.readBuffer = this.readBuffer.slice(actualReadLen);
readData.bytesRead = actualReadLen;
//console.log("Read ", readData);
this.onRead(readData);
};
SerialConnection.prototype.waitForPrompt = function(prompt, callback) {
var self = this;
setTimeout(function() {
self.readBytes(prompt.length, function(readData) {
if (prompt.trim() != readData.trim()) console.log("Mismatched prompts %s:%s", prompt, readData);
callback();
});
}, 1000);
}
SerialConnection.prototype.readUntilPrompt = function(prompt, callback) {
var self = this;
var readBuffer = "";
var emptyReadCount = 0;
function handleRead(readData) {
var readWait = 0;
//console.log("Appending ", readData);
if (readData.length > 0) {
emptyReadCount = 0;
readBuffer += readData;
} else {
readWait = 100;
if (++emptyReadCount > 200) {
return callback("Could not read");
}
}
var tailPos = readBuffer.length - prompt.length;
//console.log("Checking -%s- from =%s=", readBuffer.substring(readBuffer.length, readBuffer.length - prompt.length), readBuffer);
if (readBuffer.substring(readBuffer.length, readBuffer.length - prompt.length) == prompt) {
return callback(null, readBuffer.substring(0, tailPos));
}
//console.log("Buffer is ", readBuffer);
setTimeout(function() { self.read(handleRead); }, readWait);
}
this.read(handleRead);
};
SerialConnection.prototype.readUntil = function(marker, callback) {
var self = this;
// Only works for open serial ports.
if (this.connectionId < 0) {
throw 'Invalid connection';
}
var line = '';