johnny-five
Version:
Firmata based Arduino Programming Framework.
196 lines (161 loc) • 4.06 kB
JavaScript
var Board = require("../lib/board.js"),
Descriptor = require("descriptor"),
__ = require("../lib/fn.js"),
events = require("events"),
util = require("util");
var priv = new WeakMap(),
modes, value;
modes = {
INPUT: 0x00,
OUTPUT: 0x01,
ANALOG: 0x02,
PWM: 0x03,
SERVO: 0x04
};
value = {
low: 0,
high: 1
};
/**
* Pin
* @constructor
*
* @description Direct Pin access objects
*
* @param {Object} opts Options: pin, freq, range
*/
function Pin( opts ) {
var isPin, addr, type, highLow;
if ( !(this instanceof Pin) ) {
return new Pin( opts );
}
// Initialize a Device instance on a Board
Board.Device.call(
this, opts = Board.options( opts )
);
opts.addr = opts.addr || opts.pin;
// Create a private side table
priv.set(this, {
mode: this.as || 0x00,
last: null
});
isPin = typeof opts !== "object";
addr = isPin ? opts : opts.addr;
type = opts.type || (typeof addr === "number" ? "digital" : "analog");
// Create read-only "addr(address)" property
Object.defineProperties( this, {
type: new Descriptor( type ),
addr: new Descriptor( addr, "!writable" )
});
this.firmata.pinMode(
this.addr, priv.get(this).mode
);
highLow = function( state ) {
return function( data ) {
var privs, isNot, emit;
privs = priv.get(this);
isNot = state ? "low" : "high";
emit = state ? "high" : "low";
if ( privs.mode === modes.INPUT ) {
if ( privs.last === null ) {
privs.last = isNot;
}
if ( data === state && privs.last === isNot ) {
privs.last = emit;
this.emit( emit );
}
}
}.bind(this);
}.bind(this);
// Debounced for noise reduction: more accurately
// detect HIGH state.
this.firmata[ type + "Read" ](
this.addr, __.debounce( highLow(1), 50 )
);
// No debounce to read the constant stream
// (very noisy, only care about 0)
this.firmata[ type + "Read" ](
this.addr, highLow(0)
);
}
util.inherits( Pin, events.EventEmitter );
Pin.write = function( pin, val ) {
// Set the correct mode (OUTPUT)
// This will only set if it needs to be set, otherwise a no-op
pin.mode( modes.OUTPUT );
// Create the correct type of write command
pin.firmata[ pin.type + "Write" ]( pin.addr, val );
};
Pin.read = function( pin, callback ) {
// Set the correct mode (INPUT)
// This will only set if it needs to be set, otherwise a no-op
pin.mode( modes.INPUT );
pin.firmata[ pin.type + "Read" ]( pin.addr, function() {
callback.apply( pin, arguments );
});
};
// Create readonly mode constants
Object.keys( modes ).forEach(function( mode ) {
Object.defineProperty( Pin, mode, {
value: modes[ mode ]
});
});
/**
* high Write high/1 to the pin
* @return {Pin}
*/
/**
* low Write low/0 to the pin
* @return {Pin}
*/
[ "high", "low" ].forEach(function( state ) {
Pin.prototype[ state ] = function() {
Pin.write( this, value[ state ] );
this.emit( state );
return this;
};
});
/**
* read Read from the pin, value is passed to callback continuation
* @return {Pin}
*/
/**
* write Write to a pin
* @return {Pin}
*/
[ "read", "write" ].forEach(function( state ) {
Pin.prototype[ state ] = function( valOrCallback ) {
Pin[ state ]( this, valOrCallback );
return this;
};
});
/**
* mode Set or Get the mode
*
* @param {Hex|String} [mode] Set the IO or command mode for this pin
* INPUT: 0x00
* OUTPUT: 0x01
* ANALOG: 0x02
* PWM: 0x03
* SERVO: 0x04
*
* @return {Pin}
*
* @param {undefined} Get the mode for this pin
* @return {Hex}
*/
Pin.prototype.mode = function( mode ) {
if ( mode && priv.get(this).mode !== mode ) {
// Allows setting the mode with strings, eg "INPUT", "OUTPUT"
if ( typeof mode !== "number" && modes[ mode ] ) {
mode = modes[ mode ];
}
this.firmata.pinMode(
this.addr,
priv.get(this).mode = mode
);
return this;
}
return priv.get(this).mode;
};
module.exports = Pin;