-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding utility that sets the UUID of ChillHub attachments.
- Loading branch information
Rob Bultman
committed
Jan 22, 2015
1 parent
74b4de1
commit e26d55b
Showing
1 changed file
with
324 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,324 @@ | ||
var serial = require('serialport'); | ||
var fs = require('fs'); | ||
var stream = require('binary-stream'); | ||
var sets = require('simplesets'); | ||
var commons = require('./commons'); | ||
var parsers = require('./parsing'); | ||
var uuid = require('uuid-v4'); | ||
|
||
function ChillhubDevice(ttyPath) { | ||
var self = this; | ||
|
||
var ESC = 0xfe; | ||
var STX = 0xff; | ||
self.deviceType = ''; | ||
self.UUID = ''; | ||
self.buf = []; | ||
self.msgBody = []; | ||
self.resources = {}; | ||
self.registered = false; | ||
self.newUUID = ''; | ||
|
||
self.uid = ttyPath; | ||
self.tty = new serial.SerialPort('/dev/'+ttyPath, { | ||
baudrate: 115200, | ||
disconnectedCallback: function(err) { | ||
if (err) { | ||
console.log('error in disconnectedCallback'); | ||
console.log(err); | ||
console.log('UUID is ' + self.UUID); | ||
} | ||
} | ||
}); | ||
|
||
self.tty.open(function(err) { | ||
if (err) { | ||
console.log('error opening serial port'); | ||
console.log(err); | ||
return; | ||
} | ||
|
||
self.tty.flush(function(err) { | ||
if (err) { | ||
console.log("Error flushing the serial port input buffer."); | ||
console.log(err); | ||
return; | ||
} | ||
|
||
console.log("Serial port input buffer flushed."); | ||
|
||
self.scanForStx = function() { | ||
while (self.buf.length > 0) { | ||
var c = self.buf.shift(); | ||
if (c == STX) { | ||
self.commHandler = self.waitForLength; | ||
self.waitForLength(); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
self.waitForLength = function() { | ||
if (self.buf.length > 1) { | ||
if (self.buf[0] == ESC) { | ||
self.buf.shift(); | ||
} | ||
self.msgLen = self.buf.shift(); | ||
self.bufIndex = 0; | ||
self.msgBody.length = 0; | ||
self.commHandler = self.waitForMessage; | ||
self.waitForMessage(); | ||
} | ||
} | ||
|
||
self.waitForMessage = function() { | ||
while (self.buf.length > self.bufIndex) { | ||
if (self.buf[self.bufIndex] == ESC) { | ||
if ((self.buf.length - self.bufIndex) > 1) { | ||
self.bufIndex++; | ||
} else { | ||
return; | ||
} | ||
} | ||
self.msgBody.push(self.buf[self.bufIndex++]); | ||
// wait for message plus sent checksum | ||
if (self.msgBody.length >= self.msgLen+2) { | ||
self.checkMessage(); | ||
} | ||
} | ||
} | ||
|
||
self.checkMessage= function() { | ||
var csSent = self.msgBody.pop() + self.msgBody.pop()*256; | ||
var cs = 42; | ||
for (var i = 0; i<self.msgBody.length; i++) { | ||
cs += self.msgBody[i]; | ||
} | ||
if (cs == csSent) { | ||
// remove message from input buffer | ||
self.buf.splice(0, self.bufIndex); | ||
self.msgBody.shift(); | ||
routeIncomingMessage(self.msgBody); | ||
} else { | ||
console.log("Check sum error."); | ||
self.buf.shift(); | ||
} | ||
self.commHandler = self.scanForStx; | ||
self.scanForStx(); | ||
} | ||
|
||
self.commHandler = self.scanForStx; | ||
|
||
self.tty.on('data', function(data) { | ||
// network byte order is big endian... let's go with that | ||
self.buf = self.buf.concat((new stream.Reader(data, stream.BIG_ENDIAN)).readBytes(data.length)); | ||
self.commHandler(); | ||
return; | ||
|
||
while(self.buf.length > self.buf[0]) { | ||
msg = self.buf.slice(1,self.buf[0]+1); | ||
self.buf = self.buf.slice(self.buf[0]+1,self.buf.length); | ||
if (msg.length > 0) { | ||
routeIncomingMessage(msg); | ||
} | ||
} | ||
}); | ||
self.tty.on('error', function(err) { | ||
console.log('serial error:'); | ||
console.log(err); | ||
}); | ||
self.tty.on('disconnect', function(err) { | ||
console.log('error disconnecting?'); | ||
console.log(err); | ||
}); | ||
|
||
self.send = function(data) { | ||
// parse data into the format that usb devices expect and transmit it | ||
var dataBytes = parsers.parseJsonToStream(data); | ||
var writer = new stream.Writer(dataBytes.length+1, stream.BIG_ENDIAN); | ||
writer.writeUInt8(dataBytes.length); | ||
writer.writeBytes(dataBytes); | ||
var buf = writer.toArray(); | ||
var outBuf = []; | ||
|
||
if (buf.length > 255) { | ||
console.log("ERROR: Cannot send a message longer than 255 bytes!!!"); | ||
return; | ||
} | ||
|
||
var encodeByteToArray = function(b, a) { | ||
if (b == ESC || b == STX) { | ||
a.push(ESC); | ||
} | ||
a.push(b); | ||
} | ||
|
||
// Take message body, wrap in STX and checksum, add escapes as needed. | ||
outBuf.push(STX); | ||
encodeByteToArray(buf.length, outBuf); | ||
var cs = 42; | ||
for (var i=0; i<buf.length; i++) { | ||
encodeByteToArray(buf[i], outBuf); | ||
cs += buf[i]; | ||
} | ||
encodeByteToArray(commons.getNibble(cs, 2), outBuf); | ||
encodeByteToArray(commons.getNibble(cs, 1), outBuf); | ||
self.tty.write(outBuf, function(err) { | ||
if (err) { | ||
console.log('error writing to serial'); | ||
console.log(err); | ||
} | ||
}); | ||
return; | ||
|
||
writer.writeUInt8(dataBytes.length); | ||
writer.writeBytes(dataBytes); | ||
console.log("WRITER in send",writer.toArray()); | ||
self.tty.write(writer.toArray(), function(err) { | ||
if (err) { | ||
console.log('error writing to serial'); | ||
console.log(err); | ||
} | ||
}); | ||
}; | ||
|
||
if (self.onOpenCallback) { | ||
self.onOpenCallback(); | ||
} | ||
}); | ||
}); | ||
|
||
function setDeviceUUID() { | ||
self.send({ | ||
type: 0x0c, | ||
content: self.newUUID | ||
}); | ||
// wait a little, then request UUID again. | ||
setTimeout(function() { | ||
self.send({ | ||
type: 0x08, | ||
content: { | ||
numericType: 'U8', | ||
numericValue: 1 | ||
} | ||
}); | ||
}, 2000); | ||
} | ||
|
||
function startSetUUIDProcess() { | ||
self.newUUID = uuid(); | ||
console.log("Attempting to set UUID to: " + self.newUUID); | ||
setDeviceUUID(); | ||
} | ||
|
||
function routeIncomingMessage(data) { | ||
// parse into whatever form and then send it along | ||
var jsonData = parsers.parseStreamToJson(data); | ||
|
||
switch (jsonData.type) { | ||
case 0x00: | ||
if (self.registered == false) { | ||
if (jsonData.content === undefined) { | ||
console.log("Content is missing from message type 0x00 received from attachment."); | ||
return; | ||
} | ||
self.deviceType = jsonData.content[0]; | ||
self.UUID = jsonData.content[1]; | ||
console.log('Found device "'+self.deviceType+'" with UUID '+ self.UUID + '!'); | ||
|
||
self.registered = true; | ||
startSetUUIDProcess(); | ||
} else { | ||
// we were registered, see if the set UUID process worked. | ||
if (jsonData.content === undefined) { | ||
console.log("Content is missing from message type 0x00 received from attachment."); | ||
return; | ||
} | ||
self.deviceType = jsonData.content[0]; | ||
self.UUID = jsonData.content[1]; | ||
if (self.UUID === self.newUUID) { | ||
console.log("New UUID successfully set."); | ||
process.exit(0); | ||
} else { | ||
console.log("ERROR: Unable to set the UUID on the device."); | ||
console.log("The device sent a UUID of " + self.UUID); | ||
process.exit(1); | ||
} | ||
} | ||
break; | ||
} | ||
} | ||
|
||
self.cleanup = function() { | ||
}; | ||
|
||
self.registerOpenCallback = function(func) { | ||
self.onOpenCallback = func; | ||
} | ||
|
||
self.sendRegistrationRequest = function sendRegistrationRequest () { | ||
self.send({ | ||
type: 0x08, | ||
content: { | ||
numericType: 'U8', | ||
numericValue: 1 | ||
} | ||
}); | ||
} | ||
|
||
self.checkForDeviceRegistration = function checkForDeviceRegistration() { | ||
if (!self.registered) { | ||
console.log("Device was not properly registered, requesting registration info again."); | ||
self.sendRegistrationRequest(); | ||
setTimeout(self.checkForDeviceRegistration, 5000); | ||
} | ||
} | ||
|
||
setTimeout(self.checkForDeviceRegistration, 5000); | ||
} | ||
|
||
var devices = {}; | ||
|
||
if (process.platform === 'darwin') { | ||
console.log("We are running on a Mac, look for tty.usbmodem devices."); | ||
var filePattern = /^tty.usbmodem[0-9]+$/; | ||
} else { | ||
var filePattern = /^ttyACM[0-9]{1,2}$/; | ||
} | ||
|
||
fs.readdir('/dev/', function(err, files) { | ||
files = files.filter(function(file) { | ||
return filePattern.test(file); | ||
}); | ||
|
||
files.forEach(function(filename) { | ||
console.log('registering new USB device ' + filename); | ||
devices[filename] = new ChillhubDevice(filename); | ||
(function() { | ||
var what = filename; | ||
devices[filename].registerOpenCallback (function() { | ||
devices[what].sendRegistrationRequest(); | ||
}); | ||
})(); | ||
}); | ||
}); | ||
|
||
// watch for new devices | ||
fs.watch('/dev/', function(event, filename) { | ||
console.log("Saw a change in dev."); | ||
if (!filePattern.test(filename)) | ||
return; | ||
|
||
fs.exists('/dev/'+filename, function (exists) { | ||
if (devices[filename] && !exists) { | ||
console.log('unregistering USB device ' + filename); | ||
devices[filename].cleanup(); | ||
delete devices[filename]; | ||
} | ||
else if (!devices[filename] && exists) { | ||
console.log('registering new USB device ' + filename); | ||
devices[filename] = new ChillhubDevice(filename); | ||
} | ||
}); | ||
}); | ||
|