Commit 306536c6 authored by Karan Goel's avatar Karan Goel
Browse files

hookup brain server to client.

parent d8ad5fb9
// DEBUG switch.
var DEBUG = false;
// Import filesystem.
var fs = require('fs');
var app = require('http').createServer();
// Import socket.io.
var io = require('socket.io')(app);
// Import enums.
var Enum = require('enum');
// Create serial port object.
var SerialPort = require("serialport").SerialPort;
// ThinkGear Communication Protocol constants.
var AUTOCONNECT = 0xC2;
var CONNECT = 0xC0C00C;
var DISCONNECT = 0xC1;
var SYNC = 0xAA;
var EXCODE = 0x55;
var CODE_ATTENTION = 0x04
var CODE_MEDITATION = 0x05
// The object that holds the timer that reties connection
var connect_timer = null;
// Obtain name of user-speficied serial port device.
var serialPortName = process.argv[2];
if (!serialPortName) {
console.log("Serial port name missing! => node NodeTGC.js <path-to-serial-port-device>")
process.exit(1);
}
// Open serial port of the Neurosky MindWave using the given name.
var nmwSerialPort = new SerialPort(serialPortName, {
baudRate : 115200 // According the chip specification the baudrate has to be 115200.
});
var nmwSerialPortOpen = false;
// Start socket.io server listening on port 3000.
io.listen(3000);
// Handle user input.
var readline = require('readline'),
rl = readline.createInterface(process.stdin, process.stdout);
rl.on('close', function() {
if (nmwSerialPortOpen) {
// Disconnect from the Neurosky MindWave.
nmwSerialPort.write(new Buffer([DISCONNECT], 'hex'), function(error, results) {
if (error || results != 1) {
console.log("Could not disconnect from the Neurosky MindWave." + err);
process.exit(1);
} else {
console.log("Disconnect...");
}
});
nmwSerialPort.drain();
nmwSerialPort.close();
}
io.close();
process.exit(0);
});
// Listen for open-events: Called when the serial port connection is established.
nmwSerialPort.on("open", function (error) {
if (error) {
console.log("Serial port failed to open: " + error);
} else {
nmwSerialPortOpen = true;
console.log("Serial port to \"" + serialPortName + "\" successfully openend.");
// Attach a listener for the incoming packets from the serial port.
nmwSerialPort.on("data", receivePackets);
connect_timer = setInterval(connect, 10000);
}
});
function connect() {
// Autoconnect to the first discovered Neurosky MindWave.
nmwSerialPort.write(new Buffer([AUTOCONNECT], 'hex'), function(error, results) {
if (error || results != 1) {
console.log("Could not connect to the Neurosky MindWave." + err);
process.exit(1);
} else {
console.log("Connecting...");
}
});
}
// State Machine for the serial port data processing.
var ProcessState = new Enum(['SYNC', 'SYNC_CHECK', 'PAYLOAD_LENGTH', 'PAYLOAD', 'CHECKSUM']);
var state = ProcessState.SYNC; // Initial state is SYNC.
var payloadLength;
var payloadIndex;
var payloadBuffer;
var checksum;
// Process the incoming packets from the serial port.
// TODO: Decouple processing of the packets from the checksum check => new PROCESS state!
function receivePackets (data) {
for (var i = 0; i < data.length; i++) {
// Obtain the next byte from the serial port connection.
var next_byte = data.readUInt8(i);
if (DEBUG) console.log ("Process Next Byte: " + next_byte.toString(16));
switch (state) {
// Seek for synchronization byte.
case ProcessState.SYNC:
if (next_byte == SYNC) {
state = ProcessState.SYNC_CHECK;
if (DEBUG) console.log("SYNC");
}
break;
// Double check the synchronization byte.
case ProcessState.SYNC_CHECK:
if (next_byte == SYNC) {
state = ProcessState.PAYLOAD_LENGTH;
if (DEBUG) console.log("SYNC DOUBLECHECK");
} else {
state = ProcessState.SYNC;
if (DEBUG) console.log("SYNC DOUBLECHECK FAILED");
}
break;
// Obtain the payload length.
case ProcessState.PAYLOAD_LENGTH:
payloadLength = next_byte;
if (payloadLength > 170) {
state = ProcessState.SYNC;
if (DEBUG) console.log("PAYLOAD TOO LARGE (>170)");
} else if (payloadLength == 170) {
if (DEBUG) console.log("PAYLOAD == SYNC");
} else { // Pre-Condition: payLoadLength < 170
// Create a suitable payload buffer for the upcoming serial data.
payloadBuffer = new Buffer(payloadLength, 'hex');
payloadIndex = 0;
checksum = 0;
state = ProcessState.PAYLOAD;
if (DEBUG) console.log("PAYLOAD LENGTH IS: " + payloadLength);
}
break;
// Receive the payload and compute the checksum in parallel.
case ProcessState.PAYLOAD:
if (payloadIndex < payloadLength) {
payloadBuffer[payloadIndex] = next_byte;
checksum += next_byte;
++payloadIndex;
if (DEBUG) console.log("RECEIVE PAYLOAD [" + payloadIndex + "," + payloadBuffer.toString('hex') + "]");
}
if (payloadIndex == payloadLength) {
checksum = checksum & 0xFF;
checksum = (~checksum) & 0xFF;
state = ProcessState.CHECKSUM;
if (DEBUG) console.log("PREPARE CHECKSUM CHECK");
}
break;
// Validate the payload with the following checksum byte;
case ProcessState.CHECKSUM:
if (checksum == next_byte) {
if (DEBUG) console.log("CHECKSUM VALID");
// Checksum was valid, thus, processing packet given by the payload since is okay.
processPacket();
} else { // Pre-Condition: checksum != data
if (DEBUG) console.log("CHECKSUM IS WRONG [" + checksum + "!=" + next_byte + "]");
}
state = ProcessState.SYNC;
break;
default:
if (DEBUG) console.log("CRITICAL ERROR");
process.exit(1);
}
}
}
function processPacket() {
if (DEBUG) console.log("Process Packet");
// Create an empty EEG package.
var EEGPackage = {};
// Process all data rows in the received serial data package.
var payloadPointer = 0;
while (payloadPointer < payloadBuffer.length) {
// Determine the Extended Code Level (EXCODE) and CODE.
var extendedCodeLevel = 0;
var code;
while (payloadPointer < payloadBuffer.length) {
var next_byte = payloadBuffer.readUInt8(payloadPointer);
++payloadPointer;
if (next_byte == EXCODE) {
++extendedCodeLevel;
} else {
// The first byte unequal the EXCODE byte specifies the CODE.
code = next_byte;
break;
}
}
if (DEBUG) console.log ("extendedCodeLevel: " + extendedCodeLevel.toString(16) + ", code: " + code.toString(16));
if (extendedCodeLevel == 0) {
if (code <= 0x7F) { // Single-Byte CODEs
if (DEBUG) console.log ("Single-Byte CODE");
if (payloadPointer < payloadBuffer.length) {
var value = payloadBuffer.readUInt8(payloadPointer);
++payloadPointer;
// TODO: move to multi byte code
connect_timer = null;
switch (code) {
case CODE_ATTENTION:
EEGPackage["attention"] = value;
console.log ("ATTENTION: " + value);
break;
case CODE_MEDITATION:
EEGPackage["meditation"] = value;
console.log ("MEDITATION: " + value);
break;
default:
if (DEBUG) console.log ("DEFAULT: " + value);
}
} else {
if (DEBUG) console.log("CRITICAL ERROR");
process.exit(1);
}
} else { // Multi-Byte CODEs, Pre-Condition: code >= 0x80
if (DEBUG) console.log ("Multi-Byte CODE");
if (payloadPointer < payloadBuffer.length) {
var vlength = payloadBuffer.readUInt8(payloadPointer);
++payloadPointer;
if (DEBUG) console.log("payloadPointer: " + payloadPointer + ", vlength: " + vlength);
// Skip multi-byte data asap.
payloadPointer += vlength;
if (DEBUG) console.log("next payloadPointer: " + payloadPointer);
} else {
if (DEBUG) console.log("CRITICAL ERROR");
process.exit(1);
}
}
} else {
console.log("Not implemented!");
process.exit(1);
}
}
// Record/send the EEGPackage.
if (Object.getOwnPropertyNames(EEGPackage).length !== 0) {
var EEGPackage_JSON = JSON.stringify(EEGPackage);
// Send to clients listening via sockets.
io.emit('get-EEG', JSON.stringify(EEGPackage));
if (DEBUG) console.log(EEGPackage_JSON);
}
}
\ No newline at end of file
......@@ -32,14 +32,34 @@
height: 200px;
margin-bottom: 30px;
position: absolute;
top: 50%;
transform: translateY(-100px);
top: 10%;
/*transform: translateY(-150px);*/
}
#eegWave {
width: 100%;
height: 200px;
margin-bottom: 30px;
position: absolute;
top: 60%;
/*transform: translateY(150px);*/
}
h1 {
color: #fff;
}
</style>
</head>
<body>
<div id="wave"></div>
<div id="wave">
<h1>Soundwave</h1>
</div>
<div id="eegWave">
<h1>EEG Data: (Attention)</h1>
</div>
<script type="text/javascript">
......@@ -52,6 +72,8 @@ var tines = [];
var lastSound = [];
var data = [];
var eegData = [];
var waveform = new Waveform({
container: document.getElementById("wave"),
......@@ -65,6 +87,20 @@ gradient.addColorStop(1.0, "#ff1b00");
waveform.innerColor = gradient;
var eegWaveform = new Waveform({
container: document.getElementById("eegWave"),
interpolate: false
});
var ctx2 = eegWaveform.context;
var gradient2 = ctx2.createLinearGradient(0, 0, 0, eegWaveform.height);
gradient2.addColorStop(0.0, "#ff6");
gradient2.addColorStop(1.0, "#fff");
eegWaveform.innerColor = gradient2;
var instrument = 4;
......@@ -94,16 +130,27 @@ RefreshFrame = function () {
}
};
var socket = io('http://localhost');
socket.on('brain', function (data) {
var socket = io('http://localhost:3000');
socket.on('get-EEG', function (data) {
data = JSON.parse(data);
if (data.attention > 0 && data.meditation > 0) {
RefreshFrame();
var min_nbrPoints = 48;
var max_nbrPoints = 96;
var min_data = 0;
var max_data = 100;
nbrPoints = min_nbrPoints + ((max_nbrPoints - min_nbrPoints) * (data.attention - min_data)) / (max_data - min_data)
nbrPoints = min_nbrPoints + ((max_nbrPoints - min_nbrPoints) * (data.attention - min_data)) / (max_data - min_data);
eegData.push(Math.cos(data.attention - 0.2 + 0.3));
eegWaveform.update({
data: eegData
});
} else {
eegData.push(Math.cos(90));
eegWaveform.update({
data: eegData
});
console.log('Connecting...')
}
});
......@@ -125,7 +172,7 @@ window.onload = function () {
MIDI.programChange(3, 104);
MIDI.programChange(4, 1);
setInterval(RefreshFrame, 200);
// setInterval(RefreshFrame, 200);
}
});
};
......
......@@ -10,6 +10,8 @@
"author": "",
"license": "MIT",
"dependencies": {
"enum": "*",
"serialport": "^1.4.10",
"socket.io": "^1.3.2"
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment