hybridgroup/cylon-bean

View on GitHub
lib/adaptor.js

Summary

Maintainability
C
1 day
Test Coverage
"use strict";

var Cylon = require("cylon");
var SerialPort = require("bean-serial").SerialPort;
var Firmata = require("firmata");
var Bean = require("ble-bean");

var Adaptor = module.exports = function Adaptor(opts) {
  Adaptor.__super__.constructor.apply(this, arguments);
  opts = opts || {};
  this.beanName = opts.beanName;
};

var PINS = {
  0: 6, // currently
  1: 9, // unavilable?
  2: 10,
  3: 11,
  4: 12,
  5: 13
};

var PWM_PINS = {
  0: 6, // currently
  1: 9, // unavilable?
  2: 10,
  3: 11
};

var ANALOG_PINS = {
  A0: 4,
  A1: 5,
  0: 4,
  1: 5
};

Cylon.Utils.subclass(Adaptor, Cylon.Adaptor);

Adaptor.prototype.commands = [
  "pinMode",
  "digitalRead",
  "digitalWrite",
  "analogRead",
  "analogWrite",
  "pwmWrite",
  "servoWrite",
  "i2cConfig",
  "i2cWrite",
  "i2cRead",
  "setColor",
  "getAcceleration",
  "getTemperature"
];

Adaptor.prototype.connect = function(callback) {
  var self = this;

  Bean.discover(function(bean) {
    self.connectedBean = bean;

    if (self.beanName &&
        self.beanName !== bean._peripheral.advertisement.localName) {
      return;
    }

    bean.on("accell", function(x, y, z, valid) {
      self.emit("accel", x, y, z, valid);
    });

    bean.on("temp", function(temp, valid) {
      self.emit("temp", temp, valid);
    });

    bean.connectAndSetup(function() {
      // set color to the built in LED so we know we're connected
      self.setLed(255, 255, 0);

      bean.unGate(function() {
        self.serialPort = new SerialPort(self.connectedBean);

        self.board = new Firmata.Board(self.serialPort,
           {skipHandshake: true, samplingInterval: 250},
           function(err, ok) {
             if (err) {
               Cylon.Logger.debug("Error connect to virtual serial port", err);
             }
             Cylon.Logger.debug("Connected to virtual serial port", ok);
             callback();
           }
         );
      });
    });
  });
};

Adaptor.prototype.disconnect = function(callback) {
  var bean = this.connectedBean;
  if (bean) {
    bean.setColor(new Buffer([0x0, 0x0, 0x0]), function() {});
    setTimeout(bean.disconnect.bind(bean, callback), 2000);
  } else {
    callback();
  }
};

/**
 * Reads a value from a digital pin
 *
 * @param {Number} pinNum the number of the pin to use
 * @param {Function} callback triggered when the value has been read from the
 * pin
 * @return {void}
 * @publish
 */
Adaptor.prototype.digitalRead = function(pinNum, callback) {
  var pin;
  pin = this._translatePin(pinNum);
  this.pinMode(pin, "input");

  this.board.digitalRead(pin, function(value) {
    this.respond("digitalRead", callback, null, value, pin);
  }.bind(this));
};

/**
 * Writes a value to a digital pin
 *
 * @param {Number} pinNum the number of the pin to use
 * @param {Number} value the value to write to the pin
 * @param {Function} callback function to be invoked when done
 * @return {void}
 * @publish
 */
Adaptor.prototype.digitalWrite = function(pinNum, value, callback) {
  var pin;
  pin = this._translatePin(pinNum);
  this.pinMode(pin, "output");
  this.board.digitalWrite(pin, value);
  this.respond("digitalWrite", callback, null, value, pin);
};

/**
 * Reads a value from an analog pin
 *
 * @param {Number} pinNum the number of the pin to use
 * @param {Function} callback triggered when the value has been read from the
 * pin
 * @return {void}
 * @publish
 */
Adaptor.prototype.analogRead = function(pinNum, callback) {
  var pin;
  pin = this._translateAnalogPin(pinNum);
  this.board.analogRead(pin, function(value) {
    this.respond("analogRead", callback, null, value, pin);
  }.bind(this));
};

/**
 * Writes a value to an analog pin
 *
 * @param {Number} pinNum the number of the pin to use
 * @param {Number} value the value to write to the pin
 * @param {Function} callback function to be invoked when done
 * @return {void}
 * @publish
 */
Adaptor.prototype.analogWrite = function(pinNum, value, callback) {
  var pin;
  pin = this._translateAnalogPin(pinNum);
  value = (value).toScale(0, 255);
  this.pinMode(this.board.analogPins[pin], "analog");
  this.board.analogWrite(this.board.analogPins[pin], value);
  this.respond("analogWrite", callback, null, value, pin);
};

/**
 * Writes a PWM value to a pin
 *
 * @param {Number} pinNum the number of the pin to use
 * @param {Number} value the value to write to the pin
 * @param {Function} callback function to be invoked when done
 * @return {void}
 * @publish
 */
Adaptor.prototype.pwmWrite = function(pinNum, value, callback) {
  var pin;
  pin = this._translatePwmPin(pinNum);
  value = (value).toScale(0, 255);
  this.pinMode(pin, "pwm");
  this.board.analogWrite(pin, value);
  this.respond("pwmWrite", callback, null, value, pin);
};

/**
 * Writes a servo value to a pin
 *
 * @param {Number} pinNum the number of the pin to use
 * @param {Number} value the value to write to the pin
 * @param {Function} callback function to be invoked when done
 * @return {void}
 * @publish
 */
Adaptor.prototype.servoWrite = function(pinNum, value, callback) {
  var pin;
  pin = this._translatePwmPin(pinNum);
  value = (value).toScale(0, 180);
  this.pinMode(pin, "servo");
  this.board.servoWrite(pin, value);
  this.respond("servoWrite", callback, null, value, pin);
};

/**
 * Writes an I2C value to the board.
 *
 * @param {Number} address I2C address to write to
 * @param {Number} cmd I2C command to write
 * @param {Array} buff buffered data to write
 * @param {Function} callback function to be invoked when done
 * @return {void}
 * @publish
 */
Adaptor.prototype.i2cWrite = function(address, cmd, buff, callback) {
  if (!this.i2cReady) { this.i2cConfig(2000); }
  cmd = (Array.isArray(cmd)) ? cmd : [cmd];
  this.board.sendI2CWriteRequest(address, cmd.concat(buff));
  this.respond("i2cWrite", callback);
};

/**
 * Reads an I2C value from the board.
 *
 * @param {Number} address I2C address to write to
 * @param {Number} cmd I2C command to write
 * @param {Number} length amount of data to read
 * @param {Function} callback function to be invoked when done
 * @return {void}
 * @publish
 */
Adaptor.prototype.i2cRead = function(address, cmd, length, callback) {
  if (!this.i2cReady) {
    this.i2cConfig(2000);
  }

  // TODO: decouple read and write operations here...
  if (cmd) {
    cmd = (Array.isArray(cmd)) ? cmd : [cmd];
    this.board.sendI2CWriteRequest(address, cmd);
  }

  this.board.sendI2CReadRequest(address, length, function(data) {
    var err = null;

    if (data.name === "Error") {
      err = data;
      data = null;
    }

    this.respond("i2cRead", callback, err, data);
  }.bind(this));
};

Adaptor.prototype.pinMode = function(pin, mode) {
  this.board.pinMode(pin, this._convertPinMode(mode));
};

Adaptor.prototype.i2cConfig = function(delay) {
  this.board.sendI2CConfig(delay);
  this.i2cReady = true;
};

Adaptor.prototype._convertPinMode = function(mode) {
  return this.board.MODES[mode.toUpperCase()] || this.board.MODES.INPUT;
};

/**
 * Sets the built-in LED to a specific color
 *
 * @param {Number} r the red value to set
 * @param {Number} g the green value to set
 * @param {Number} b the blue value to set
 * @return {void}
 * @publish
 */
Adaptor.prototype.setLed = function(r, g, b) {
  this.connectedBean.setColor(new Buffer([r, g, b]), function(err) {
    if (err) {
      Cylon.Logger.debug("setColor error", err);
    }
  });
};

/**
 * Reads the built-in accelerometer once
 *
 * @return {void}
 * @publish
 */
Adaptor.prototype.getAcceleration = function() {
  this.connectedBean.requestAccell();
};

/**
 * Reads the built-in thermometer once
 *
 * @return {void}
 * @publish
 */
Adaptor.prototype.getTemperature = function() {
  this.connectedBean.requestTemp();
};

Adaptor.prototype._translatePin = function(pinNum) {
  return PINS[pinNum.toString()];
};

Adaptor.prototype._translatePwmPin = function(pinNum) {
  return PWM_PINS[pinNum.toString()];
};

Adaptor.prototype._translateAnalogPin = function(pinNum) {
  return ANALOG_PINS[pinNum.toString()];
};