UNPKG

brickpi-raspberry

Version:
411 lines (328 loc) 12.2 kB
var SerialPort = require('serialport').SerialPort; var async = require('async'); var BitArray = require('./BitArray'); var PROTOCOL = require('./Protocol'); var SENSOR_TYPE = require('./Sensor_Type'); // i am pretty sure these could be merged. left for later. var READ_TIMEOUT = 500; //500 var PROTOCOL_TIMEOUT = 1000; //1000 var Driver = function(serialPortAddress) { this._reading = null; this._readLength = null; this._readChecksum = null; this._readBuffer = null; this._readBufferOffset = null; this._readTimeout = null; this._readChecksumData = null; this._asyncCallback = null; this._asyncTimeout = null; this._currentChip = null; this._motors = null; this._sensors = null; this._serialPortAddress = serialPortAddress; }; exports.Driver = Driver; Driver.prototype.open = function(callback) { this._serialPort = new SerialPort(this._serialPortAddress, {baudrate: 500000}); // open serial communication this._serialPort.on("open", function(err) { if (err) callback(err); async.eachSeries([1, 2], this._SetCommunicationTimeout.bind(this), function(err) { callback(err); }); this._serialPort.on('data', function(data) { Array.prototype.forEach.call(data, function(byte) { this._addByte(byte); }.bind(this)); }.bind(this)); }.bind(this)); } Driver.prototype._SetCommunicationTimeout = function(chipIndex, callback) { this._asyncCallback = callback; this._asyncTimeout = setTimeout(function() { console.log('rx Timeout'); callback('timed out'); }, PROTOCOL_TIMEOUT); var timeout = 1000; // set brickpi comm timeout. var data = [ timeout & 0xFF, (timeout >> 8) & 0xFF, (timeout >> 16) & 0xFF, (timeout >> 24) & 0xFF ]; this._currentChip = chipIndex; this._write(chipIndex, PROTOCOL.SET_COMMUNICATION_TIMEOUT, data); }; Driver.prototype.UpdateValues = function(motors, sensors, callback) { async.eachSeries([{chipIndex: 1, motors: motors, sensors: sensors}, {chipIndex: 2, motors: motors, sensors: sensors}], this._UpdateValues.bind(this), function(err) { callback(err); }); } Driver.prototype._UpdateValues = function(params, callback) { this._asyncCallback = callback; this._asyncTimeout = setTimeout(function() { console.log('rx Timeout'); callback('timed out'); }, PROTOCOL_TIMEOUT); this._motors = params.motors; this._sensors = params.sensors; var motors = this._motors; var sensors = this._sensors; // sorry for sloppyness. var chipIndex = params.chipIndex; // 2x motors with 10 bits each + 2 for the encoder offsets var data = new BitArray(); data.addBits(0, 0, 2, 0); // process the motors and sensors asscociated with the chipIndex for (var i=(chipIndex*2 - 2); i<(chipIndex*2); i++) { var motor = motors[i]; if(motor != null) { var speed = motor.speed; var direction = 0 if(speed < 0) { direction = 1 speed *= -1 } if(speed > 255) { speed = 255 } var value = ((((speed & 0xFF) << 2) | ((direction & 0x11) << 1) | ((motor.enabled ? 1 : 0) & 0x01)) & 0x3FF); data.addBits(0, 0, 10, value); } else { data.addBits(0, 0, 10, 0); } } for (var i=(chipIndex*2 - 2); i < (chipIndex*2); i++) { var sensor = sensors[i]; if (sensor != null) { // TOUCH, and other NON I2C sensors, nothing to do. if (sensor.type === SENSOR_TYPE.DEXTER.IMU.ACC) { if (!sensor.setupDone) { sensor.setupDone = true; data.addBits(0, 0, 4, 2); // I2C WRITE data.addBits(0, 0, 4, 0); // I2C READ data.addBits(0, 0, 8, 0x16 /**/); data.addBits(0, 0, 8, 0x05 /*DIMU_ACC_RANGE_2G 0x04 | DIMU_ACC_MODE_MEAS 0x01 */); // I2Cout } data.addBits(0, 0, 4, 1); // Write data.addBits(0, 0, 4, 1); // Read data.addBits(0, 0, 8, sensor.currentAxis); // I2Cout 0x06 x 0x07 y 0x08 z } // console.log('update value request: ' + data.getArray()); } } this._currentChip = chipIndex; this._write(chipIndex, PROTOCOL.READ_SENSOR_VALUES, data.getArray()); } Driver.prototype.SetupSensors = function(sensors, callback) { // console.log('setting up sensors'); async.eachSeries([{chipIndex: 1, sensors: sensors}, {chipIndex: 2, sensors: sensors}], this._SetupSensors.bind(this), function(err) { callback(err); }); } Driver.prototype._SetupSensors = function(params, callback) { this._asyncCallback = callback; this._asyncTimeout = setTimeout(function() { console.log('rx Timeout'); callback('timed out'); }, PROTOCOL_TIMEOUT); this._sensors = params.sensors; var chipIndex = params.chipIndex; var data = new BitArray(); for (var i=(chipIndex*2 - 2); i<(chipIndex*2); i++) { var sensor = this._sensors[i]; if (sensor != null) { if (sensor.type === SENSOR_TYPE.NXT.ULTRASONIC.CONT) { data.addBits(0, 0, 8, SENSOR_TYPE.I2C); data.addBits(0, 0, 8, 10 /*US_I2C_SPEED*/); data.addBits(0, 0, 3, 0); // # devices - 1 data.addBits(0, 0, 7, 1/*LEGO_US_I2C_ADDR >> 1*/); data.addBits(0, 0, 2, 0x03 /* sensor settings (BIT_I2C_MID | BIT_I2C_SAME)*/); data.addBits(0, 0, 4, 1); // I2C WRITE data.addBits(0, 0, 4, 1); // I2C READ data.addBits(0, 0, 8, 0x42 /*LEGO_US_I2C_DATA_REG*/); } else if ((sensor.type === SENSOR_TYPE.I2C) || (sensor.type === SENSOR_TYPE.I2C_9V)) { data.addBits(0, 0, 8, sensor.type); data.addBits(0, 0, 8, 0 /*I2C_SPEED*/); data.addBits(0, 0, 3, 0); // # devices - 1, there is never more than one device by I2C port. data.addBits(0, 0, 7, 1 /* I2C_ADDR >> 1*/); data.addBits(0, 0, 2, 0x02 /* sensor settings for IRLink PF function*/); } else if (sensor.type === SENSOR_TYPE.DEXTER.IMU.ACC) { data.addBits(0, 0, 8, SENSOR_TYPE.I2C); data.addBits(0, 0, 8, 0 /*I2C_SPEED*/); data.addBits(0, 0, 3, 0); // # devices - 1 data.addBits(0, 0, 7, 0x3A >> 1 /* DIMU_ACC_I2C_ADDR >> 1*/); data.addBits(0, 0, 2, 0x00 /* sensor settings */); } else { data.addBits(0, 0, 8, sensor.type); } } else { data.addBits(0, 0, 8, 0); } } var buf = new Buffer(data.getArray()); console.log('out going setup sensors' + buf.toJSON()); this._currentChip = chipIndex; this._write(chipIndex, PROTOCOL.CONFIGURE_SENSORS, data.getArray()); } Driver.prototype._write = function(chipIndex, command, data) { var packet = new Buffer(data.length + 4); // clear the read buffer before writing... this._serialPort.flush(function(error) { if(error) { callback(error); return; } // + 1 for the command byte var dataLength = data.length + 1; // the checksum is the sum of all the bytes in the entire packet EXCEPT the checksum var checksum = chipIndex + command + dataLength + Array.prototype.reduce.call(data, function(a, b, index) { packet[index + 4] = b & 0xFF return a + (b & 0xFF) }, 0); packet[0] = chipIndex & 0xFF packet[1] = checksum & 0xFF packet[2] = dataLength packet[3] = command & 0xFF var buf = new Buffer(packet); this._serialPort.write(new Buffer(packet), function(err, results) { if (err && this._asynCallback) this._asyncCallback('write error'); }); }.bind(this)); } Driver.prototype._addByte = function(byte) { if(!this._reading) { if(this._readChecksum === null) { return this._recordExpectedChecksum(byte) } if(this._readLength === null) { return this._recordExpectedReadLength(byte) } } this._readChecksumData += byte this._readBuffer[this._readBufferOffset] = byte this._readBufferOffset++ this._checkResponseIfFinished(); } Driver.prototype._recordExpectedChecksum = function(byte) { this._readChecksum = byte } Driver.prototype._recordExpectedReadLength = function(byte) { this._readLength = byte; this._readChecksumData = this._readLength; this._readBuffer = new Buffer(this._readLength); this._readBufferOffset = 0; this._reading = true this._readTimeout = setTimeout(function() { if(this._readBuffer[0]) { if (this._asynCallback) this._asyncCallback('read timeout'); } else { if (this._asynCallback) this._asyncCallback('read timeout'); } this._resetReadFields(); }.bind(this), READ_TIMEOUT); } Driver.prototype._checkResponseIfFinished = function() { if(this._readBufferOffset != this._readLength) { return; } // done reading response clearTimeout(this._readTimeout) var error = undefined; if((this._readChecksumData & 0xFF) != this._readChecksum) { if (this._asyncCallback) this._asyncCallback('checksum failed'); } // this is where the reponse from the Brickpi is handled. if (this._readBuffer[0] === PROTOCOL.SET_COMMUNICATION_TIMEOUT) { if (this._asyncTimeout) clearTimeout(this._asyncTimeout); this._asyncCallback(null); } if (this._readBuffer[0] === PROTOCOL.READ_SENSOR_VALUES) { var incoming = new BitArray(this._readBuffer); var encoderLengths = [ incoming.getBits(1, 0, 5), incoming.getBits(1, 0, 5), ] for(var i = 0; i < 2; i++) { var value = incoming.getBits(1, 0, encoderLengths[i]); var position = value; position = (position/2).toFixed(0); if(value & 0x01) { position *= -1; } if (this._motors) { if (this._motors[this._currentChip*2 + i - 2]) { // motor is defined. update position this._motors[this._currentChip*2 + i - 2]._update(position); } } } for (var i = 0; i < 2; i++) { // read sensor values. var sensor = this._sensors[this._currentChip*2 + i - 2]; if (sensor) { //// var buf = new Buffer(incoming.getArray()); console.log(sensor.name); console.log('incoming: ' + buf.toJSON()); ///// var value; if (sensor.type === SENSOR_TYPE.NXT.TOUCH) { value = incoming.getBits(1, 0, 1); } else if (sensor.type === SENSOR_TYPE.NXT.ULTRASONIC.CONT) { var port = incoming.getBits(1, 0, 1); value = incoming.getBits(1, 0, 8); } else if (sensor.type === SENSOR_TYPE.DEXTER.IMU.ACC) { var port = incoming.getBits(1, 0, 1); value = incoming.getBits(1, 0, 8); value = (value > 128) ? ((value-256)/64) : (value/64); var newValue = sensor.getValue(); if (sensor.currentAxis === 0x6) { sensor.currentAxis = 0x07; // set it up so that next cycle, the y is read. newValue.x = value; value = newValue; } else if (sensor.currentAxis === 0x7) { sensor.currentAxis = 0x08; // set it up so that next cycle, the z is read. newValue.y = value; value = newValue; } else { sensor.currentAxis = 0x06; // set it up so that next cycle, the x is read. newValue.z = value; value = newValue; } } else if (sensor.type === SENSOR_TYPE.NXT.ULTRASONIC.SS) { // i don't know how _SS works. Need to implement _CONT value = incoming.getBits(1, 0, 8); } else if (sensor.type === SENSOR_TYPE.NXT.COLOR.FULL) { value = {blank: incoming.getBits(1, 0, 10), red: incoming.getBits(1, 0, 10), green: incoming.getBits(1, 0, 10), blue: incoming.getBits(1, 0, 10)}; } else if ((sensor.type === SENSOR_TYPE.EV3.COLOUR.M3) || (sensor.type === SENSOR_TYPE.EV3.GYRO.M3) || (sensor.type === SENSOR_TYPE.EV3.INFRARED.M2)) { value = incoming.getBits(1, 0, 32); } else { // COLOR.RED, etc.. value = incoming.getBits(1, 0, 10); } sensor._update(value); } else { incoming.getBits(1, 0, 10); } } if (this._asyncTimeout) clearTimeout(this._asyncTimeout); this._asyncCallback(null); } if (this._readBuffer[0] === PROTOCOL.CONFIGURE_SENSORS) { if (this._asyncTimeout) clearTimeout(this._asyncTimeout); this._asyncCallback(null); } this._resetReadFields(); } Driver.prototype._resetReadFields = function() { this._reading = false; this._readChecksum = null; this._readLength = null; this._readBuffer = null; } Driver.prototype.close = function(callback) { this._serialPort.close(function() { if (callback) callback(); }); }