function Accelerometer(opts) {
if (!(this instanceof Accelerometer)) {
return new Accelerometer(opts);
}
var controller = null;
var state = {
enabled: true,
x: {
value: 0,
previous: 0,
stash: [],
orientation: null,
inclination: null,
acceleration: null,
calibration: []
},
y: {
value: 0,
previous: 0,
stash: [],
orientation: null,
inclination: null,
acceleration: null,
calibration: []
},
z: {
value: 0,
previous: 0,
stash: [],
orientation: null,
inclination: null,
acceleration: null,
calibration: []
}
};
Board.Component.call(
this, opts = Board.Options(opts)
);
if (opts.controller && typeof opts.controller === "string") {
controller = Controllers[opts.controller.toUpperCase()];
} else {
controller = opts.controller;
}
if (controller == null) {
controller = Controllers.ANALOG;
}
Board.Controller.call(this, controller, opts);
if (!this.toGravity) {
this.toGravity = opts.toGravity || function(raw) {
return raw;
};
}
if (!this.enabledChanged) {
this.enabledChanged = function() {};
}
priv.set(this, state);
/* istanbul ignore else */
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
var isChange = false;
if (!state.enabled) {
return;
}
Object.keys(data).forEach(function(axis) {
var value = data[axis];
var sensor = state[axis];
if (opts.autoCalibrate && sensor.calibration.length < calibrationSize) {
var axisIndex = axes.indexOf(axis);
sensor.calibration.push(value);
if (!Array.isArray(state.zeroV)) {
state.zeroV = [];
}
state.zeroV[axisIndex] = sum(sensor.calibration) / sensor.calibration.length;
if (axis === aZ) {
state.zeroV[axisIndex] -= state.sensitivity;
}
}
// The first run needs to prime the "stash"
// of data values.
if (sensor.stash.length === 0) {
for (var i = 0; i < 5; i++) {
sensor.stash[i] = value;
}
}
sensor.previous = sensor.value;
sensor.stash.shift();
sensor.stash.push(value);
sensor.value = (sum(sensor.stash) / 5) | 0;
if (this.acceleration !== sensor.acceleration) {
sensor.acceleration = this.acceleration;
isChange = true;
this.emit("acceleration", sensor.acceleration);
}
if (this.orientation !== sensor.orientation) {
sensor.orientation = this.orientation;
isChange = true;
this.emit("orientation", sensor.orientation);
}
if (this.inclination !== sensor.inclination) {
sensor.inclination = this.inclination;
isChange = true;
this.emit("inclination", sensor.inclination);
}
}, this);
this.emit("data", {
x: state.x.value,
y: state.y.value,
z: state.z.value
});
if (isChange) {
this.emit("change", {
x: this.x,
y: this.y,
z: this.z
});
}
}.bind(this));
}
Object.defineProperties(this, {
hasAxis: {
writable: true,
value: function(axis) {
/* istanbul ignore next */
return state[axis] ? state[axis].stash.length > 0 : false;
}
},
enable: {
value: function() {
state.enabled = true;
this.enabledChanged(true);
return this;
}
},
disable: {
value: function() {
state.enabled = false;
this.enabledChanged(false);
return this;
}
},
zeroV: {
get: function() {
return state.zeroV;
}
},
/**
* [read-only] Calculated pitch value
* @property pitch
* @type Number
*/
pitch: {
get: function() {
var x = this.x;
var y = this.y;
var z = this.z;
var r ...
n/a
function Altimeter(opts) {
if (!(this instanceof Altimeter)) {
return new Altimeter(opts);
}
var controller = null;
var freq;
var last = null;
var raw = null;
var state = {};
Board.Component.call(
this, opts = Board.Options(opts)
);
freq = opts.freq || 25;
if (opts.controller && typeof opts.controller === "string") {
controller = Controllers[opts.controller.toUpperCase()];
} else {
controller = opts.controller;
}
if (controller == null) {
throw new Error("Altimeter expects a valid controller");
}
priv.set(this, state);
Board.Controller.call(this, controller, opts);
if (!this.toMeters) {
this.toMeters = opts.toMeters || function(x) {
return x;
};
}
var descriptors = {
meters: {
get: function() {
return this.toMeters(raw);
}
},
feet: {
get: function() {
return Fn.toFixed(this.meters * 3.28084, 2);
}
}
};
// Convenience aliases
descriptors.m = descriptors.meters;
descriptors.ft = descriptors.feet;
Object.defineProperties(this, descriptors);
/* istanbul ignore else */
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
raw = data;
});
}
setInterval(function() {
if (raw == null) {
return;
}
var data = {};
data.m = data.meters = this.meters;
data.ft = data.feet = this.feet;
this.emit("data", data);
/* istanbul ignore else */
if (this.meters !== last) {
last = this.meters;
this.emit("change", data);
}
}.bind(this), freq);
}
n/a
Analog = function (opts) { return new module.exports.Sensor(opts); }
n/a
function Animation(target) { // Necessary to avoid loading temporal unless necessary if (!temporal) { temporal = require("temporal"); } if (!(this instanceof Animation)) { return new Animation(target); } Animation.Segment.call(this); this.defaultTarget = target; }
n/a
Animation.TemporalFallback = function (animation) { this.interval = setInterval(function() { animation.loopFunction({ calledAt: Date.now() }); }, animation.rate); }
n/a
function Barometer(opts) { if (!(this instanceof Barometer)) { return new Barometer(opts); } var controller = null; var last = null; var raw = null; Board.Component.call( this, opts = Board.Options(opts) ); var freq = opts.freq || 25; if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { // controller = Controllers["ANALOG"]; throw new Error("Missing Barometer controller"); } Board.Controller.call(this, controller, opts); if (!this.toPressure) { this.toPressure = opts.toPressure || function(raw) { return raw; }; } if (typeof this.initialize === "function") { this.initialize(opts, function(data) { raw = data; }); } Object.defineProperties(this, { pressure: { get: function() { return toFixed(this.toPressure(raw), 4); } } }); setInterval(function() { if (raw === null) { return; } var data = { pressure: this.pressure }; this.emit("data", data); if (this.pressure !== last) { last = this.pressure; this.emit("change", data); } }.bind(this), freq); }
n/a
function Board(opts) {
if (!(this instanceof Board)) {
return new Board(opts);
}
// Ensure opts is an object
opts = opts || {};
// Used to define the board instance's own
// properties in the REPL's scope.
var replContext = {};
// It's feasible that an IO-Plugin may emit
// "connect" and "ready" events out of order.
// This is used to enforce the order, by
// postponing the "ready" event if the IO-Plugin
// hasn't emitted a "connect" event. Once
// the "connect" event is emitted, the
// postponement is lifted and the board may
// proceed with emitting the events in the
// correct order.
var isPostponed = false;
// Initialize this Board instance with
// param specified properties.
Object.assign(this, opts);
this.timer = null;
this.isConnected = false;
// Easily track state of hardware
this.isReady = false;
// Initialize instance property to reference io board
this.io = this.io || null;
// Registry of components
this.register = [];
// Pins, Addr (alt Pin name), Addresses
this.occupied = [];
// Registry of drivers by address (i.e. I2C Controllers)
this.Drivers = {};
// Identify for connect hardware cache
if (!this.id) {
this.id = Fn.uid();
}
// If no debug flag, default to true
if (typeof this.debug === UNDEFINED) {
this.debug = true;
}
// If no repl flag, default to true
if (typeof this.repl === UNDEFINED) {
this.repl = true;
}
// If no sigint flag, default to true
if (typeof this.sigint === UNDEFINED) {
this.sigint = true;
}
// Specially processed pin capabilities object
// assigned when physical board has reported
// "ready" via Firmata or IO-Plugin.
this.pins = null;
// Create a Repl instance and store as
// instance property of this io/board.
// This will reduce the amount of boilerplate
// code required to _always_ have a Repl
// session available.
//
// If a sesssion exists, use it
// (instead of creating a new session)
//
/* istanbul ignore if */
if (this.repl) {
/* istanbul ignore if */
if (Repl.ref) {
/* istanbul ignore next */
replContext[this.id] = this;
/* istanbul ignore next */
Repl.ref.on("ready", function() {
/* istanbul ignore next */
Repl.ref.inject(replContext);
});
/* istanbul ignore next */
this.repl = Repl.ref;
} else {
replContext[this.id] = replContext.board = this;
this.repl = new Repl(replContext);
}
}
if (opts.io) {
// If you already have a connected io instance
this.io = opts.io;
this.isReady = opts.io.isReady;
this.transport = this.io.transport || null;
this.port = this.io.name;
this.pins = Board.Pins(this);
} else {
if (this.port && opts.port) {
Serial.connect.call(this, this.port, finalizeAndBroadcast);
} else {
Serial.detect.call(this, function(path) {
Serial.connect.call(this, path, finalizeAndBroadcast);
});
}
}
// Either an IO instance was provided or isOnBoard is true
if (!opts.port && this.io !== null) {
/* istanbul ignore next */
this.info("Available", chalk.grey(this.io.name || "unknown"));
["connect", "ready"].forEach(function(type) {
this.io.once(type, function() {
// Since connection and readiness happen asynchronously,
// it's actually possible for Johnny-Five to receive the
// events out of order and that should be ok.
if (type === "ready" && !this.isConnected) {
isPostponed = true;
} else {
// Will emit the "connect" and "ready" events
// if received in order. If out of order, this
// will only emit the "connect" event. The
// "ready" event will be handled in the next
// condition's consequent.
finalizeAndBroadcast.call(this, null, type, this.io);
}
if (type === "connect" && isPostponed) {
finalizeAndBroadcast.call(this, null, "ready", this.io);
}
}.bind(this));
if (this.io.isReady) { ...
...
## Hello Johnny
The ubiquitous "Hello World" program of the microcontroller and SoC world is "blink an LED". The following code
demonstrates how this is done using the Johnny-Five framework.
```javascript
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
...
Board.Component = function (opts, componentOpts) {
if (typeof opts === UNDEFINED) {
opts = {};
}
if (typeof componentOpts === UNDEFINED) {
componentOpts = {};
}
// Board specific properties
this.board = Board.mount(opts);
this.io = this.board.io;
// Component/Module instance properties
this.id = opts.id || Board.uid();
this.custom = opts.custom || {};
var originalPins;
if (typeof opts.pin === "number" || typeof opts.pin === "string") {
originalPins = [opts.pin];
} else {
if (Array.isArray(opts.pins)) {
originalPins = opts.pins.slice();
} else {
if (typeof opts.pins === "object" && opts.pins !== null) {
var pinset = opts.pins || opts.pin;
originalPins = [];
for (var p in pinset) {
originalPins.push(pinset[p]);
}
}
}
}
if (opts.controller) {
if (typeof opts.controller === "string") {
opts.controller = opts.controller.replace(/-/g, "");
}
if (!Expander) {
Expander = require("./expander");
}
if (Expander.hasController(opts.controller)) {
componentOpts = {
normalizePin: false,
requestPin: false,
};
}
}
componentOpts = Board.Component.initialization(componentOpts);
if (componentOpts.normalizePin) {
opts = Board.Pins.normalize(opts, this.board);
}
// var requesting = [];
if (typeof opts.pins !== UNDEFINED) {
this.pins = opts.pins || [];
// if (Array.isArray(this.pins)) {
// requesting = requesting.concat(
// this.pins.map(function(pin) {
// return {
// value: pin,
// type: "pin"
// };
// })
// );
// } else {
// requesting = requesting.concat(
// Object.keys(this.pins).map(function(key) {
// return {
// value: this.pins[key],
// type: "pin"
// };
// }, this)
// );
// }
}
if (typeof opts.pin !== UNDEFINED) {
this.pin = opts.pin;
// requesting.push({
// value: this.pin,
// type: "pin"
// });
}
// TODO: Figure out what is using this
/* istanbul ignore if */
if (typeof opts.emitter !== UNDEFINED) {
/* istanbul ignore next */
this.emitter = opts.emitter;
// requesting.push({
// value: this.emitter,
// type: "emitter"
// });
}
if (typeof opts.address !== UNDEFINED) {
this.address = opts.address;
// requesting.forEach(function(request) {
// request.address = this.address;
// }, this);
}
if (typeof opts.controller !== UNDEFINED) {
this.controller = opts.controller;
// requesting.forEach(function(request) {
// request.controller = this.controller;
// }, this);
}
// TODO: Figure out what is using this
/* istanbul ignore if */
if (typeof opts.bus !== UNDEFINED) {
/* istanbul ignore next */
this.bus = opts.bus;
// requesting.forEach(function(request) {
// request.bus = this.bus;
// }, this);
}
// if (componentOpts.requestPin) {
// // With the pins being requested for use by this component,
// // compare with the list of pins that are already known to be
// // in use by other components. If any are known to be in use,
// // produce a warning for the user.
// requesting.forEach(function(request, index) {
// var hasController = typeof request.controller !== UNDEFINED;
// var hasAddress = typeof request.address !== UNDEFINED;
// var isOccupied = false;
// var message = "";
// request.value = originalPins[index];
// if (this.board.occupied.length) {
// isOccupied = this.board.occupied.some(function(occupied) {
// var isPinOccupied = request.value === occupied.value && request.type === occupied.type;
// if (typeof occupied.controller !== UNDEFINED) {
// if (hasController) {
// return isPinOccupied && (request.controller === occupied.controller);
// }
// return false;
// }
// if (typeof occupied.addre ...
n/a
function Pins(board) { if (!(this instanceof Pins)) { return new Pins(board); } var io = board.io; var pins = io.pins.slice(); var length = pins.length; var type = pinsToType[length] || "OTHER"; board.type = type; // Copy pin data to index for (var i = 0; i < length; i++) { this[i] = pins[i]; } Object.defineProperties(this, { type: { value: type }, length: { value: length } }); // If an IO Plugin or Expander defines // these, override the default [ "isInput", "isOutput", "isAnalog", "isPwm", "isServo", ].forEach(function(isType) { if (io[isType]) { this[isType] = io[isType]; } }, this); }
n/a
Board.range = function (lower, upper, tick) { if (arguments.length === 1) { upper = lower - 1; lower = 0; } lower = lower || 0; upper = upper || 0; tick = tick || 1; var len = Math.max(Math.ceil((upper - lower) / tick), 0), idx = 0, range = []; while (idx <= len) { range[idx++] = lower; lower += tick; } return range; }
n/a
function Boards(opts) {
if (!(this instanceof Boards)) {
return new Boards(opts);
}
var ports;
// new Boards([ ...Array of board opts ])
if (Array.isArray(opts)) {
ports = opts.slice();
opts = {
ports: ports,
};
}
// new Boards({ ports: [ ...Array of board opts ], .... })
/* istanbul ignore else */
if (!Array.isArray(opts) && typeof opts === "object" && opts.ports !== undefined) {
ports = opts.ports;
}
// new Boards(non-Array?)
// new Boards({ ports: non-Array? })
/* istanbul ignore if */
if (!Array.isArray(ports)) {
throw new Error("Expected ports to be an array");
}
if (typeof opts.debug === UNDEFINED) {
opts.debug = true;
}
if (typeof opts.repl === UNDEFINED) {
opts.repl = true;
}
var initialized = {};
var noRepl = ports.some(function(port) { return port.repl === false; });
var noDebug = ports.some(function(port) { return port.debug === false; });
this.length = ports.length;
this.debug = opts.debug;
this.repl = opts.repl;
// If any of the port definitions have
// explicitly shut off debug output, bubble up
// to the Boards instance
/* istanbul ignore else */
if (noDebug) {
this.debug = false;
}
// If any of the port definitions have
// explicitly shut off the repl, bubble up
// to the Boards instance
/* istanbul ignore else */
if (noRepl) {
this.repl = false;
}
var expecteds = ports.map(function(port, index) {
var portOpts;
if (typeof port === "string") {
portOpts = {};
// If the string matches a known valid port
// name pattern, then assume this is what
// the user code intended.
if (rport.test(port)) {
portOpts.port = port;
} else {
// Otherwise they expect Johnny-Five to figure
// out what ports to use and intended this
// value to be used an id
portOpts.id = port;
}
} else {
portOpts = port;
}
// Shut off per-board repl instance creation
portOpts.repl = false;
this[index] = initialized[portOpts.id] = new Board(portOpts);
// "error" event is not async, register immediately
this[index].on("error", function(error) {
this.emit("error", error);
}.bind(this));
return new Promise(function(resolve) {
this[index].on("ready", function() {
resolve(initialized[portOpts.id]);
});
}.bind(this));
}, this);
Promise.all(expecteds).then(function(boards) {
Object.assign(this, boards);
this.each(function(board) {
board.info("Board ID: ", chalk.green(board.id));
});
// If the Boards instance requires a REPL,
// make sure it's created before calling "ready"
if (this.repl) {
this.repl = new Repl(
Object.assign({}, initialized, {
board: this
})
);
this.repl.initialize(function() {
this.emit("ready", initialized);
}.bind(this));
} else {
// Otherwise, call ready immediately
this.emit("ready", initialized);
}
}.bind(this));
}
n/a
function Button(opts) {
if (!(this instanceof Button)) {
return new Button(opts);
}
var pinValue;
var raw;
var invert = false;
var downValue = 1;
var upValue = 0;
var controller = null;
var state = {
interval: null,
last: null
};
// Create a debounce boundary on event triggers
// this avoids button events firing on
// press noise and false positives
var trigger = Fn.debounce(function(key) {
aliases[key].forEach(function(type) {
this.emit(type);
}, this);
}, 7);
pinValue = typeof opts === "object" ? opts.pin : opts;
Board.Component.call(
this, opts = Board.Options(opts)
);
opts.pinValue = pinValue;
if (opts.controller && typeof opts.controller === "string") {
controller = Controllers[opts.controller.toUpperCase()];
} else {
controller = opts.controller;
}
if (controller == null) {
controller = Controllers.DEFAULT;
}
Board.Controller.call(this, controller, opts);
// `holdtime` is used by an interval to determine
// if the button has been released within a specified
// time frame, in milliseconds.
this.holdtime = opts.holdtime || 500;
// `opts.isPullup` is included as part of an effort to
// phase out "isFoo" options properties
this.pullup = opts.pullup || opts.isPullup || false;
this.pulldown = opts.pulldown || opts.isPulldown || false;
// Turns out some button circuits will send
// 0 for up and 1 for down, and some the inverse,
// so we can invert our function with this option.
// Default to invert in pullup mode, but use opts.invert
// if explicitly defined (even if false)
invert = typeof opts.invert !== "undefined" ?
opts.invert : (this.pullup || false);
if (invert) {
downValue = downValue ^ 1;
upValue = upValue ^ 1;
}
state.last = upValue;
// Create a "state" entry for privately
// storing the state of the button
priv.set(this, state);
Object.defineProperties(this, {
value: {
get: function() {
return Number(this.isDown);
}
},
invert: {
get: function() {
return invert;
},
set: function(value) {
invert = value;
downValue = invert ? 0 : 1;
upValue = invert ? 1 : 0;
state.last = upValue;
}
},
downValue: {
get: function() {
return downValue;
},
set: function(value) {
downValue = value;
upValue = value ^ 1;
invert = value ? true : false;
state.last = upValue;
}
},
upValue: {
get: function() {
return upValue;
},
set: function(value) {
upValue = value;
downValue = value ^ 1;
invert = value ? true : false;
state.last = downValue;
}
},
isDown: {
get: function() {
return this.toBoolean(raw);
}
}
});
/* istanbul ignore else */
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
// Update the raw data value, which
// is used by isDown = toBoolean()
raw = data;
if (!this.isDown) {
/* istanbul ignore else */
if (state.interval) {
clearInterval(state.interval);
}
trigger.call(this, "up");
}
if (this.isDown) {
trigger.call(this, "down");
state.interval = setInterval(function() {
/* istanbul ignore else */
if (this.isDown) {
this.emit("hold");
}
}.bind(this), this.holdtime);
}
state.last = data;
}.bind(this));
}
}
n/a
function Buttons(numsOrObjects) { if (!(this instanceof Buttons)) { return new Buttons(numsOrObjects); } Object.defineProperty(this, "type", { value: Button }); Collection.Emitter.call(this, numsOrObjects); }
n/a
Buttons.super_ = function (numsOrObjects) {
// Create private state ahead of super call
priv.set(this, {
timing: {
last: Date.now()
}
});
Collection.call(this, numsOrObjects);
// If the Collection.Emitter was created
// with a Shared Properties object, then
// we should abide by the freq or period
// properties...
var interval = null;
var period = 5;
if (!Array.isArray(numsOrObjects) &&
(typeof numsOrObjects === "object" && numsOrObjects !== null)) {
period = numsOrObjects.freq || numsOrObjects.period || period;
// _However_, looking to the future, we
// need to start thinking about replacing
// the garbage named _freq_ (the value is
// actually a period), with real _frequency_
// in Hz.
// If provided, convert frequency to period
/* istanbul ignore else */
if (numsOrObjects.frequency) {
period = (1 / numsOrObjects.frequency) * 1000;
}
}
Object.defineProperties(this, {
period: {
get: function() {
return period;
},
set: function(value) {
if (period !== value) {
period = value;
}
if (interval) {
clearInterval(interval);
}
interval = setInterval(function() {
this.emit("data", this);
}.bind(this), period);
}
},
});
this.period = period;
this.on("newListener", function(event) {
if (event === "change" || event === "data") {
return;
}
this.forEach(function(input) {
input.on(event, function(data) {
this.emit(event, input, data);
}.bind(this));
}, this);
});
}
n/a
function Collection(numsOrObjects) {
var Type = this.type;
var initObjects = [];
this.length = 0;
if (Array.isArray(numsOrObjects)) {
initObjects = numsOrObjects;
} else {
// Initialize with a Shared Properties object
/* istanbul ignore else */
if (Array.isArray(numsOrObjects.pins)) {
var keys = Object.keys(numsOrObjects).filter(function(key) {
return key !== "pins";
});
initObjects = numsOrObjects.pins.map(function(pin) {
var obj = {};
if (Array.isArray(pin)) {
obj.pins = pin;
} else {
obj.pin = pin;
}
return keys.reduce(function(accum, key) {
accum[key] = numsOrObjects[key];
return accum;
}, obj);
});
}
}
/* istanbul ignore else */
if (initObjects.length) {
while (initObjects.length) {
var numOrObject = initObjects.shift();
// When a Type exists, respect it!
if (typeof Type === "function") {
if (!(numOrObject instanceof Type || numOrObject instanceof this.constructor)) {
numOrObject = new Type(numOrObject);
}
}
this.add(numOrObject);
}
}
}
n/a
function Color(opts) { if (!(this instanceof Color)) { return new Color(opts); } var controller = null; var state = {}; var freq = opts.freq || 25; var raw = 0; var last = null; Board.Component.call( this, opts = Board.Options(opts) ); if (typeof opts.controller === "string") { controller = Controllers[opts.controller]; } else { controller = opts.controller; } if (controller == null) { throw new Error("Color expects a valid controller"); } priv.set(this, state); Board.Controller.call(this, controller, opts); if (!this.toRGB) { this.toRGB = opts.toRGB || function(x) { return x; }; } Object.defineProperties(this, { value: { get: function() { return raw; } }, rgb: { get: function() { return this.toRGB(raw).reduce(function(accum, value, index) { accum[colorNames[index]] = value; return accum; }, {}); } } }); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { raw = data; }); } setInterval(function() { if (raw === undefined) { return; } var data = { rgb: this.rgb, }; this.emit("data", data); if (raw !== last) { last = raw; this.emit("change", data); } }.bind(this), freq); }
n/a
function Compass(opts) {
if (!(this instanceof Compass)) {
return new Compass(opts);
}
Board.Component.call(
this, opts = Board.Options(opts)
);
var freq = opts.freq || 25;
var controller = null;
var raw = {
x: null,
y: null,
z: null,
};
var state = {
x: 0,
y: 0,
z: 0,
scale: 0,
register: 0,
heading: 0
};
if (opts.controller && typeof opts.controller === "string") {
controller = Controllers[opts.controller.toUpperCase()];
} else {
controller = opts.controller;
}
if (controller == null) {
throw new Error("Compass expects a valid controller");
}
Board.Controller.call(this, controller, opts);
if (!this.toScaledHeading) {
this.toScaledHeading = opts.toScaledHeading || function(raw) {
return raw;
};
}
priv.set(this, state);
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
raw = data;
});
}
setInterval(function() {
if (raw.x === null) {
return;
}
var isChange = false;
state.x = raw.x;
state.y = raw.y;
state.z = raw.z;
var heading = this.heading;
if (heading !== state.heading) {
state.heading = heading;
isChange = true;
}
this.emit("data", {
heading: state.heading
});
if (isChange) {
this.emit("change", {
heading: state.heading
});
}
}.bind(this), freq);
Object.defineProperties(this, {
/**
* [read-only] Bearing information
* @name bearing
* @property
* @type Object
*
*
name
abbr
low
mid
high
heading
*
*/
bearing: {
get: function() {
var length = Compass.Points.length;
var heading = Math.floor(this.heading);
var point;
for (var i = 0; i < length; i++) {
point = Compass.Points[i];
if (point.range.includes(heading)) {
// Specify fields to return to avoid returning the
// range array (too much noisy data)
return {
name: point.name,
abbr: point.abbr,
low: point.low,
high: point.high,
heading: heading
};
}
}
}
},
/**
* [read-only] Heading (azimuth)
* @name heading
* @property
* @type number
*/
heading: {
get: function() {
return this.toScaledHeading(raw);
}
}
});
}
n/a
Digital = function (opts) { var pin; if (typeof opts === "number" || typeof opts === "string") { pin = opts; opts = { type: "digital", pin: pin }; } else { opts.type = opts.type || "digital"; } return new module.exports.Sensor(opts); }
n/a
function ESC(opts) { if (!(this instanceof ESC)) { return new ESC(opts); } var controller = null; var pinValue; var device; var state = { // All speed history for this ESC // history = [ // { // timestamp: Date.now(), // speed: speed // } // ]; history: [], value: 0 }; Board.Component.call( this, opts = Board.Options(opts) ); priv.set(this, state); this.startAt = typeof opts.startAt !== "undefined" ? opts.startAt : null; this.neutral = opts.neutral; this.range = opts.range || [0, 100]; this.pwmRange = opts.pwmRange || [544, 2400]; this.interval = null; // StandardFirmata on Arduino allows controlling // servos from analog pins. // If we're currently operating with an Arduino // and the user has provided an analog pin name // (eg. "A0", "A5" etc.), parse out the numeric // value and capture the fully qualified analog // pin number. if (typeof opts.controller === "undefined" && Pins.isFirmata(this)) { if (typeof pinValue === "string" && pinValue[0] === "A") { pinValue = this.io.analogPins[+pinValue.slice(1)]; } pinValue = +pinValue; // If the board's default pin normalization // came up with something different, use the // the local value. if (!Number.isNaN(pinValue) && this.pin !== pinValue) { this.pin = pinValue; } } // Allow users to pass in custom device types device = typeof opts.device === "string" ? Devices[opts.device] : opts.device; if (!device) { device = Devices.FORWARD; } if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (!controller) { controller = Controllers.DEFAULT; } Object.defineProperties(this, Object.assign({}, device, controller, { value: { get: function() { return state.value; } }, history: { get: function() { return state.history.slice(-5); } }, last: { get: function() { return state.history[state.history.length - 1] || { last: null }; } } })); this.initialize(opts); if (this.deviceName !== "FORWARD") { if (Number.isNaN(+this.neutral)) { throw new Error("Directional speed controllers require a neutral point from 0-100 (number)"); } this.startAt = this.neutral; } // Match either null or undefined, but not 0 if (this.startAt !== null && this.startAt !== undefined) { this.speed(this.startAt); } }
n/a
function ESCs(numsOrObjects) { if (!(this instanceof ESCs)) { return new ESCs(numsOrObjects); } Object.defineProperty(this, "type", { value: ESC }); Collection.call(this, numsOrObjects); }
n/a
function Expander(opts) { if (!(this instanceof Expander)) { return new Expander(opts); } Base.call(this); var expander = null; var addressError = "Expander cannot reuse an active address"; var controller = null; var state = {}; var controllerValue; if (typeof opts === "string") { controllerValue = opts; } Board.Component.call( this, opts = Board.Options(opts), { normalizePin: false, requestPin: false } ); if (nonAddressable.includes(opts.controller) && typeof this.address === "undefined") { this.address = Fn.uid(); } expander = active.get(this.address); if (expander) { if (this.bus && (expander.bus !== undefined && expander.bus === this.bus)) { addressError += " on this bus"; } throw new Error(addressError); } if (typeof opts.controller === "undefined" && controllerValue) { opts.controller = controllerValue; } if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { throw new Error("Expander expects a valid controller"); } Board.Controller.call(this, controller, opts); priv.set(this, state); if (typeof this.initialize === "function") { this.initialize(opts); } active.set(this.address, this); }
n/a
function Base() { Emitter.call(this); this.HIGH = 1; this.LOW = 0; this.isReady = false; this.MODES = {}; this.pins = []; this.analogPins = []; }
n/a
function GPS(opts) { var breakout, receiver, chip, state; if (!(this instanceof GPS)) { return new GPS(opts); } // Allow users to pass in a 2 element array for rx and tx pins if (Array.isArray(opts)) { opts = { pins: { rx: opts[0], tx: opts[1], onOff: opts[2] } }; } if (typeof opts.pins === "undefined") { opts.pins = {}; } Board.Component.call( this, opts = Board.Options(opts) ); // Get user values for breakout, receiver and chip breakout = opts.breakout || {}; receiver = opts.receiver; chip = opts.chip; // If a breakout is defined check for receiver and chip if (Breakouts[breakout]) { if (!receiver && Breakouts[breakout].receiver) { receiver = Breakouts[breakout].receiver.value; } if (!chip && Breakouts[breakout].chip) { chip = Breakouts[breakout].chip.value; } } // If a receiver was defined or derived but chip was not if (!chip) { if (receiver && Receivers[receiver].chip) { chip = Receivers[receiver].chip.value; } else { chip = "DEFAULT"; } } // Allow users to pass in custom chip types chip = typeof chip === "string" ? Chips[chip] : opts.chip; // Allow users to pass in custom receiver types receiver = typeof receiver === "string" ? Receivers[receiver] : opts.receiver; // Chip decorates the instance Object.defineProperties(this, chip); // Receiver decorates this instance if (receiver) { Object.defineProperties(this, receiver); } // breakout decorates the instance if (opts.breakout) { breakout = typeof opts.breakout === "string" ? Breakouts[opts.breakout] : opts.breakout; Board.Controller.call(this, breakout, opts); } // If necessary set default property values this.fixed = opts.fixed || 6; this.baud = opts.baud || this.baud; // Create a "state" entry for privately // storing the state of the instance state = { sat: {}, latitude: 0.0, longitude: 0.0, altitude: 0.0, speed: 0.0, course: 0.0, frequency: 1, lowPowerMode: false }; priv.set(this, state); // Getters for private state values Object.defineProperties(this, { latitude: { get: function() { return state.latitude; } }, longitude: { get: function() { return state.longitude; } }, altitude: { get: function() { return state.altitude; } }, sat: { get: function() { return state.sat; } }, speed: { get: function() { return state.speed; } }, course: { get: function() { return state.course; } }, time: { get: function() { return state.time; } } }); if (this.initialize) { this.initialize(opts); } }
n/a
function Gripper(opts) { if (!(this instanceof Gripper)) { return new Gripper(opts); } // Default options mode, assume only when opts is a pin number if (typeof opts === "number") { opts = { servo: { pin: opts, range: [0, 180] }, scale: [0, 10] }; } // Default set() args to 0-10 this.scale = opts.scale || [0, 10]; // Setup servo // Allows pre-constructed servo or creating new servo. // Defaults for new Servo creation fall back to Servo defaults this.servo = opts.servo instanceof Servo ? opts.servo : new Servo(opts.servo); }
n/a
function Gyro(opts) { if (!(this instanceof Gyro)) { return new Gyro(opts); } var controller = null; var isCalibrated = false; var sampleSize = 100; var state = { x: { angle: 0, value: 0, previous: 0, calibration: [], stash: [0, 0, 0, 0, 0], center: 0, hasValue: false }, y: { angle: 0, value: 0, previous: 0, calibration: [], stash: [0, 0, 0, 0, 0], center: 0, hasValue: false }, z: { angle: 0, value: 0, previous: 0, calibration: [], stash: [0, 0, 0, 0, 0], center: 0, hasValue: false } }; Board.Component.call( this, opts = Board.Options(opts) ); if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.ANALOG; } Board.Controller.call(this, controller, opts); if (!this.toNormal) { this.toNormal = opts.toNormal || function(raw) { return raw; }; } if (!this.toDegreesPerSecond) { this.toDegreesPerSecond = opts.toDegreesPerSecond || function(raw) { return raw; }; } priv.set(this, state); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { var isChange = false; Object.keys(data).forEach(function(axis) { var value = data[axis]; var sensor = state[axis]; sensor.previous = sensor.value; sensor.stash.shift(); sensor.stash.push(value); sensor.hasValue = true; sensor.value = (sum(sensor.stash) / 5) | 0; if (!isCalibrated && (state.x.calibration.length === sampleSize && state.y.calibration.length === sampleSize && (this.z === undefined || state.z.calibration.length === sampleSize))) { isCalibrated = true; state.x.center = (sum(state.x.calibration) / sampleSize) | 0; state.y.center = (sum(state.y.calibration) / sampleSize) | 0; state.z.center = (sum(state.z.calibration) / sampleSize) | 0; state.x.calibration.length = 0; state.y.calibration.length = 0; state.z.calibration.length = 0; } else { if (sensor.calibration.length < sampleSize) { sensor.calibration.push(value); } } if (sensor.previous !== sensor.value) { isChange = true; } }, this); if (isCalibrated) { state.x.angle += this.rate.x / 100; state.y.angle += this.rate.y / 100; state.z.angle += this.rate.z / 100; this.emit("data", { x: this.x, y: this.y, z: this.z }); if (isChange) { this.emit("change", { x: this.x, y: this.y, z: this.z }); } } }.bind(this)); } Object.defineProperties(this, { isCalibrated: { get: function() { return isCalibrated; }, set: function(value) { if (typeof value === "boolean") { isCalibrated = value; } } }, pitch: { get: function() { return { rate: toFixed(this.rate.y, 2), angle: toFixed(state.y.angle, 2) }; } }, roll: { get: function() { return { rate: toFixed(this.rate.x, 2), angle: toFixed(state.x.angle, 2) }; } }, yaw: { get: function() { return { rate: this.z !== undefined ? toFixed(this.rate.z, 2) : 0, angle: this.z !== undefined ? toFixed(state.z.angle, 2) : 0 }; } }, x: { get: function() { return toFixed(this.toNormal(state.x.value), 4); } }, y: { get: function() { return toFixed(this.toNormal(state.y.value), 4); } }, z: { get: function() { return state.z.hasValue ? toFixed(this.toNormal(state. ...
n/a
function Hygrometer(opts) { if (!(this instanceof Hygrometer)) { return new Hygrometer(opts); } var controller = null; var last = null; var raw = null; Board.Component.call( this, opts = Board.Options(opts) ); var freq = opts.freq || 25; if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { throw new Error("Missing Hygrometer controller"); } priv.set(this, {}); Board.Controller.call(this, controller, opts); if (!this.toRelativeHumidity) { this.toRelativeHumidity = opts.toRelativeHumidity || function(x) { return x; }; } var propDescriptors = { relativeHumidity: { get: function() { return this.toRelativeHumidity(raw); } } }; // Convenience aliases propDescriptors.RH = propDescriptors.relativeHumidity; Object.defineProperties(this, propDescriptors); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { raw = data; }); } setInterval(function() { if (raw == null) { return; } if (Number.isNaN(this.relativeHumidity)) { return; } var data = {}; data.RH = data.relativeHumidity = this.relativeHumidity; this.emit("data", data); if (this.relativeHumidity !== last) { last = this.relativeHumidity; this.emit("change", data); } }.bind(this), freq); }
n/a
function IMU(opts) { if (!(this instanceof IMU)) { return new IMU(opts); } var controller, state; Board.Component.call( this, opts = Board.Options(opts) ); if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { throw new Error("Missing IMU/Multi controller"); } this.freq = opts.freq || 20; state = {}; priv.set(this, state); Board.Controller.call(this, controller, opts); if (typeof this.initialize === "function") { this.initialize(opts); } // The IMU/Multi isn't considered "ready" // until one of the components has notified via // a change event. this.isReady = false; setInterval(function() { if (this.isReady) { this.emit("data", this); } }.bind(this), this.freq); var awaiting = this.components.slice(); if (this.components && this.components.length > 0) { this.components.forEach(function(component) { if (!(this[component] instanceof Emitter)) { return; } this[component].on("change", function() { if (awaiting.length) { var index = awaiting.indexOf(component); if (index !== -1) { awaiting.splice(index, 1); } } if (!awaiting.length && !this.isReady) { this.isReady = true; } if (this.isReady) { this.emit("change", this, component); } }.bind(this)); }, this); } }
n/a
IR = function () { throw new Error("IR has been removed. Use Motion or Proximity instead."); }
n/a
function Joystick(opts) { if (!(this instanceof Joystick)) { return new Joystick(opts); } var controller = null; var state = { x: { invert: false, value: 0, previous: 0, zeroV: 0, calibrated: false }, y: { invert: false, value: 0, previous: 0, zeroV: 0, calibrated: false } }; Board.Component.call( this, opts = Board.Options(opts) ); if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.ANALOG; } Board.Controller.call(this, controller, opts); if (!this.toAxis) { this.toAxis = opts.toAxis || function(raw) { return raw; }; } state.x.zeroV = opts.zeroV === undefined ? 0 : (opts.zeroV.x || 0); state.y.zeroV = opts.zeroV === undefined ? 0 : (opts.zeroV.y || 0); state.x.invert = opts.invertX || opts.invert || false; state.y.invert = opts.invertY || opts.invert || false; priv.set(this, state); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { var isChange = false; var computed = { x: null, y: null }; Object.keys(data).forEach(function(axis) { var value = data[axis]; var sensor = state[axis]; // Set the internal ADC reading value... sensor.value = value; if (!state[axis].calibrated) { state[axis].calibrated = true; state[axis].zeroV = value; isChange = true; } // ... Get the computed axis value. computed[axis] = this[axis]; var absAxis = Math.abs(computed[axis]); var absPAxis = Math.abs(sensor.previous); if ((absAxis < absPAxis) || (absAxis > absPAxis)) { isChange = true; } sensor.previous = computed[axis]; }, this); this.emit("data", { x: computed.x, y: computed.y }); if (isChange) { this.emit("change", { x: computed.x, y: computed.y }); } }.bind(this)); } Object.defineProperties(this, { x: { get: function() { return this.toAxis(state.x.value, "x") * (state.x.invert ? -1 : 1); } }, y: { get: function() { return this.toAxis(state.y.value, "y") * (state.y.invert ? -1 : 1); } } }); }
n/a
function Keypad(opts) { if (!(this instanceof Keypad)) { return new Keypad(opts); } // Initialize a Device instance on a Board Board.Component.call( this, opts = Board.Options(opts) ); var raw = null; var controller = null; var state = { touches: null, timeout: null, length: null, keys: null, mapping: null, holdtime: null, }; var trigger = Fn.debounce(function(type, value) { var event = { type: type, which: value, timestamp: Date.now() }; aliases[type].forEach(function(type) { this.emit(type, event); }, this); this.emit("change", Object.assign({}, event)); }, 5); if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.ANALOG; } Board.Controller.call(this, controller, opts); state.holdtime = opts.holdtime ? opts.holdtime : 500; priv.set(this, state); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { raw = data; var now = Date.now(); var indices = this.toIndices(data); var kLength = state.length; var lists = { down: [], hold: [], up: [], }; var target = null; var alias = null; for (var k = 0; k < kLength; k++) { alias = this.toAlias(k); if (indices.includes(k)) { if (state.touches[k].value === 0) { state.touches[k].timeout = now + state.holdtime; lists.down.push(alias); } else if (state.touches[k].value === 1) { if (state.touches[k].timeout !== null && now > state.touches[k].timeout) { state.touches[k].timeout = now + state.holdtime; lists.hold.push(alias); } } state.touches[k].value = 1; } else { if (state.touches[k].value === 1) { state.touches[k].timeout = null; lists.up.push(alias); } state.touches[k].value = 0; } target = null; alias = null; } Object.keys(lists).forEach(function(key) { var list = lists[key]; if (list.length) { trigger.call(this, key, list); } }, this); }.bind(this)); } Object.defineProperties(this, { isMultitouch: { get: function() { return state.isMultitouch; } }, value: { get: function() { return raw; } }, }); }
n/a
function LCD(opts) { if (!(this instanceof LCD)) { return new LCD(opts); } Board.Component.call( this, opts = Board.Options(opts) ); var controller = null; if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.PARALLEL; } Board.Controller.call(this, controller, opts); this.ctype = opts.controller; if (this.initialize) { this.initialize(opts); } Object.defineProperties(this, { characters: { get: function() { return Object.assign({}, priv.get(this).characters); }, }, }); }
n/a
function Led(opts) {
if (!(this instanceof Led)) {
return new Led(opts);
}
var pinValue = typeof opts === "object" ? opts.pin : opts;
var controller = null;
Board.Component.call(
this, opts = Board.Options(opts)
);
if (opts.controller && typeof opts.controller === "string") {
controller = Controllers[opts.controller.toUpperCase()];
} else {
controller = opts.controller;
}
if (controller == null) {
controller = Controllers.DEFAULT;
}
Object.defineProperties(this, controller);
var state = {
isAnode: opts.isAnode,
isOn: false,
isRunning: false,
value: null,
direction: 1,
mode: null,
intensity: 0,
interval: null
};
priv.set(this, state);
Object.defineProperties(this, {
value: {
get: function() {
return state.value;
}
},
mode: {
get: function() {
return state.mode;
}
},
isOn: {
get: function() {
return !!state.value;
}
},
isRunning: {
get: function() {
return state.isRunning;
}
},
animation: {
get: function() {
return state.animation;
}
}
});
/* istanbul ignore else */
if (typeof this.initialize === "function") {
this.initialize(opts, pinValue);
}
}
...
```javascript
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
<img src="https://github.com/rwaldron/johnny-five/raw/master/assets/led-blink.gif">
...
function RGB(opts) { if (!(this instanceof RGB)) { return new RGB(opts); } var controller = null; if (Array.isArray(opts)) { // RGB([Byte, Byte, Byte]) shorthand // Convert to opts.pins array definition opts = { pins: opts }; // If opts.pins is an object, convert to array } else if (typeof opts.pins === "object" && !Array.isArray(opts.pins)) { opts.pins = [opts.pins.red, opts.pins.green, opts.pins.blue]; } Board.Component.call( this, opts = Board.Options(opts) ); if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.DEFAULT; } // The default color is #ffffff, but the light will be off var state = { red: 255, green: 255, blue: 255, intensity: 100, isAnode: opts.isAnode || false, interval: null }; // red, green, and blue store the raw color set via .color() // values takes state into account, such as on/off and intensity state.values = { red: state.red, green: state.green, blue: state.blue }; priv.set(this, state); Board.Controller.call(this, controller, opts); Object.defineProperties(this, { isOn: { get: function() { return RGB.colors.some(function(color) { return state[color] > 0; }); } }, isRunning: { get: function() { return !!state.interval; } }, isAnode: { get: function() { return state.isAnode; } }, values: { get: function() { return Object.assign({}, state.values); } }, update: { value: function(colors) { var state = priv.get(this); colors = colors || this.color(); state.values = RGB.ToScaledRGB(state.intensity, colors); this.write(state.values); Object.assign(state, colors); } } }); this.initialize(opts); this.off(); }
n/a
function RGBs(numsOrObjects) { if (!(this instanceof RGBs)) { return new RGBs(numsOrObjects); } Object.defineProperty(this, "type", { value: RGB }); Collection.call(this, numsOrObjects); }
n/a
function LedControl(opts) {
Board.Component.call(
this, opts = Board.Options(opts)
);
/*
device instance uses an interface from Controllers:
either MAX 7219 (default) or HT16K33
*/
var controller = null;
if (typeof opts.controller === "string") {
controller = Controllers[opts.controller];
} else {
controller = opts.controller;
}
if (typeof controller === "undefined") {
controller = Controllers.DEFAULT;
}
// functions from Controller interface
this.clear = controller.clear;
this.led = controller.led;
this.row = controller.row;
this.scanLimit = controller.scanLimit;
this.send = controller.send;
this.sendDigit = controller.sendDigit;
this.initialize = controller.initialize;
// controller specific op codes
this.OP = controller.OP;
// digit indexes may be ordered left to right (1) or reversed (-1)
this.digitOrder = 1;
// Does the device have a built-in colon?
/* istanbul ignore else */
if (!this.isMatrix) {
this.colon = opts.colon || false;
}
// extra functions for HT16K33 devices only
if (controller.writeDisplay) {
this.writeDisplay = controller.writeDisplay;
}
if (controller.blink) {
this.blink = controller.blink;
}
/*
devices variable indicates number of connected LED devices
Here's an example of multiple devices:
http://tronixstuff.com/2013/10/11/tutorial-arduino-max7219-led-display-driver-ic/
*/
var devices = opts.devices || (opts.addresses ? opts.addresses.length : 1);
this.memory = Array(64).fill(0);
opts.dims = opts.dims || LedControl.MATRIX_DIMENSIONS["8x8"];
if (typeof opts.dims === "string") {
opts.dims = LedControl.MATRIX_DIMENSIONS[opts.dims];
}
if (Array.isArray(opts.dims)) {
opts.dims = {
rows: opts.dims[0],
columns: opts.dims[1],
};
}
var state = {
devices: devices,
digits: opts.digits || 8,
isMatrix: !!opts.isMatrix,
isBicolor: !!opts.isBicolor,
rows: opts.dims.rows,
columns: opts.dims.columns
};
if (!(state.columns === 8 || state.columns === 16) || !(state.rows === 8 || state.rows === 16) || (state.columns + state.rows ===
32)) {
throw new Error("Invalid matrix dimensions specified: must be 8x8, 16x8 or 8x16");
}
Object.defineProperties(this, {
devices: {
get: function() {
return state.devices;
}
},
digits: {
get: function() {
return state.digits;
}
},
isMatrix: {
get: function() {
return state.isMatrix;
}
},
isBicolor: {
get: function() {
return state.isBicolor;
}
},
rows: {
get: function() {
return state.rows;
}
},
columns: {
get: function() {
return state.columns;
}
}
});
priv.set(this, state);
controller.initialize.call(this, opts);
}
n/a
function Leds(numsOrObjects) { if (!(this instanceof Leds)) { return new Leds(numsOrObjects); } Object.defineProperty(this, "type", { value: Led }); Collection.call(this, numsOrObjects); }
n/a
function Light(opts) {
if (!(this instanceof Light)) {
return new Light(opts);
}
var controller = null;
var state = {};
var raw = 0;
var last = 0;
var freq = opts.freq || 25;
Board.Component.call(
this, opts = Board.Options(opts)
);
if (typeof opts.controller === "string") {
controller = Controllers[opts.controller];
} else {
controller = opts.controller || Controllers.DEFAULT;
}
Board.Controller.call(this, controller, opts);
if (!this.toIntensityLevel) {
this.toIntensityLevel = opts.toIntensityLevel || function(x) {
return x;
};
}
if (!this.toLux) {
this.toLux = opts.toLux || function(x) {
return x;
};
}
Object.defineProperties(this, {
value: {
get: function() {
return raw;
},
},
level: {
get: function() {
return this.toIntensityLevel(raw);
},
},
});
priv.set(this, state);
/* istanbul ignore else */
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
raw = data;
});
}
if (typeof this.lux === "undefined") {
Object.defineProperty(this, "lux", {
get: function() {
return this.toLux(raw);
},
});
}
var data = {
level: 0,
lux: 0,
};
setInterval(function() {
data.level = this.level;
data.lux = this.lux;
this.emit("data", data);
if (raw !== last) {
last = raw;
this.emit("change", data);
}
}.bind(this), freq);
}
n/a
Luxmeter = function (options) { return new module.exports.Light(options); }
n/a
Magnetometer = function (options) { return new module.exports.Compass(options); }
n/a
function Motion(opts) {
if (!(this instanceof Motion)) {
return new Motion(opts);
}
var freq = opts.freq || 25;
var last = false;
var controller;
var state;
Board.Component.call(
this, opts = Board.Options(opts)
);
if (typeof opts.controller === "string") {
controller = Controllers[opts.controller];
} else {
controller = opts.controller || Controllers["PIR"];
}
Board.Controller.call(this, controller, opts);
state = {
value: false,
isCalibrated: false
};
priv.set(this, state);
Object.defineProperties(this, {
/**
* [read-only] Current sensor state
* @property detectedMotion
* @type Boolean
*/
detectedMotion: {
get: function() {
return this.toBoolean(state.value);
}
},
/**
* [read-only] Sensor calibration status
* @property isCalibrated
* @type Boolean
*/
isCalibrated: {
get: function() {
return state.isCalibrated;
}
},
});
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
state.value = data;
});
}
setInterval(function() {
var isChange = false;
var eventData = {
timestamp: Date.now(),
detectedMotion: this.detectedMotion,
isCalibrated: state.isCalibrated
};
if (state.isCalibrated && this.detectedMotion && !last) {
this.emit("motionstart", eventData);
}
if (state.isCalibrated && !this.detectedMotion && last) {
this.emit("motionend", eventData);
}
if (last !== this.detectedMotion) {
isChange = true;
}
this.emit("data", eventData);
if (isChange) {
this.emit("change", eventData);
}
last = this.detectedMotion;
}.bind(this), freq);
}
n/a
Motion.Collection = function (numsOrObjects) { if (!(this instanceof Motion.Collection)) { return new Motion.Collection(numsOrObjects); } Object.defineProperty(this, "type", { value: Motion }); Collection.Emitter.call(this, numsOrObjects); }
n/a
function Motor(opts) {
var device, controller, state;
if (!(this instanceof Motor)) {
return new Motor(opts);
}
Board.Component.call(
this, this.opts = Board.Options(opts)
);
controller = opts.controller || null;
// Derive device based on pins passed
if (typeof this.opts.device === "undefined") {
this.opts.device = (typeof this.opts.pins === "undefined" && typeof this.opts.register !== "object") ?
"NONDIRECTIONAL" : "DIRECTIONAL";
if (this.opts.pins && (this.opts.pins.cdir || this.opts.pins.length > 2)) {
this.opts.device = "CDIR";
}
if (typeof controller === "string" &&
(controller.startsWith("EVS") || controller.startsWith("GROVE_I2C"))) {
this.opts.device = "DIRECTIONAL";
}
}
// Allow users to pass in custom device types
device = typeof this.opts.device === "string" ?
Devices[this.opts.device] : this.opts.device;
this.threshold = typeof this.opts.threshold !== "undefined" ?
this.opts.threshold : 30;
this.invertPWM = typeof this.opts.invertPWM !== "undefined" ?
this.opts.invertPWM : false;
Object.defineProperties(this, device);
if (this.opts.register) {
this.opts.controller = "ShiftRegister";
}
/**
* Note: Controller decorates the device. Used for adding
* special controllers (i.e. PCA9685)
**/
if (this.opts.controller) {
controller = typeof this.opts.controller === "string" ?
Controllers[this.opts.controller] : this.opts.controller;
Board.Controller.call(this, controller, opts);
}
// current just wraps a Sensor
if (this.opts.current) {
this.opts.current.board = this.board;
this.current = new Sensor(this.opts.current);
}
// Create a "state" entry for privately
// storing the state of the motor
state = {
isOn: false,
currentSpeed: typeof this.opts.speed !== "undefined" ?
this.opts.speed : 128,
braking: false,
enabled: true
};
priv.set(this, state);
Object.defineProperties(this, {
// Calculated, read-only motor on/off state
// true|false
isOn: {
get: function() {
return state.isOn;
}
},
currentSpeed: {
get: function() {
return state.currentSpeed;
}
},
braking: {
get: function() {
return state.braking;
}
},
enabled: {
get: function() {
return state.enabled;
}
}
});
// We need to store and initialize the state of the dir pin(s)
this.direction = {
value: 1
};
if (this.initialize) {
this.initialize(opts);
}
this.enable();
this.dir(this.direction);
}
n/a
function Motors(numsOrObjects) { if (!(this instanceof Motors)) { return new Motors(numsOrObjects); } Object.defineProperty(this, "type", { value: Motor }); Collection.call(this, numsOrObjects); }
n/a
function IMU(opts) { if (!(this instanceof IMU)) { return new IMU(opts); } var controller, state; Board.Component.call( this, opts = Board.Options(opts) ); if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { throw new Error("Missing IMU/Multi controller"); } this.freq = opts.freq || 20; state = {}; priv.set(this, state); Board.Controller.call(this, controller, opts); if (typeof this.initialize === "function") { this.initialize(opts); } // The IMU/Multi isn't considered "ready" // until one of the components has notified via // a change event. this.isReady = false; setInterval(function() { if (this.isReady) { this.emit("data", this); } }.bind(this), this.freq); var awaiting = this.components.slice(); if (this.components && this.components.length > 0) { this.components.forEach(function(component) { if (!(this[component] instanceof Emitter)) { return; } this[component].on("change", function() { if (awaiting.length) { var index = awaiting.indexOf(component); if (index !== -1) { awaiting.splice(index, 1); } } if (!awaiting.length && !this.isReady) { this.isReady = true; } if (this.isReady) { this.emit("change", this, component); } }.bind(this)); }, this); } }
n/a
Nunchuk = function (opts) { opts = opts || {}; opts.device = "RVL-004"; return new Wii(opts); }
n/a
function Piezo(opts) { if (!(this instanceof Piezo)) { return new Piezo(opts); } Board.Component.call( this, opts = Board.Options(opts) ); var controller = null; if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.DEFAULT; } Object.defineProperties(this, controller); Board.Controller.call(this, controller, opts); // Piezo instance properties var state = { isPlaying: false, timeout: null, address: null, }; priv.set(this, state); Object.defineProperties(this, { isPlaying: { get: function() { return state.isPlaying; } } }); if (typeof this.initialize === "function") { this.initialize(opts); } }
n/a
function Pin(opts) { if (!(this instanceof Pin)) { return new Pin(opts); } if (opts === undefined || (typeof opts === "object" && opts.addr === undefined && opts.pin === undefined)) { throw new Error("Pins must have a pin number"); } var pinValue = typeof opts === "object" ? (opts.addr || opts.pin || 0) : opts; var isAnalogInput = Pin.isAnalog(opts); var isDTOA = false; Board.Component.call( this, opts = Board.Options(opts) ); opts.addr = opts.addr || opts.pin; if (this.io.analogPins.includes(pinValue)) { isAnalogInput = false; isDTOA = true; } var isPin = typeof opts !== "object"; var addr = isDTOA ? pinValue : (isPin ? opts : opts.addr); var type = opts.type || (isAnalogInput ? "analog" : "digital"); // Create a private side table var state = { mode: null, last: null, value: 0 }; priv.set(this, state); // Create read-only "addr(address)" property Object.defineProperties(this, { type: { get: function() { return type; } }, addr: { get: function() { return addr; } }, value: { get: function() { return state.value; } }, mode: { set: function(mode) { var state = priv.get(this); state.mode = mode; this.io.pinMode(this.addr, mode); }, get: function() { return priv.get(this).mode; } } }); this.mode = typeof opts.as !== "undefined" ? opts.as : (typeof opts.mode !== "undefined" ? opts.mode : (isAnalogInput ? 0x02 : 0x01)); this.freq = typeof opts.freq !== "undefined" ? opts.freq : 20; if (this.mode === 0 || this.mode === 2) { read(this); } if (type === "digital") { Object.defineProperties(this, { isHigh: { get: function() { return !!state.value; } }, isLow: { get: function() { return !state.value; } }, }); } }
n/a
function Ping(opts) { if (!(this instanceof Ping)) { return new Ping(opts); } var last = null; Board.Component.call( this, opts = Board.Options(opts) ); this.pin = opts && opts.pin || 7; this.freq = opts.freq || 20; // this.pulse = opts.pulse || 250; var state = { value: null }; // Private settings object var settings = { pin: this.pin, value: this.io.HIGH, pulseOut: 5 }; this.io.setMaxListeners(100); // Interval for polling pulse duration as reported in microseconds setInterval(function() { this.io.pingRead(settings, function(microseconds) { state.value = microseconds; }); }.bind(this), 225); // Interval for throttled event setInterval(function() { if (state.value === null) { return; } // The "read" event has been deprecated in // favor of a "data" event. this.emit("data", state.value); // If the state.value for this interval is not the same as the // state.value in the last interval, fire a "change" event. if (state.value !== last) { this.emit("change", state.value); } // Store state.value for comparison in next interval last = state.value; // Reset samples; // samples.length = 0; }.bind(this), this.freq); Object.defineProperties(this, { value: { get: function() { return state.value; } }, // Based on the round trip travel time in microseconds, // Calculate the distance in inches and centimeters inches: { get: function() { return toFixed(state.value / 74 / 2, 2); } }, in: { get: function() { return this.inches; } }, cm: { get: function() { return toFixed(state.value / 29 / 2, 3); } } }); priv.set(this, state); }
n/a
function Pins(numsOrObjects) { if (!(this instanceof Pins)) { return new Pins(numsOrObjects); } Object.defineProperty(this, "type", { value: Pin }); Collection.call(this, numsOrObjects); }
n/a
function Proximity(opts) {
if (!(this instanceof Proximity)) {
return new Proximity(opts);
}
var controller = null;
var state = {};
var raw = 0;
var freq = opts.freq || 25;
var last = 0;
var pinValue = typeof opts === "object" ? opts.pin : opts;
Board.Component.call(
this, opts = Board.Options(opts)
);
if (typeof opts.controller === "string") {
controller = Controllers[opts.controller];
} else {
controller = opts.controller || Controllers["GP2Y0A21YK"];
}
Board.Controller.call(this, controller, opts);
if (!this.toCm) {
this.toCm = opts.toCm || function(x) {
return x;
};
}
priv.set(this, state);
Object.defineProperties(this, {
/**
* [read-only] Calculated centimeter value
* @property centimeters
* @type Number
*/
centimeters: {
get: function() {
return this.toCm(raw);
}
},
cm: {
get: function() {
return this.centimeters;
}
},
/**
* [read-only] Calculated inch value
* @property inches
* @type Number
*/
inches: {
get: function() {
return toFixed(this.centimeters * 0.39, 2);
}
},
in: {
get: function() {
return this.inches;
}
},
});
if (typeof this.initialize === "function") {
opts.pinValue = pinValue;
this.initialize(opts, function(data) {
raw = data;
});
}
setInterval(function() {
if (raw === undefined) {
return;
}
var data = {
cm: this.cm,
centimeters: this.centimeters,
in: this.in,
inches: this.inches
};
this.emit("data", data);
if (raw !== last) {
last = raw;
this.emit("change", data);
}
}.bind(this), freq);
}
n/a
Proximity.Collection = function (numsOrObjects) { if (!(this instanceof Proximity.Collection)) { return new Proximity.Collection(numsOrObjects); } Object.defineProperty(this, "type", { value: Proximity }); Collection.Emitter.call(this, numsOrObjects); }
n/a
function Relay(opts) { var state; if (!(this instanceof Relay)) { return new Relay(opts); } Board.Component.call( this, opts = Board.Options(opts) ); opts.type = opts.type || "NO"; state = { isInverted: opts.type === "NC", isOn: false, value: null, }; priv.set(this, state); Object.defineProperties(this, { value: { get: function() { return Number(this.isOn); } }, type: { get: function() { return state.isInverted ? "NC" : "NO"; } }, isOn: { get: function() { return state.isOn; } } }); }
n/a
function Relays(numsOrObjects) { if (!(this instanceof Relays)) { return new Relays(numsOrObjects); } Object.defineProperty(this, "type", { value: Relay }); Collection.call(this, numsOrObjects); }
n/a
function Repl(opts) { if (!Repl.isActive) { Repl.isActive = true; if (!(this instanceof Repl)) { return new Repl(opts); } // Store context values in instance property // this will be used for managing scope when // injecting new values into an existing Repl // session. this.context = {}; this.ready = false; var state = { opts: opts, board: opts.board, }; priv.set(this, state); // Store an accessible copy of the Repl instance // on a static property. This is later used by the // Board constructor to automattically setup Repl // sessions for all programs, which reduces the // boilerplate requirement. Repl.ref = this; } else { return Repl.ref; } }
n/a
function Sensor(opts) {
if (!(this instanceof Sensor)) {
return new Sensor(opts);
}
// Defaults to 10-bit resolution
var resolution = 0x3FF;
var raw = null;
var last = -1;
var samples = [];
Board.Component.call(
this, opts = Board.Options(opts)
);
if (!opts.type) {
opts.type = "analog";
}
if (this.io.RESOLUTION &&
(this.io.RESOLUTION.ADC &&
(this.io.RESOLUTION.ADC !== resolution))) {
resolution = this.io.RESOLUTION.ADC;
}
// Set the pin to ANALOG (INPUT) mode
this.mode = opts.type === "digital" ?
this.io.MODES.INPUT :
this.io.MODES.ANALOG;
this.io.pinMode(this.pin, this.mode);
// Create a "state" entry for privately
// storing the state of the sensor
var state = {
enabled: typeof opts.enabled === "undefined" ? true : opts.enabled,
booleanBarrier: opts.type === "digital" ? 0 : null,
intervalId: null,
scale: null,
value: 0,
median: 0,
freq: opts.freq || 25,
previousFreq: opts.freq || 25,
};
// Put a reference where the prototype methods defined in this file have access
priv.set(this, state);
// Sensor instance properties
this.range = opts.range || [0, resolution];
this.limit = opts.limit || null;
this.threshold = opts.threshold === undefined ? 1 : opts.threshold;
this.isScaled = false;
this.io[opts.type + "Read"](this.pin, function(data) {
raw = data;
// Only append to the samples when noise filtering can/will be used
if (opts.type !== "digital") {
samples.push(raw);
}
}.bind(this));
// Throttle
// TODO: The event (interval) processing function should be outside of the Sensor
// constructor function (with appropriate passed (and bound?) arguments), to
// avoid creating a separate copy (of the function) for each Sensor instance.
var eventProcessing = function() {
var err, boundary;
err = null;
// For digital sensors, skip the analog
// noise filtering provided below.
if (opts.type === "digital") {
this.emit("data", raw);
/* istanbul ignore else */
if (last !== raw) {
this.emit("change", raw);
last = raw;
}
return;
}
// Keep the previous calculated value if there were no new readings
if (samples.length > 0) {
// Filter the accumulated sample values to reduce analog reading noise
state.median = median(samples);
}
this.emit("data", state.median);
// If the filtered (state.median) value for this interval is at least ± the
// configured threshold from last, fire change events
if (state.median <= (last - this.threshold) || state.median >= (last + this.threshold)) {
this.emit("change", state.median);
// Update the instance-local `last` value (only) when a new change event
// has been emitted. For comparison in the next interval
last = state.median;
}
if (this.limit) {
if (state.median <= this.limit[0]) {
boundary = "lower";
}
if (state.median >= this.limit[1]) {
boundary = "upper";
}
if (boundary) {
this.emit("limit", {
boundary: boundary,
value: state.median
});
this.emit("limit:" + boundary, state.median);
}
}
// Reset samples
samples.length = 0;
}.bind(this); // ./function eventProcessing()
Object.defineProperties(this, {
raw: {
get: function() {
return raw;
}
},
analog: {
get: function() {
if (opts.type === "digital") {
return raw;
}
return raw === null ? 0 :
Fn.map(this.raw, 0, resolution, 0, 255) | 0;
},
},
constrained: {
get: function() {
if (opts.type === "digital") {
return raw;
}
return raw === null ? 0 :
Fn.constrain(this.raw, 0, 255);
}
},
boolean: {
get: function() {
var state = priv.get(this);
var booleanBarrier = state.booleanBarrier;
var scale = state.scale || [0, resolution];
if (boolean ...
n/a
function Sensors(numsOrObjects) { if (!(this instanceof Sensors)) { return new Sensors(numsOrObjects); } Object.defineProperty(this, "type", { value: Sensor }); Collection.Emitter.call(this, numsOrObjects); }
n/a
function Servo(opts) { if (!(this instanceof Servo)) { return new Servo(opts); } var history = []; var pinValue = typeof opts === "object" ? opts.pin : opts; var controller = null; Board.Component.call( this, opts = Board.Options(opts) ); this.range = opts.range || [0, 180]; this.deadband = opts.deadband || [90, 90]; this.fps = opts.fps || 100; this.offset = opts.offset || 0; this.mode = this.io.MODES.SERVO; this.interval = null; this.value = null; // StandardFirmata on Arduino allows controlling // servos from analog pins. // If we're currently operating with an Arduino // and the user has provided an analog pin name // (eg. "A0", "A5" etc.), parse out the numeric // value and capture the fully qualified analog // pin number. if (typeof opts.controller === "undefined" && Pins.isFirmata(this)) { if (typeof pinValue === "string" && pinValue[0] === "A") { pinValue = this.io.analogPins[+pinValue.slice(1)]; } pinValue = +pinValue; // If the board's default pin normalization // came up with something different, use the // the local value. if (!Number.isNaN(pinValue) && this.pin !== pinValue) { this.pin = pinValue; } } // The type of servo determines certain alternate // behaviours in the API this.type = opts.type || "standard"; // Invert the value of all servoWrite operations // eg. 80 => 100, 90 => 90, 0 => 180 if (opts.isInverted) { console.warn("The 'isInverted' property has been renamed 'invert'"); } this.invert = opts.isInverted || opts.invert || false; // Allow "setup"instructions to come from // constructor options properties this.startAt = 90; // Collect all movement history for this servo // history = [ // { // timestamp: Date.now(), // degrees: degrees // } // ]; if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.Standard; } priv.set(this, { history: history }); Board.Controller.call(this, controller, opts); Object.defineProperties(this, { history: { get: function() { return history.slice(-5); } }, last: { get: function() { return history[history.length - 1]; } }, position: { get: function() { return history.length ? history[history.length - 1].degrees : -1; } } }); this.initialize(opts); // If "startAt" is defined and center is falsy // set servo to min or max degrees if (opts.startAt !== undefined) { this.startAt = opts.startAt; this.to(opts.startAt); } // If "center" true set servo to 90deg if (opts.center) { this.center(); } if (opts.type === "continuous") { this.stop(); } }
n/a
function Servos(numsOrObjects) { if (!(this instanceof Servos)) { return new Servos(numsOrObjects); } Object.defineProperty(this, "type", { value: Servo }); Collection.call(this, numsOrObjects); }
n/a
function ShiftRegister(opts) { if (!(this instanceof ShiftRegister)) { return new ShiftRegister(opts); } if (Array.isArray(opts)) { // [Data, Clock, Latch, Reset] opts = { pins: { data: opts[0], clock: opts[1], latch: opts[2], reset: opts.length === 4 ? opts[3] : null, } }; } else if (typeof opts.pins === "object" && Array.isArray(opts.pins)) { opts.pins = { data: opts.pins[0], clock: opts.pins[1], latch: opts.pins[2], reset: opts.pins.length === 4 ? opts.pins[3] : null, }; } Board.Component.call( this, opts = Board.Options(opts) ); this.size = opts.size || 1; this.pins.reset = typeof opts.pins.reset !== "undefined" ? opts.pins.reset : null; var isAnode = typeof opts.isAnode !== "undefined" ? opts.isAnode : false; var clear = isAnode ? 255 : 0; var state = { isAnode: isAnode, value: new Array(this.size).fill(clear), encoded: encoded[isAnode ? "anode" : "cathode"], clear: clear, }; priv.set(this, state); Object.defineProperties(this, { isAnode: { get: function() { return isAnode; } }, value: { get: function() { return state.value; } }, }); }
n/a
function ShiftRegisters(numsOrObjects) { if (!(this instanceof ShiftRegisters)) { return new ShiftRegisters(numsOrObjects); } Object.defineProperty(this, "type", { value: ShiftRegister }); Collection.call(this, numsOrObjects); }
n/a
function Sonar(opts) { if (!(this instanceof Sonar)) { return new Sonar(opts); } Board.Component.call( this, opts = Board.Options(opts) ); var device, state; // Sonar instance properties this.freq = opts.freq || 100; this.value = null; state = { last: 0, median: 0, samples: [] }; priv.set(this, state); if (typeof opts.device === "string") { device = Devices[opts.device]; } else { device = opts.device; } if (typeof device === "undefined") { device = Devices.DEFAULT; } device.initialize.call(this, opts); if (!device.descriptor.inches) { device.descriptor.inches = { get: function() { return +(this.cm * 0.39).toFixed(2); } }; } device.descriptor.in = device.descriptor.inches; Object.defineProperties(this, device.descriptor); // Throttle setInterval(function() { // Nothing read since previous interval if (state.samples.length === 0) { return; } state.median = state.samples.sort()[Math.floor(state.samples.length / 2)]; this.value = state.median; this.emit("data", state.median); // If the state.median value for this interval is not the same as the // state.median value in the last interval, fire a "change" event. // if (state.last && state.median && (state.median.toFixed(1) !== state.last.toFixed(1))) { this.emit("change", state.median); } // Store this media value for comparison // in next interval state.last = state.median; // Reset state.samples; state.samples.length = 0; }.bind(this), this.freq); }
n/a
function Stepper(opts) { var state, params = []; if (!(this instanceof Stepper)) { return new Stepper(opts); } Board.Component.call( this, opts = Board.Options(opts) ); if (!isSupported(this.io)) { throw new Error( "Stepper is not supported" ); } if (!opts.pins) { throw new Error( "Stepper requires a `pins` object or array" ); } if (!opts.stepsPerRev) { throw new Error( "Stepper requires a `stepsPerRev` number value" ); } steppers.set(this.board, steppers.get(this.board) || []); this.id = steppers.get(this.board).length; if (this.id >= MAXSTEPPERS) { throw new Error( "Stepper cannot exceed max steppers (" + MAXSTEPPERS + ")" ); } // Convert an array of pins to the appropriate named pin if (Array.isArray(this.pins)) { if (this.pins.length === 2) { // Using an array of 2 pins requres a TYPE // to disambiguate DRIVER and TWO_WIRE if (!opts.type) { throw new Error( "Stepper requires a `type` number value (DRIVER, TWO_WIRE)" ); } } if (opts.type === Stepper.TYPE.DRIVER) { this.pins = { step: this.pins[0], dir: this.pins[1] }; } else { this.pins = new MotorPins(this.pins); } } // Attempt to guess the type if none is provided if (!opts.type) { if (this.pins.dir) { opts.type = Stepper.TYPE.DRIVER; } else { if (this.pins.motor3) { opts.type = Stepper.TYPE.FOUR_WIRE; } else { opts.type = Stepper.TYPE.TWO_WIRE; } } } // Initial Stepper config params (same for all 3 types) params.push(this.id, opts.type, opts.stepsPerRev); if (opts.type === Stepper.TYPE.DRIVER) { if (typeof this.pins.dir === "undefined" || typeof this.pins.step === "undefined") { throw new Error( "Stepper.TYPE.DRIVER expects: `pins.dir`, `pins.step`" ); } params.push( this.pins.dir, this.pins.step ); } if (opts.type === Stepper.TYPE.TWO_WIRE) { if (typeof this.pins.motor1 === "undefined" || typeof this.pins.motor2 === "undefined") { throw new Error( "Stepper.TYPE.TWO_WIRE expects: `pins.motor1`, `pins.motor2`" ); } params.push( this.pins.motor1, this.pins.motor2 ); } if (opts.type === Stepper.TYPE.FOUR_WIRE) { if (typeof this.pins.motor1 === "undefined" || typeof this.pins.motor2 === "undefined" || typeof this.pins.motor3 === "undefined" || typeof this.pins.motor4 === "undefined") { throw new Error( "Stepper.TYPE.FOUR_WIRE expects: `pins.motor1`, `pins.motor2`, `pins.motor3`, `pins.motor4`" ); } params.push( this.pins.motor1, this.pins.motor2, this.pins.motor3, this.pins.motor4 ); } // Iterate the params and set each pin's mode to MODES.STEPPER // Params: // [deviceNum, type, stepsPerRev, dirOrMotor1Pin, stepOrMotor2Pin, motor3Pin, motor4Pin] // The first 3 are required, the remaining 2-4 will be pins params.slice(3).forEach(function(pin) { this.io.pinMode(pin, this.io.MODES.STEPPER); }, this); this.io.stepperConfig.apply(this.io, params); steppers.get(this.board).push(this); state = Step.PROPERTIES.reduce(function(state, key, i) { return (state[key] = typeof opts[key] !== "undefined" ? opts[key] : Step.DEFAULTS[i], state); }, { isRunning: false, type: opts.type, pins: this.pins }); priv.set(this, state); Object.defineProperties(this, { type: { get: function() { return state.type; } }, pins: { get: function() { return state.pins; } } }); }
n/a
function Switch(opts) { if (!(this instanceof Switch)) { return new Switch(opts); } // Create a 5 ms debounce boundary on event triggers // this avoids button events firing on // press noise and false positives var trigger = Fn.debounce(function(key) { aliases[key].forEach(function(type) { this.emit(type, null); }, this); }, 5); // Resolve the default type to Normally Open opts.type = opts.type || "NO"; // Is this instance Normally Open? var isNormallyOpen = opts.type === "NO"; var raw = null; var invert = typeof opts.invert !== "undefined" ? opts.invert : (isNormallyOpen || false); // Logical Defaults var closeValue = 1; var openValue = 0; if (invert) { closeValue ^= 1; openValue ^= 1; } Board.Component.call( this, opts = Board.Options(opts) ); this.io.pinMode(this.pin, this.io.MODES.INPUT); if (isNormallyOpen) { this.io.digitalWrite(this.pin, this.io.HIGH); } this.io.digitalRead(this.pin, function(data) { raw = data; trigger.call(this, this.isOpen ? "open" : "close"); }.bind(this)); Object.defineProperties(this, { value: { get: function() { return Number(this.isOpen); } }, invert: { get: function() { return invert; }, set: function(value) { invert = value; closeValue = invert ? 0 : 1; openValue = invert ? 1 : 0; } }, closeValue: { get: function() { return closeValue; }, set: function(value) { closeValue = value; openValue = value ^ 1; } }, openValue: { get: function() { return openValue; }, set: function(value) { openValue = value; closeValue = value ^ 1; } }, isOpen: { get: function() { return raw === openValue; } }, isClosed: { get: function() { return raw === closeValue; } }, }); }
n/a
function Switches(numsOrObjects) { if (!(this instanceof Switches)) { return new Switches(numsOrObjects); } Object.defineProperty(this, "type", { value: Switch }); Collection.Emitter.call(this, numsOrObjects); }
n/a
function Thermometer(opts) { if (!(this instanceof Thermometer)) { return new Thermometer(opts); } var controller = null; var last = null; var raw = null; Board.Component.call( this, opts = Board.Options(opts) ); var freq = opts.freq || 25; // Analog Reference Voltage (default to board.io.aref || 5) this.aref = opts.aref || this.io.aref || 5; if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.ANALOG; } priv.set(this, {}); Board.Controller.call(this, controller, opts); if (!this.toCelsius) { this.toCelsius = opts.toCelsius || function(x) { return x; }; } var descriptors = { celsius: { get: function() { return this.toCelsius(raw); } }, fahrenheit: { get: function() { return toFixed((this.celsius * 9 / 5) + 32, 2); } }, kelvin: { get: function() { return toFixed(this.celsius + CELSIUS_TO_KELVIN, 2); } } }; // Convenience aliases descriptors.C = descriptors.celsius; descriptors.F = descriptors.fahrenheit; descriptors.K = descriptors.kelvin; Object.defineProperties(this, descriptors); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { raw = data; }); } setInterval(function() { if (raw == null) { return; } var data = {}; data.C = data.celsius = this.celsius; data.F = data.fahrenheit = this.fahrenheit; data.K = data.kelvin = this.kelvin; this.emit("data", data); if (this.celsius !== last) { last = this.celsius; this.emit("change", data); } }.bind(this), freq); }
n/a
function Thermometer(opts) { if (!(this instanceof Thermometer)) { return new Thermometer(opts); } var controller = null; var last = null; var raw = null; Board.Component.call( this, opts = Board.Options(opts) ); var freq = opts.freq || 25; // Analog Reference Voltage (default to board.io.aref || 5) this.aref = opts.aref || this.io.aref || 5; if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.ANALOG; } priv.set(this, {}); Board.Controller.call(this, controller, opts); if (!this.toCelsius) { this.toCelsius = opts.toCelsius || function(x) { return x; }; } var descriptors = { celsius: { get: function() { return this.toCelsius(raw); } }, fahrenheit: { get: function() { return toFixed((this.celsius * 9 / 5) + 32, 2); } }, kelvin: { get: function() { return toFixed(this.celsius + CELSIUS_TO_KELVIN, 2); } } }; // Convenience aliases descriptors.C = descriptors.celsius; descriptors.F = descriptors.fahrenheit; descriptors.K = descriptors.kelvin; Object.defineProperties(this, descriptors); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { raw = data; }); } setInterval(function() { if (raw == null) { return; } var data = {}; data.C = data.celsius = this.celsius; data.F = data.fahrenheit = this.fahrenheit; data.K = data.kelvin = this.kelvin; this.emit("data", data); if (this.celsius !== last) { last = this.celsius; this.emit("change", data); } }.bind(this), freq); }
n/a
function Keypad(opts) { if (!(this instanceof Keypad)) { return new Keypad(opts); } // Initialize a Device instance on a Board Board.Component.call( this, opts = Board.Options(opts) ); var raw = null; var controller = null; var state = { touches: null, timeout: null, length: null, keys: null, mapping: null, holdtime: null, }; var trigger = Fn.debounce(function(type, value) { var event = { type: type, which: value, timestamp: Date.now() }; aliases[type].forEach(function(type) { this.emit(type, event); }, this); this.emit("change", Object.assign({}, event)); }, 5); if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.ANALOG; } Board.Controller.call(this, controller, opts); state.holdtime = opts.holdtime ? opts.holdtime : 500; priv.set(this, state); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { raw = data; var now = Date.now(); var indices = this.toIndices(data); var kLength = state.length; var lists = { down: [], hold: [], up: [], }; var target = null; var alias = null; for (var k = 0; k < kLength; k++) { alias = this.toAlias(k); if (indices.includes(k)) { if (state.touches[k].value === 0) { state.touches[k].timeout = now + state.holdtime; lists.down.push(alias); } else if (state.touches[k].value === 1) { if (state.touches[k].timeout !== null && now > state.touches[k].timeout) { state.touches[k].timeout = now + state.holdtime; lists.hold.push(alias); } } state.touches[k].value = 1; } else { if (state.touches[k].value === 1) { state.touches[k].timeout = null; lists.up.push(alias); } state.touches[k].value = 0; } target = null; alias = null; } Object.keys(lists).forEach(function(key) { var list = lists[key]; if (list.length) { trigger.call(this, key, list); } }, this); }.bind(this)); } Object.defineProperties(this, { isMultitouch: { get: function() { return state.isMultitouch; } }, value: { get: function() { return raw; } }, }); }
n/a
function Wii(opts) { if (!(this instanceof Wii)) { return new Wii(opts); } Board.Component.call(this, opts); // Derive device definition from Devices var device = Devices[opts.device]; var address = device.address; var bytes = device.bytes; var delay = device.delay; var data = device.data.bind(this); var setup = device.setup; var preread = device.preread; // Wii controller instance properties this.freq = opts.freq || 100; // Button instance properties this.holdtime = opts.holdtime || 500; this.threshold = opts.threshold || 10; // Initialize components device.initialize.call(this); // Set initial "last data" byte array last.set(this, [0, 0, 0, 0, 0, 0, 0]); // Set up I2C data connection this.io.i2cConfig(opts); // Iterate and write each set of setup instructions setup.forEach(function(bytes) { this.io.i2cWrite(address, bytes); }, this); // Unthrottled i2c read request loop setInterval(function() { // Send this command to get all sensor data and store into // the 6-byte register within Wii controller. // This must be execute before reading data from the Wii. // Iterate and write each set of setup instructions preread.forEach(function(bytes) { this.io.i2cWrite(address, bytes); }, this); // Request six bytes of data from the controller this.io.i2cReadOnce(address, bytes, data); // Use the high-frequency data read loop as the change event // emitting loop. This drastically improves change event // frequency and sensitivity // // Emit change events if any delta is greater than // the threshold // RVL-005 does not have a read method at this time. if (typeof device.read !== "undefined") { device.read.call(this); } }.bind(this), delay || this.freq); // Throttled "read" event loop setInterval(function() { var event = new Board.Event({ target: this }); this.emit("data", event); }.bind(this), this.freq); }
n/a
function EVS(options) { if (shared) { return shared; } this.bank = { a: new Bank({ address: EVS.BANK_A, io: options.io, }), b: new Bank({ address: EVS.BANK_B, io: options.io, }) }; shared = this; }
n/a
function Orientation(opts) { if (!(this instanceof Orientation)) { return new Orientation(opts); } Board.Component.call( this, opts = Board.Options(opts) ); var freq = opts.freq || 25; var controller = null; var raw = null; var state = { euler: { heading: 0, roll: 0, pitch: 0, }, quarternion: { w: 0, x: 0, y: 0, z: 0, }, calibration: 0, }; if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller === null || typeof controller !== "object") { throw new Error("Missing valid Orientation controller"); } Board.Controller.call(this, controller, opts); if (!this.toScaledQuarternion) { this.toScaledQuarternion = opts.toScaledQuarternion || function(raw) { return raw; }; } if (!this.toScaledEuler) { this.toScaledEuler = opts.toScaledEuler || function(raw) { return raw; }; } priv.set(this, state); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { raw = data; }); } setInterval(function() { if (raw === null) { return; } var didOrientationChange = false; var didCalibrationChange = false; ["heading", "roll", "pitch"].forEach(function(el) { if (state.euler[el] !== raw.orientation.euler[el]) { didOrientationChange = true; } state.euler[el] = raw.orientation.euler[el]; }); ["w", "x", "y", "z"].forEach(function(el) { if (state.quarternion[el] !== raw.orientation.quarternion[el]) { didOrientationChange = true; } state.quarternion[el] = raw.orientation.quarternion[el]; }); //if we have a raw calibration state... // not sure if this is the best place... some devices may not have a calibration state... if (raw.calibration) { if (state.calibration !== raw.calibration) { didCalibrationChange = true; } state.calibration = raw.calibration; } var data = { euler: this.euler, quarternion: this.quarternion, calibration: this.calibration }; this.emit("data", data); if (didOrientationChange) { this.emit("change", data); } //not sure how we can get this event into other drivers if (didCalibrationChange) { this.emit("calibration", this.calibration); } }.bind(this), freq); }
n/a
function ReflectanceArray(opts) { if (!(this instanceof ReflectanceArray)) { return new ReflectanceArray(opts); } this.opts = Board.Options(opts); Board.Component.call( this, this.opts, { requestPin: false } ); // Read event throttling this.freq = opts.freq || 25; // Make private data entry var state = { lastLine: 0, isOn: false, calibration: { min: [], max: [] }, autoCalibrate: opts.autoCalibrate || false }; priv.set(this, state); initialize.call(this); Object.defineProperties(this, { isOn: { get: function() { return state.emitter.isOn; } }, isCalibrated: { get: function() { return calibrationIsValid(this.calibration, this.sensors); } }, isOnLine: { get: function() { var line = this.line; return line > CALIBRATED_MIN_VALUE && line < maxLineValue.call(this); } }, sensors: { get: function() { return state.sensorStates.map(function(sensorState) { return sensorState.sensor; }); } }, calibration: { get: function() { return state.calibration; } }, raw: { get: function() { return state.sensorStates.map(function(sensorState) { return sensorState.rawValue; }); } }, values: { get: function() { return this.isCalibrated ? calibratedValues.call(this) : this.raw; } }, line: { get: function() { return this.isCalibrated ? getLine.call(this) : 0; } } }); }
n/a
function Accelerometer(opts) {
if (!(this instanceof Accelerometer)) {
return new Accelerometer(opts);
}
var controller = null;
var state = {
enabled: true,
x: {
value: 0,
previous: 0,
stash: [],
orientation: null,
inclination: null,
acceleration: null,
calibration: []
},
y: {
value: 0,
previous: 0,
stash: [],
orientation: null,
inclination: null,
acceleration: null,
calibration: []
},
z: {
value: 0,
previous: 0,
stash: [],
orientation: null,
inclination: null,
acceleration: null,
calibration: []
}
};
Board.Component.call(
this, opts = Board.Options(opts)
);
if (opts.controller && typeof opts.controller === "string") {
controller = Controllers[opts.controller.toUpperCase()];
} else {
controller = opts.controller;
}
if (controller == null) {
controller = Controllers.ANALOG;
}
Board.Controller.call(this, controller, opts);
if (!this.toGravity) {
this.toGravity = opts.toGravity || function(raw) {
return raw;
};
}
if (!this.enabledChanged) {
this.enabledChanged = function() {};
}
priv.set(this, state);
/* istanbul ignore else */
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
var isChange = false;
if (!state.enabled) {
return;
}
Object.keys(data).forEach(function(axis) {
var value = data[axis];
var sensor = state[axis];
if (opts.autoCalibrate && sensor.calibration.length < calibrationSize) {
var axisIndex = axes.indexOf(axis);
sensor.calibration.push(value);
if (!Array.isArray(state.zeroV)) {
state.zeroV = [];
}
state.zeroV[axisIndex] = sum(sensor.calibration) / sensor.calibration.length;
if (axis === aZ) {
state.zeroV[axisIndex] -= state.sensitivity;
}
}
// The first run needs to prime the "stash"
// of data values.
if (sensor.stash.length === 0) {
for (var i = 0; i < 5; i++) {
sensor.stash[i] = value;
}
}
sensor.previous = sensor.value;
sensor.stash.shift();
sensor.stash.push(value);
sensor.value = (sum(sensor.stash) / 5) | 0;
if (this.acceleration !== sensor.acceleration) {
sensor.acceleration = this.acceleration;
isChange = true;
this.emit("acceleration", sensor.acceleration);
}
if (this.orientation !== sensor.orientation) {
sensor.orientation = this.orientation;
isChange = true;
this.emit("orientation", sensor.orientation);
}
if (this.inclination !== sensor.inclination) {
sensor.inclination = this.inclination;
isChange = true;
this.emit("inclination", sensor.inclination);
}
}, this);
this.emit("data", {
x: state.x.value,
y: state.y.value,
z: state.z.value
});
if (isChange) {
this.emit("change", {
x: this.x,
y: this.y,
z: this.z
});
}
}.bind(this));
}
Object.defineProperties(this, {
hasAxis: {
writable: true,
value: function(axis) {
/* istanbul ignore next */
return state[axis] ? state[axis].stash.length > 0 : false;
}
},
enable: {
value: function() {
state.enabled = true;
this.enabledChanged(true);
return this;
}
},
disable: {
value: function() {
state.enabled = false;
this.enabledChanged(false);
return this;
}
},
zeroV: {
get: function() {
return state.zeroV;
}
},
/**
* [read-only] Calculated pitch value
* @property pitch
* @type Number
*/
pitch: {
get: function() {
var x = this.x;
var y = this.y;
var z = this.z;
var r ...
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function Altimeter(opts) {
if (!(this instanceof Altimeter)) {
return new Altimeter(opts);
}
var controller = null;
var freq;
var last = null;
var raw = null;
var state = {};
Board.Component.call(
this, opts = Board.Options(opts)
);
freq = opts.freq || 25;
if (opts.controller && typeof opts.controller === "string") {
controller = Controllers[opts.controller.toUpperCase()];
} else {
controller = opts.controller;
}
if (controller == null) {
throw new Error("Altimeter expects a valid controller");
}
priv.set(this, state);
Board.Controller.call(this, controller, opts);
if (!this.toMeters) {
this.toMeters = opts.toMeters || function(x) {
return x;
};
}
var descriptors = {
meters: {
get: function() {
return this.toMeters(raw);
}
},
feet: {
get: function() {
return Fn.toFixed(this.meters * 3.28084, 2);
}
}
};
// Convenience aliases
descriptors.m = descriptors.meters;
descriptors.ft = descriptors.feet;
Object.defineProperties(this, descriptors);
/* istanbul ignore else */
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
raw = data;
});
}
setInterval(function() {
if (raw == null) {
return;
}
var data = {};
data.m = data.meters = this.meters;
data.ft = data.feet = this.feet;
this.emit("data", data);
/* istanbul ignore else */
if (this.meters !== last) {
last = this.meters;
this.emit("change", data);
}
}.bind(this), freq);
}
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function Animation(target) { // Necessary to avoid loading temporal unless necessary if (!temporal) { temporal = require("temporal"); } if (!(this instanceof Animation)) { return new Animation(target); } Animation.Segment.call(this); this.defaultTarget = target; }
n/a
Segment = function (options) { this.cuePoints = [0, 1]; this.duration = 1000; this.easing = "linear"; this.loop = false; this.loopback = 0; this.metronomic = false; this.currentSpeed = 1; this.progress = 0; this.fps = 60; this.rate = 1000 / 60; this.paused = false; this.segments = []; this.onstart = null; this.onpause = null; this.onstop = null; this.oncomplete = null; this.onloop = null; if (options) { Object.assign(this, options); if (options.segments) { this.segments = options.segments.slice(); } } }
n/a
TemporalFallback = function (animation) { this.interval = setInterval(function() { animation.loopFunction({ calledAt: Date.now() }); }, animation.rate); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
TemporalFallback = function (animation) { this.interval = setInterval(function() { animation.loopFunction({ calledAt: Date.now() }); }, animation.rate); }
n/a
stop = function () { if (this.interval) { clearInterval(this.interval); } }
n/a
calculateProgress = function (calledAt) { var progress = (calledAt - this.startTime) / this.scaledDuration; if (progress > 1) { progress = 1; } this.progress = progress; if (this.reverse) { progress = 1 - progress; } // Ease the timeline // to do: When reverse replace inFoo with outFoo and vice versa. skip inOutFoo progress = ease[this.easing](progress); progress = Fn.constrain(progress, 0, 1); return progress; }
n/a
enqueue = function (opts) {
opts = opts || {};
/* istanbul ignore else */
if (typeof opts.target === "undefined") {
opts.target = this.defaultTarget;
}
this.segments.push(new Animation.Segment(opts));
/* istanbul ignore if */
if (!this.paused) {
this.next();
}
return this;
}
n/a
findIndices = function (progress) { var indices = { left: null, right: null }; // Find our current before and after cuePoints indices.right = this.cuePoints.findIndex(function(point) { return point >= progress; }); indices.left = indices.right === 0 ? /* istanbul ignore next */ 0 : indices.right - 1; return indices; }
n/a
loopFunction = function (loop) {
// Find the current timeline progress
var progress = this.calculateProgress(loop.calledAt);
// Find the left and right cuePoints/keyFrames;
var indices = this.findIndices(progress);
// call render function with tweened value
this.target[Animation.render](this.tweenedValue(indices, progress));
/**
* If this animation has been running in temporal for too long
* fall back to using setInterval so we don't melt the user's CPU
**/
if (loop.calledAt > this.fallBackTime) {
this.fallBackTime = Infinity;
if (this.playLoop) {
this.playLoop.stop();
}
this.playLoop = new Animation.TemporalFallback(this);
}
// See if we have reached the end of the animation
/* istanbul ignore else */
if ((this.progress === 1 && !this.reverse) || (progress === this.loopback && this.reverse)) {
if (this.loop || (this.metronomic && !this.reverse)) {
if (this.onloop) {
this.onloop();
}
if (this.metronomic) {
this.reverse = this.reverse ? false : true;
}
this.normalizeKeyframes();
this.progress = this.loopback;
this.startTime = Date.now() - this.scaledDuration * this.progress;
this.endTime = this.startTime + this.scaledDuration;
} else {
this.stop();
if (this.oncomplete) {
process.nextTick(this.oncomplete.bind(this));
}
if (this.segments.length > 0) {
this.next();
}
}
}
}
n/a
next = function () { if (this.segments.length > 0) { Object.assign(this, this.segments.shift()); this.paused = this.currentSpeed === 0 ? true : false; if (this.onstart) { this.onstart(); } this.normalizeKeyframes(); if (this.reverse) { this.currentSpeed *= -1; } if (this.currentSpeed !== 0) { this.play(); } else { this.paused = true; } } else { this.playLoop.stop(); } return this; }
n/a
normalizeKeyframes = function () {
var previousVal,
keyFrameSet = Fn.cloneDeep(this.keyFrames),
cuePoints = this.cuePoints;
// Run through the target's normalization
keyFrameSet = this.target[Animation.normalize](keyFrameSet);
// keyFrames can be passed as a single dimensional array if
// there is just one servo/device. If the first element is not an
// array, nest keyFrameSet so we only have to deal with one format
if (!Array.isArray(keyFrameSet[0])) {
keyFrameSet = [keyFrameSet];
}
keyFrameSet.forEach(function(keyFrames) {
// Pad the right side of keyFrames arrays with null
for (var i = keyFrames.length; i < cuePoints.length; i++) {
keyFrames.push(null);
}
keyFrames.forEach(function(keyFrame, i, source) {
if (keyFrame !== null) {
// keyFrames need to be converted to objects
if (typeof keyFrame !== "object") {
keyFrame = {
step: keyFrame,
easing: "linear"
};
}
// Replace step values
if (typeof keyFrame.step !== "undefined") {
keyFrame.value = keyFrame.step === false ?
previousVal : previousVal + keyFrame.step;
}
// Set a default easing function
if (!keyFrame.easing) {
keyFrame.easing = "linear";
}
// Copy value from another frame
/* istanbul ignore if */
if (typeof keyFrame.copyValue !== "undefined") {
keyFrame.value = source[keyFrame.copyValue].value;
}
// Copy everything from another keyframe in this array
/* istanbul ignore if */
if (keyFrame.copyFrame) {
keyFrame = source[keyFrame.copyFrame];
}
previousVal = keyFrame.value;
} else {
if (i === source.length - 1) {
keyFrame = {
value: previousVal,
easing: "linear"
};
} else {
keyFrame = null;
}
}
source[i] = keyFrame;
}, this);
});
this.normalizedKeyFrames = keyFrameSet;
return this;
}
n/a
pause = function () { this.emit("animation:pause"); if (this.playLoop) { this.playLoop.stop(); } this.paused = true; if (this.onpause) { this.onpause(); } }
n/a
play = function () {
var now = Date.now();
if (this.playLoop) {
this.playLoop.stop();
}
this.paused = false;
// Find our timeline endpoints and refresh rate
this.scaledDuration = this.duration / Math.abs(this.currentSpeed);
this.startTime = now - this.scaledDuration * this.progress;
this.endTime = this.startTime + this.scaledDuration;
// If our animation runs for more than 5 seconds switch to setTimeout
this.fallBackTime = now + temporalTTL;
this.frameCount = 0;
/* istanbul ignore else */
if (this.fps) {
this.rate = 1000 / this.fps;
}
this.rate = this.rate | 0;
this.playLoop = temporal.loop(this.rate, this.loopFunction.bind(this));
}
n/a
speed = function (speed) { if (typeof speed === "undefined") { return this.currentSpeed; } else { this.currentSpeed = speed; // Find our timeline endpoints and refresh rate this.scaledDuration = this.duration / Math.abs(this.currentSpeed); this.startTime = Date.now() - this.scaledDuration * this.progress; this.endTime = this.startTime + this.scaledDuration; if (!this.paused) { this.play(); } return this; } }
n/a
stop = function () { this.emit("animation:stop"); this.segments = []; if (this.playLoop) { this.playLoop.stop(); } if (this.onstop) { this.onstop(); } }
n/a
tweenedValue = function (indices, progress) {
var tween = {
duration: null,
progress: null
};
var result = this.normalizedKeyFrames.map(function(keyFrame) {
// Note: "this" is bound to the animation object
var memberIndices = {
left: null,
right: null
};
// If the keyframe at indices.left is null, move left
for (memberIndices.left = indices.left; memberIndices.left > -1; memberIndices.left--) {
/* istanbul ignore else */
if (keyFrame[memberIndices.left] !== null) {
break;
}
}
// If the keyframe at indices.right is null, move right
memberIndices.right = keyFrame.findIndex(function(frame, index) {
return index >= indices.right && frame !== null;
});
// Find our progress for the current tween
tween.duration = this.cuePoints[memberIndices.right] - this.cuePoints[memberIndices.left];
tween.progress = (progress - this.cuePoints[memberIndices.left]) / tween.duration;
// Catch divide by zero
if (!Number.isFinite(tween.progress)) {
/* istanbul ignore next */
tween.progress = this.reverse ? 0 : 1;
}
var left = keyFrame[memberIndices.left],
right = keyFrame[memberIndices.right];
// Apply tween easing to tween.progress
// to do: When reverse replace inFoo with outFoo and vice versa. skip inOutFoo
tween.progress = ease[right.easing](tween.progress);
// Calculate this tween value
var calcValue;
if (right.position) {
// This is a tuple
calcValue = right.position.map(function(value, index) {
return (value - left.position[index]) *
tween.progress + left.position[index];
});
} else {
if (typeof right.value === "number" && typeof left.value === "number") {
calcValue = (right.value - left.value) * tween.progress + left.value;
} else {
calcValue = this.target[Animation.keys].reduce(function(accum, key) {
accum[key] = (right.value[key] - left.value[key]) * tween.progress + left.value[key];
return accum;
}, {});
}
}
return calcValue;
}, this);
return result;
}
n/a
function Barometer(opts) { if (!(this instanceof Barometer)) { return new Barometer(opts); } var controller = null; var last = null; var raw = null; Board.Component.call( this, opts = Board.Options(opts) ); var freq = opts.freq || 25; if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { // controller = Controllers["ANALOG"]; throw new Error("Missing Barometer controller"); } Board.Controller.call(this, controller, opts); if (!this.toPressure) { this.toPressure = opts.toPressure || function(raw) { return raw; }; } if (typeof this.initialize === "function") { this.initialize(opts, function(data) { raw = data; }); } Object.defineProperties(this, { pressure: { get: function() { return toFixed(this.toPressure(raw), 4); } } }); setInterval(function() { if (raw === null) { return; } var data = { pressure: this.pressure }; this.emit("data", data); if (this.pressure !== last) { last = this.pressure; this.emit("change", data); } }.bind(this), freq); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function Board(opts) {
if (!(this instanceof Board)) {
return new Board(opts);
}
// Ensure opts is an object
opts = opts || {};
// Used to define the board instance's own
// properties in the REPL's scope.
var replContext = {};
// It's feasible that an IO-Plugin may emit
// "connect" and "ready" events out of order.
// This is used to enforce the order, by
// postponing the "ready" event if the IO-Plugin
// hasn't emitted a "connect" event. Once
// the "connect" event is emitted, the
// postponement is lifted and the board may
// proceed with emitting the events in the
// correct order.
var isPostponed = false;
// Initialize this Board instance with
// param specified properties.
Object.assign(this, opts);
this.timer = null;
this.isConnected = false;
// Easily track state of hardware
this.isReady = false;
// Initialize instance property to reference io board
this.io = this.io || null;
// Registry of components
this.register = [];
// Pins, Addr (alt Pin name), Addresses
this.occupied = [];
// Registry of drivers by address (i.e. I2C Controllers)
this.Drivers = {};
// Identify for connect hardware cache
if (!this.id) {
this.id = Fn.uid();
}
// If no debug flag, default to true
if (typeof this.debug === UNDEFINED) {
this.debug = true;
}
// If no repl flag, default to true
if (typeof this.repl === UNDEFINED) {
this.repl = true;
}
// If no sigint flag, default to true
if (typeof this.sigint === UNDEFINED) {
this.sigint = true;
}
// Specially processed pin capabilities object
// assigned when physical board has reported
// "ready" via Firmata or IO-Plugin.
this.pins = null;
// Create a Repl instance and store as
// instance property of this io/board.
// This will reduce the amount of boilerplate
// code required to _always_ have a Repl
// session available.
//
// If a sesssion exists, use it
// (instead of creating a new session)
//
/* istanbul ignore if */
if (this.repl) {
/* istanbul ignore if */
if (Repl.ref) {
/* istanbul ignore next */
replContext[this.id] = this;
/* istanbul ignore next */
Repl.ref.on("ready", function() {
/* istanbul ignore next */
Repl.ref.inject(replContext);
});
/* istanbul ignore next */
this.repl = Repl.ref;
} else {
replContext[this.id] = replContext.board = this;
this.repl = new Repl(replContext);
}
}
if (opts.io) {
// If you already have a connected io instance
this.io = opts.io;
this.isReady = opts.io.isReady;
this.transport = this.io.transport || null;
this.port = this.io.name;
this.pins = Board.Pins(this);
} else {
if (this.port && opts.port) {
Serial.connect.call(this, this.port, finalizeAndBroadcast);
} else {
Serial.detect.call(this, function(path) {
Serial.connect.call(this, path, finalizeAndBroadcast);
});
}
}
// Either an IO instance was provided or isOnBoard is true
if (!opts.port && this.io !== null) {
/* istanbul ignore next */
this.info("Available", chalk.grey(this.io.name || "unknown"));
["connect", "ready"].forEach(function(type) {
this.io.once(type, function() {
// Since connection and readiness happen asynchronously,
// it's actually possible for Johnny-Five to receive the
// events out of order and that should be ok.
if (type === "ready" && !this.isConnected) {
isPostponed = true;
} else {
// Will emit the "connect" and "ready" events
// if received in order. If out of order, this
// will only emit the "connect" event. The
// "ready" event will be handled in the next
// condition's consequent.
finalizeAndBroadcast.call(this, null, type, this.io);
}
if (type === "connect" && isPostponed) {
finalizeAndBroadcast.call(this, null, "ready", this.io);
}
}.bind(this));
if (this.io.isReady) { ...
...
## Hello Johnny
The ubiquitous "Hello World" program of the microcontroller and SoC world is "blink an LED". The following code
demonstrates how this is done using the Johnny-Five framework.
```javascript
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
...
function Boards(opts) {
if (!(this instanceof Boards)) {
return new Boards(opts);
}
var ports;
// new Boards([ ...Array of board opts ])
if (Array.isArray(opts)) {
ports = opts.slice();
opts = {
ports: ports,
};
}
// new Boards({ ports: [ ...Array of board opts ], .... })
/* istanbul ignore else */
if (!Array.isArray(opts) && typeof opts === "object" && opts.ports !== undefined) {
ports = opts.ports;
}
// new Boards(non-Array?)
// new Boards({ ports: non-Array? })
/* istanbul ignore if */
if (!Array.isArray(ports)) {
throw new Error("Expected ports to be an array");
}
if (typeof opts.debug === UNDEFINED) {
opts.debug = true;
}
if (typeof opts.repl === UNDEFINED) {
opts.repl = true;
}
var initialized = {};
var noRepl = ports.some(function(port) { return port.repl === false; });
var noDebug = ports.some(function(port) { return port.debug === false; });
this.length = ports.length;
this.debug = opts.debug;
this.repl = opts.repl;
// If any of the port definitions have
// explicitly shut off debug output, bubble up
// to the Boards instance
/* istanbul ignore else */
if (noDebug) {
this.debug = false;
}
// If any of the port definitions have
// explicitly shut off the repl, bubble up
// to the Boards instance
/* istanbul ignore else */
if (noRepl) {
this.repl = false;
}
var expecteds = ports.map(function(port, index) {
var portOpts;
if (typeof port === "string") {
portOpts = {};
// If the string matches a known valid port
// name pattern, then assume this is what
// the user code intended.
if (rport.test(port)) {
portOpts.port = port;
} else {
// Otherwise they expect Johnny-Five to figure
// out what ports to use and intended this
// value to be used an id
portOpts.id = port;
}
} else {
portOpts = port;
}
// Shut off per-board repl instance creation
portOpts.repl = false;
this[index] = initialized[portOpts.id] = new Board(portOpts);
// "error" event is not async, register immediately
this[index].on("error", function(error) {
this.emit("error", error);
}.bind(this));
return new Promise(function(resolve) {
this[index].on("ready", function() {
resolve(initialized[portOpts.id]);
});
}.bind(this));
}, this);
Promise.all(expecteds).then(function(boards) {
Object.assign(this, boards);
this.each(function(board) {
board.info("Board ID: ", chalk.green(board.id));
});
// If the Boards instance requires a REPL,
// make sure it's created before calling "ready"
if (this.repl) {
this.repl = new Repl(
Object.assign({}, initialized, {
board: this
})
);
this.repl.initialize(function() {
this.emit("ready", initialized);
}.bind(this));
} else {
// Otherwise, call ready immediately
this.emit("ready", initialized);
}
}.bind(this));
}
n/a
function Boards(opts) {
if (!(this instanceof Boards)) {
return new Boards(opts);
}
var ports;
// new Boards([ ...Array of board opts ])
if (Array.isArray(opts)) {
ports = opts.slice();
opts = {
ports: ports,
};
}
// new Boards({ ports: [ ...Array of board opts ], .... })
/* istanbul ignore else */
if (!Array.isArray(opts) && typeof opts === "object" && opts.ports !== undefined) {
ports = opts.ports;
}
// new Boards(non-Array?)
// new Boards({ ports: non-Array? })
/* istanbul ignore if */
if (!Array.isArray(ports)) {
throw new Error("Expected ports to be an array");
}
if (typeof opts.debug === UNDEFINED) {
opts.debug = true;
}
if (typeof opts.repl === UNDEFINED) {
opts.repl = true;
}
var initialized = {};
var noRepl = ports.some(function(port) { return port.repl === false; });
var noDebug = ports.some(function(port) { return port.debug === false; });
this.length = ports.length;
this.debug = opts.debug;
this.repl = opts.repl;
// If any of the port definitions have
// explicitly shut off debug output, bubble up
// to the Boards instance
/* istanbul ignore else */
if (noDebug) {
this.debug = false;
}
// If any of the port definitions have
// explicitly shut off the repl, bubble up
// to the Boards instance
/* istanbul ignore else */
if (noRepl) {
this.repl = false;
}
var expecteds = ports.map(function(port, index) {
var portOpts;
if (typeof port === "string") {
portOpts = {};
// If the string matches a known valid port
// name pattern, then assume this is what
// the user code intended.
if (rport.test(port)) {
portOpts.port = port;
} else {
// Otherwise they expect Johnny-Five to figure
// out what ports to use and intended this
// value to be used an id
portOpts.id = port;
}
} else {
portOpts = port;
}
// Shut off per-board repl instance creation
portOpts.repl = false;
this[index] = initialized[portOpts.id] = new Board(portOpts);
// "error" event is not async, register immediately
this[index].on("error", function(error) {
this.emit("error", error);
}.bind(this));
return new Promise(function(resolve) {
this[index].on("ready", function() {
resolve(initialized[portOpts.id]);
});
}.bind(this));
}, this);
Promise.all(expecteds).then(function(boards) {
Object.assign(this, boards);
this.each(function(board) {
board.info("Board ID: ", chalk.green(board.id));
});
// If the Boards instance requires a REPL,
// make sure it's created before calling "ready"
if (this.repl) {
this.repl = new Repl(
Object.assign({}, initialized, {
board: this
})
);
this.repl.initialize(function() {
this.emit("ready", initialized);
}.bind(this));
} else {
// Otherwise, call ready immediately
this.emit("ready", initialized);
}
}.bind(this));
}
n/a
Component = function (opts, componentOpts) {
if (typeof opts === UNDEFINED) {
opts = {};
}
if (typeof componentOpts === UNDEFINED) {
componentOpts = {};
}
// Board specific properties
this.board = Board.mount(opts);
this.io = this.board.io;
// Component/Module instance properties
this.id = opts.id || Board.uid();
this.custom = opts.custom || {};
var originalPins;
if (typeof opts.pin === "number" || typeof opts.pin === "string") {
originalPins = [opts.pin];
} else {
if (Array.isArray(opts.pins)) {
originalPins = opts.pins.slice();
} else {
if (typeof opts.pins === "object" && opts.pins !== null) {
var pinset = opts.pins || opts.pin;
originalPins = [];
for (var p in pinset) {
originalPins.push(pinset[p]);
}
}
}
}
if (opts.controller) {
if (typeof opts.controller === "string") {
opts.controller = opts.controller.replace(/-/g, "");
}
if (!Expander) {
Expander = require("./expander");
}
if (Expander.hasController(opts.controller)) {
componentOpts = {
normalizePin: false,
requestPin: false,
};
}
}
componentOpts = Board.Component.initialization(componentOpts);
if (componentOpts.normalizePin) {
opts = Board.Pins.normalize(opts, this.board);
}
// var requesting = [];
if (typeof opts.pins !== UNDEFINED) {
this.pins = opts.pins || [];
// if (Array.isArray(this.pins)) {
// requesting = requesting.concat(
// this.pins.map(function(pin) {
// return {
// value: pin,
// type: "pin"
// };
// })
// );
// } else {
// requesting = requesting.concat(
// Object.keys(this.pins).map(function(key) {
// return {
// value: this.pins[key],
// type: "pin"
// };
// }, this)
// );
// }
}
if (typeof opts.pin !== UNDEFINED) {
this.pin = opts.pin;
// requesting.push({
// value: this.pin,
// type: "pin"
// });
}
// TODO: Figure out what is using this
/* istanbul ignore if */
if (typeof opts.emitter !== UNDEFINED) {
/* istanbul ignore next */
this.emitter = opts.emitter;
// requesting.push({
// value: this.emitter,
// type: "emitter"
// });
}
if (typeof opts.address !== UNDEFINED) {
this.address = opts.address;
// requesting.forEach(function(request) {
// request.address = this.address;
// }, this);
}
if (typeof opts.controller !== UNDEFINED) {
this.controller = opts.controller;
// requesting.forEach(function(request) {
// request.controller = this.controller;
// }, this);
}
// TODO: Figure out what is using this
/* istanbul ignore if */
if (typeof opts.bus !== UNDEFINED) {
/* istanbul ignore next */
this.bus = opts.bus;
// requesting.forEach(function(request) {
// request.bus = this.bus;
// }, this);
}
// if (componentOpts.requestPin) {
// // With the pins being requested for use by this component,
// // compare with the list of pins that are already known to be
// // in use by other components. If any are known to be in use,
// // produce a warning for the user.
// requesting.forEach(function(request, index) {
// var hasController = typeof request.controller !== UNDEFINED;
// var hasAddress = typeof request.address !== UNDEFINED;
// var isOccupied = false;
// var message = "";
// request.value = originalPins[index];
// if (this.board.occupied.length) {
// isOccupied = this.board.occupied.some(function(occupied) {
// var isPinOccupied = request.value === occupied.value && request.type === occupied.type;
// if (typeof occupied.controller !== UNDEFINED) {
// if (hasController) {
// return isPinOccupied && (request.controller === occupied.controller);
// }
// return false;
// }
// if (typeof occupied.addre ...
n/a
Controller = function (controller, options) {
var requirements = controller.requirements && controller.requirements.value;
if (requirements) {
/* istanbul ignore else */
if (requirements.options) {
Object.keys(requirements.options).forEach(function(key) {
/*
requirements: {
value: {
options: {
parameterName: {
throws: false,
message: "...blah blah blah",
typeof: "number",
}
}
}
},
*/
if (typeof options[key] === UNDEFINED ||
typeof options[key] !== requirements.options[key].typeof) {
if (requirements.options[key].throws) {
throw new Error(requirements.options[key].message);
} else {
this.board.warn(this.constructor.name, requirements.options[key].message);
}
}
}, this);
}
}
Object.defineProperties(this, controller);
}
n/a
Event = function (event) { if (typeof event === UNDEFINED) { throw new Error("Board.Event missing Event object"); } // default event is read this.type = event.type || "data"; // actual target instance this.target = event.target || null; // Initialize this Board instance with // param specified properties. Object.assign(this, event); }
n/a
function Options(arg) { if (!(this instanceof Options)) { return new Options(arg); } var opts = {}; if (typeof arg === "number" || typeof arg === "string") { opts.pin = arg; } else if (Array.isArray(arg)) { opts.pins = arg; } else { opts = arg; // @Nick, this is where you want to focus. // Anytime this path is taken, the constructor // received an object. If the object contains // a "pins" property that is ALSO an object, we need // to normalize the keys of that object, using the // "aliases" map defined above. // // This change will require renaming pin properties in // a few classes, but I'm ok with that, because if we do this // right, no existing code will break. // } Object.assign(this, opts); }
...
function Orientation(opts) {
if (!(this instanceof Orientation)) {
return new Orientation(opts);
}
Board.Component.call(
this, opts = Board.Options(opts)
);
var freq = opts.freq || 25;
var controller = null;
var raw = null;
var state = {
euler: {
...
function Pins(board) { if (!(this instanceof Pins)) { return new Pins(board); } var io = board.io; var pins = io.pins.slice(); var length = pins.length; var type = pinsToType[length] || "OTHER"; board.type = type; // Copy pin data to index for (var i = 0; i < length; i++) { this[i] = pins[i]; } Object.defineProperties(this, { type: { value: type }, length: { value: length } }); // If an IO Plugin or Expander defines // these, override the default [ "isInput", "isOutput", "isAnalog", "isPwm", "isServo", ].forEach(function(isType) { if (io[isType]) { this[isType] = io[isType]; } }, this); }
n/a
Virtual = function (opts) { var temp; if (opts instanceof module.exports.Expander) { temp = { io: opts }; } else { temp = opts; } return new module.exports.Board( Object.assign({}, { repl: false, debug: false, sigint: false }, temp) ); }
n/a
constrain = function (value, lower, upper) { return Math.min(upper, Math.max(lower, value)); }
...
function calibratedValues() {
return this.raw.map(function(value, i) {
var max = this.calibration.max[i],
min = this.calibration.min[i];
var scaled = __.scale(value, min, max, CALIBRATED_MIN_VALUE, CALIBRATED_MAX_VALUE);
return __.constrain(scaled, CALIBRATED_MIN_VALUE, CALIBRATED_MAX_VALUE);
}, this);
}
function maxLineValue() {
return (this.sensors.length - 1) * CALIBRATED_MAX_VALUE;
}
...
fmap = function (value, fromLow, fromHigh, toLow, toHigh) { f32A[0] = (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow; return f32A[0]; }
n/a
map = function (value, fromLow, fromHigh, toLow, toHigh) { return ((value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow) | 0; }
...
}
state.emitter = new Led({
board: this.board,
pin: this.opts.emitter
});
state.sensorStates = this.pins.map(function(pin) {
var sensorState = {
sensor: new Sensor({
board: this.board,
freq: this.freq,
pin: pin
}),
rawValue: 0,
...
mount = function (arg) { var index = typeof arg === "number" && arg, hardware; // board was explicitly provided if (arg && arg.board) { return arg.board; } // index specified, attempt to return // hardware instance. Return null if not // found or not available if (typeof index === "number") { hardware = boards[index]; return hardware && hardware || null; } // If no arg specified and hardware instances // exist in the cache if (boards.length) { return boards[0]; } // No mountable hardware return null; }
n/a
range = function (lower, upper, tick) { if (arguments.length === 1) { upper = lower - 1; lower = 0; } lower = lower || 0; upper = upper || 0; tick = tick || 1; var len = Math.max(Math.ceil((upper - lower) / tick), 0), idx = 0, range = []; while (idx <= len) { range[idx++] = lower; lower += tick; } return range; }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
uid = function () { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(chr) { var rnd = Math.random() * 16 | 0; return (chr === "x" ? rnd : (rnd & 0x3 | 0x8)).toString(16); }).toUpperCase(); }
n/a
Component = function (opts, componentOpts) {
if (typeof opts === UNDEFINED) {
opts = {};
}
if (typeof componentOpts === UNDEFINED) {
componentOpts = {};
}
// Board specific properties
this.board = Board.mount(opts);
this.io = this.board.io;
// Component/Module instance properties
this.id = opts.id || Board.uid();
this.custom = opts.custom || {};
var originalPins;
if (typeof opts.pin === "number" || typeof opts.pin === "string") {
originalPins = [opts.pin];
} else {
if (Array.isArray(opts.pins)) {
originalPins = opts.pins.slice();
} else {
if (typeof opts.pins === "object" && opts.pins !== null) {
var pinset = opts.pins || opts.pin;
originalPins = [];
for (var p in pinset) {
originalPins.push(pinset[p]);
}
}
}
}
if (opts.controller) {
if (typeof opts.controller === "string") {
opts.controller = opts.controller.replace(/-/g, "");
}
if (!Expander) {
Expander = require("./expander");
}
if (Expander.hasController(opts.controller)) {
componentOpts = {
normalizePin: false,
requestPin: false,
};
}
}
componentOpts = Board.Component.initialization(componentOpts);
if (componentOpts.normalizePin) {
opts = Board.Pins.normalize(opts, this.board);
}
// var requesting = [];
if (typeof opts.pins !== UNDEFINED) {
this.pins = opts.pins || [];
// if (Array.isArray(this.pins)) {
// requesting = requesting.concat(
// this.pins.map(function(pin) {
// return {
// value: pin,
// type: "pin"
// };
// })
// );
// } else {
// requesting = requesting.concat(
// Object.keys(this.pins).map(function(key) {
// return {
// value: this.pins[key],
// type: "pin"
// };
// }, this)
// );
// }
}
if (typeof opts.pin !== UNDEFINED) {
this.pin = opts.pin;
// requesting.push({
// value: this.pin,
// type: "pin"
// });
}
// TODO: Figure out what is using this
/* istanbul ignore if */
if (typeof opts.emitter !== UNDEFINED) {
/* istanbul ignore next */
this.emitter = opts.emitter;
// requesting.push({
// value: this.emitter,
// type: "emitter"
// });
}
if (typeof opts.address !== UNDEFINED) {
this.address = opts.address;
// requesting.forEach(function(request) {
// request.address = this.address;
// }, this);
}
if (typeof opts.controller !== UNDEFINED) {
this.controller = opts.controller;
// requesting.forEach(function(request) {
// request.controller = this.controller;
// }, this);
}
// TODO: Figure out what is using this
/* istanbul ignore if */
if (typeof opts.bus !== UNDEFINED) {
/* istanbul ignore next */
this.bus = opts.bus;
// requesting.forEach(function(request) {
// request.bus = this.bus;
// }, this);
}
// if (componentOpts.requestPin) {
// // With the pins being requested for use by this component,
// // compare with the list of pins that are already known to be
// // in use by other components. If any are known to be in use,
// // produce a warning for the user.
// requesting.forEach(function(request, index) {
// var hasController = typeof request.controller !== UNDEFINED;
// var hasAddress = typeof request.address !== UNDEFINED;
// var isOccupied = false;
// var message = "";
// request.value = originalPins[index];
// if (this.board.occupied.length) {
// isOccupied = this.board.occupied.some(function(occupied) {
// var isPinOccupied = request.value === occupied.value && request.type === occupied.type;
// if (typeof occupied.controller !== UNDEFINED) {
// if (hasController) {
// return isPinOccupied && (request.controller === occupied.controller);
// }
// return false;
// }
// if (typeof occupied.addre ...
n/a
initialization = function (opts) { var defaults = { requestPin: true, normalizePin: true }; return Object.assign({}, defaults, opts); }
n/a
function Pins(board) { if (!(this instanceof Pins)) { return new Pins(board); } var io = board.io; var pins = io.pins.slice(); var length = pins.length; var type = pinsToType[length] || "OTHER"; board.type = type; // Copy pin data to index for (var i = 0; i < length; i++) { this[i] = pins[i]; } Object.defineProperties(this, { type: { value: type }, length: { value: length } }); // If an IO Plugin or Expander defines // these, override the default [ "isInput", "isOutput", "isAnalog", "isPwm", "isServo", ].forEach(function(isType) { if (io[isType]) { this[isType] = io[isType]; } }, this); }
n/a
Error = function (opts) { throw new Error( "Pin Error: " + opts.pin + " is not a valid " + opts.type + " pin (" + opts.via + ")" ); }
n/a
fromAnalog = function (pin) { if (typeof pin === "string" && pin[0] === "A") { return parseInt(pin.slice(1), 10); } return pin; }
n/a
identity = function (pins, needle) { return [].findIndex.call(pins, function(pin) { return pin.name === needle || pin.id === needle || pin.port === needle; }); }
n/a
function isFirmata(board) { return board.io.name === "Firmata" || board.io.name === "Mock"; }
n/a
normalize = function (opts, board) { var type = board.pins.type; var isArduino = isFirmata(board); var normalizer = normalizers.get(board); var isNormalizing; if (typeof opts === "string" || typeof opts === "number" || Array.isArray(opts)) { opts = new Options(opts); } if (!normalizer) { isNormalizing = board.io && typeof board.io.normalize === "function"; normalizer = function(pin) { return isArduino ? Pins.fromAnalog(Pins.translate(pin, type)) : (isNormalizing ? board.io.normalize(pin) : pin); }; normalizers.set(board, normalizer); } // Auto-normalize pin values, this reduces boilerplate code // inside module constructors if (hasPins(opts)) { // When an array of pins is present, attempt to // normalize them if necessary if (opts.pins) { opts.pins = opts.pins.map(normalizer); } else { opts.pin = normalizer(opts.pin); } } return opts; }
n/a
translate = function (pin, type) { var translations = Pins.translations[type.toUpperCase()]; if (!translations) { return pin; } return Object.keys(translations).reduce(function(pin, map) { return translations[map][pin] || pin; }, pin); }
n/a
isAnalog = function (pin) { var attrs = this[pin] || this[Pins.identity(this, pin)]; if (attrs && attrs.supportedModes.includes(MODES[key])) { return true; } return false; }
n/a
isDigital = function (pin) { var attrs = this[pin] || this[Pins.identity(this, pin)]; if (attrs && attrs.supportedModes.length) { return true; } return false; }
n/a
isInput = function (pin) { var attrs = this[pin] || this[Pins.identity(this, pin)]; if (attrs && attrs.supportedModes.includes(MODES[key])) { return true; } return false; }
n/a
isOutput = function (pin) { var attrs = this[pin] || this[Pins.identity(this, pin)]; if (attrs && attrs.supportedModes.includes(MODES[key])) { return true; } return false; }
n/a
isPwm = function (pin) { var attrs = this[pin] || this[Pins.identity(this, pin)]; if (attrs && attrs.supportedModes.includes(MODES[key])) { return true; } return false; }
n/a
isServo = function (pin) { var attrs = this[pin] || this[Pins.identity(this, pin)]; if (attrs && attrs.supportedModes.includes(MODES[key])) { return true; } return false; }
n/a
analogRead = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
analogWrite = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
digitalRead = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
digitalWrite = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
error = function () { var args = [].slice.call(arguments); args.unshift(type); this.log.apply(this, args); }
n/a
fail = function () { var args = [].slice.call(arguments); args.unshift(type); this.log.apply(this, args); }
n/a
i2cConfig = function () { this.io[method].apply(this.io, arguments); return this; }
...
var Emitter = require("events").EventEmitter;
var util = require("util");
var shared;
function Bank(options) {
this.address = options.address;
this.io = options.io;
this.io.i2cConfig(options);
}
Bank.prototype.read = function(register, numBytes, callback) {
if (register) {
this.io.i2cRead(this.address, register, numBytes, callback);
} else {
this.io.i2cRead(this.address, numBytes, callback);
...
i2cRead = function () { this.io[method].apply(this.io, arguments); return this; }
...
this.address = options.address;
this.io = options.io;
this.io.i2cConfig(options);
}
Bank.prototype.read = function(register, numBytes, callback) {
if (register) {
this.io.i2cRead(this.address, register, numBytes, callback);
} else {
this.io.i2cRead(this.address, numBytes, callback);
}
};
Bank.prototype.write = function(register, bytes) {
if (!Array.isArray(bytes)) {
...
i2cReadOnce = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
i2cWrite = function () { this.io[method].apply(this.io, arguments); return this; }
...
}
};
Bank.prototype.write = function(register, bytes) {
if (!Array.isArray(bytes)) {
bytes = [bytes];
}
this.io.i2cWrite(this.address, register, bytes);
};
// http://www.nr.edu/csc200/labs-ev3/ev3-user-guide-EN.pdf
function EVS(options) {
if (shared) {
return shared;
...
i2cWriteReg = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
info = function () { var args = [].slice.call(arguments); args.unshift(type); this.log.apply(this, args); }
n/a
log = function () {
var args = Array.from(arguments);
// If this was a direct call to `log(...)`, make sure
// there is a correct "type" to emit below.
if (!logging.specials.includes(args[0])) {
args.unshift("log");
}
var type = args.shift();
var klass = args.shift();
var message = args.shift();
var color = logging.colors[type];
var now = Date.now();
var event = {
type: type,
timestamp: now,
class: klass,
message: "",
data: null,
};
if (typeof args[args.length - 1] === "object") {
event.data = args.pop();
}
message += " " + args.join(", ");
event.message = message.trim();
/* istanbul ignore if */
if (this.debug) {
/* istanbul ignore next */
console.log([
// Timestamp
chalk.grey(now),
// Module, color matches type of log
chalk.magenta(klass),
// Details
chalk[color](message),
// Miscellaneous args
args.join(", ")
].join(" "));
}
this.emit(type, event);
this.emit("message", event);
}
n/a
loop = function (time, callback) { var handler = function() { callback(function() { clearInterval(interval); }); }; var interval = setInterval(handler, time); return this; }
n/a
pinMode = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
pwmWrite = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
queryPinState = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
samplingInterval = function (ms) { if (this.io.setSamplingInterval) { this.io.setSamplingInterval(ms); } else { throw new Error("This IO plugin does not implement an interval adjustment method"); } return this; }
n/a
sendI2CConfig = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
sendI2CReadRequest = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
sendI2CWriteRequest = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
serialClose = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
serialConfig = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
serialFlush = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
serialListen = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
serialRead = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
serialStop = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
serialWrite = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
serialize = function (reducer) { return JSON.stringify(this.snapshot(reducer)); }
n/a
servoConfig = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
servoWrite = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
shiftOut = function (dataPin, clockPin, isBigEndian, value) { if (arguments.length === 3) { value = isBigEndian; isBigEndian = true; } for (var i = 0; i < 8; i++) { this.io.digitalWrite(clockPin, 0); if (isBigEndian) { this.io.digitalWrite(dataPin, !!(value & (1 << (7 - i))) | 0); } else { this.io.digitalWrite(dataPin, !!(value & (1 << i)) | 0); } this.io.digitalWrite(clockPin, 1); } }
n/a
snapshot = function (reducer) { var blacklist = this.snapshot.blacklist; var special = this.snapshot.special; var hasReducer = typeof reducer === "function"; return this.register.reduce(function(accum, component) { // Don't include collections or multi/imu wrappers if (typeof component.components === UNDEFINED) { accum.push( Object.getOwnPropertyNames(component).reduce(function(data, prop) { var value = component[prop]; if (!blacklist.includes(prop) && typeof value !== "function") { if (hasReducer) { var result = reducer(prop, value, component); if (result !== undefined) { data[prop] = result; } } else { data[prop] = special[prop] ? special[prop](value) : value; } } return data; }, Object.create(null)) ); } return accum; }.bind(this), []); }
n/a
stepperConfig = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
stepperStep = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
sysexCommand = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
sysexResponse = function () { this.io[method].apply(this.io, arguments); return this; }
n/a
wait = function (time, callback) { setTimeout(callback, time); return this; }
n/a
warn = function () { var args = [].slice.call(arguments); args.unshift(type); this.log.apply(this, args); }
n/a
range = function (lower, upper, tick) { if (arguments.length === 1) { upper = lower - 1; lower = 0; } lower = lower || 0; upper = upper || 0; tick = tick || 1; var len = Math.max(Math.ceil((upper - lower) / tick), 0), idx = 0, range = []; while (idx <= len) { range[idx++] = lower; lower += tick; } return range; }
n/a
prefixed = function (prefix) { return Fn.range.apply(null, [].slice.call(arguments, 1)).map(function(val) { return prefix + val; }); }
n/a
function Boards(opts) {
if (!(this instanceof Boards)) {
return new Boards(opts);
}
var ports;
// new Boards([ ...Array of board opts ])
if (Array.isArray(opts)) {
ports = opts.slice();
opts = {
ports: ports,
};
}
// new Boards({ ports: [ ...Array of board opts ], .... })
/* istanbul ignore else */
if (!Array.isArray(opts) && typeof opts === "object" && opts.ports !== undefined) {
ports = opts.ports;
}
// new Boards(non-Array?)
// new Boards({ ports: non-Array? })
/* istanbul ignore if */
if (!Array.isArray(ports)) {
throw new Error("Expected ports to be an array");
}
if (typeof opts.debug === UNDEFINED) {
opts.debug = true;
}
if (typeof opts.repl === UNDEFINED) {
opts.repl = true;
}
var initialized = {};
var noRepl = ports.some(function(port) { return port.repl === false; });
var noDebug = ports.some(function(port) { return port.debug === false; });
this.length = ports.length;
this.debug = opts.debug;
this.repl = opts.repl;
// If any of the port definitions have
// explicitly shut off debug output, bubble up
// to the Boards instance
/* istanbul ignore else */
if (noDebug) {
this.debug = false;
}
// If any of the port definitions have
// explicitly shut off the repl, bubble up
// to the Boards instance
/* istanbul ignore else */
if (noRepl) {
this.repl = false;
}
var expecteds = ports.map(function(port, index) {
var portOpts;
if (typeof port === "string") {
portOpts = {};
// If the string matches a known valid port
// name pattern, then assume this is what
// the user code intended.
if (rport.test(port)) {
portOpts.port = port;
} else {
// Otherwise they expect Johnny-Five to figure
// out what ports to use and intended this
// value to be used an id
portOpts.id = port;
}
} else {
portOpts = port;
}
// Shut off per-board repl instance creation
portOpts.repl = false;
this[index] = initialized[portOpts.id] = new Board(portOpts);
// "error" event is not async, register immediately
this[index].on("error", function(error) {
this.emit("error", error);
}.bind(this));
return new Promise(function(resolve) {
this[index].on("ready", function() {
resolve(initialized[portOpts.id]);
});
}.bind(this));
}, this);
Promise.all(expecteds).then(function(boards) {
Object.assign(this, boards);
this.each(function(board) {
board.info("Board ID: ", chalk.green(board.id));
});
// If the Boards instance requires a REPL,
// make sure it's created before calling "ready"
if (this.repl) {
this.repl = new Repl(
Object.assign({}, initialized, {
board: this
})
);
this.repl.initialize(function() {
this.emit("ready", initialized);
}.bind(this));
} else {
// Otherwise, call ready immediately
this.emit("ready", initialized);
}
}.bind(this));
}
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
add = function () { var length = this.length; var aLen = arguments.length; for (var i = 0; i < aLen; i++) { // When a Type exists, respect it! if (this.type) { if (arguments[i] instanceof this.type || arguments[i] instanceof this.constructor) { this[length++] = arguments[i]; } } else { // Otherwise allow user to directly instantiate // Collection or Collection.Emitter to create // a mixed collection this[length++] = arguments[i]; } } return (this.length = length); }
n/a
byId = function (id) { for (var i = 0; i < this.length; i++) { if (this[i].id === id) { return this[i]; } } return null; }
n/a
each = function (callbackFn) { var length = this.length; for (var i = 0; i < length; i++) { callbackFn.call(this[i], this[i], i); } return this; }
n/a
error = function () { var args = [].slice.call(arguments); args.unshift(type); this.log.apply(this, args); }
n/a
fail = function () { var args = [].slice.call(arguments); args.unshift(type); this.log.apply(this, args); }
n/a
forEach = function () { [].forEach.apply(this, arguments); }
...
setInterval(function() {
if (raw === null) {
return;
}
var didOrientationChange = false;
var didCalibrationChange = false;
["heading", "roll", "pitch"].forEach(function(el) {
if (state.euler[el] !== raw.orientation.euler[el]) {
didOrientationChange = true;
}
state.euler[el] = raw.orientation.euler[el];
});
["w", "x", "y", "z"].forEach(function(el) {
...
includes = function () { return [].includes.apply(this, arguments); }
...
address = EVS.BANK_A;
bank = "a";
} else {
address = EVS.BANK_B;
bank = "b";
}
if (pin.includes("M")) {
motor = pin.endsWith("M1") ? EVS.S1 : EVS.S2;
}
if (pin.includes("S")) {
endsWithS1 = pin.endsWith("S1");
// Used for reading 2 byte integer values from raw sensors
...
indexOf = function () { return [].indexOf.apply(this, arguments); }
...
Object.defineProperty(Array.prototype, "includes", {
value: function(entry) {
return this.indexOf(entry) !== -1;
},
enumerable: false,
configurable: false,
writable: false
});
...
info = function () { var args = [].slice.call(arguments); args.unshift(type); this.log.apply(this, args); }
n/a
log = function () {
var args = Array.from(arguments);
// If this was a direct call to `log(...)`, make sure
// there is a correct "type" to emit below.
if (!logging.specials.includes(args[0])) {
args.unshift("log");
}
var type = args.shift();
var klass = args.shift();
var message = args.shift();
var color = logging.colors[type];
var now = Date.now();
var event = {
type: type,
timestamp: now,
class: klass,
message: "",
data: null,
};
if (typeof args[args.length - 1] === "object") {
event.data = args.pop();
}
message += " " + args.join(", ");
event.message = message.trim();
/* istanbul ignore if */
if (this.debug) {
/* istanbul ignore next */
console.log([
// Timestamp
chalk.grey(now),
// Module, color matches type of log
chalk.magenta(klass),
// Details
chalk[color](message),
// Miscellaneous args
args.join(", ")
].join(" "));
}
this.emit(type, event);
this.emit("message", event);
}
n/a
map = function () { return [].map.apply(this, arguments); }
...
}
state.emitter = new Led({
board: this.board,
pin: this.opts.emitter
});
state.sensorStates = this.pins.map(function(pin) {
var sensorState = {
sensor: new Sensor({
board: this.board,
freq: this.freq,
pin: pin
}),
rawValue: 0,
...
slice = function () { return new this.constructor([].slice.apply(this, arguments)); }
n/a
warn = function () { var args = [].slice.call(arguments); args.unshift(type); this.log.apply(this, args); }
n/a
function Button(opts) {
if (!(this instanceof Button)) {
return new Button(opts);
}
var pinValue;
var raw;
var invert = false;
var downValue = 1;
var upValue = 0;
var controller = null;
var state = {
interval: null,
last: null
};
// Create a debounce boundary on event triggers
// this avoids button events firing on
// press noise and false positives
var trigger = Fn.debounce(function(key) {
aliases[key].forEach(function(type) {
this.emit(type);
}, this);
}, 7);
pinValue = typeof opts === "object" ? opts.pin : opts;
Board.Component.call(
this, opts = Board.Options(opts)
);
opts.pinValue = pinValue;
if (opts.controller && typeof opts.controller === "string") {
controller = Controllers[opts.controller.toUpperCase()];
} else {
controller = opts.controller;
}
if (controller == null) {
controller = Controllers.DEFAULT;
}
Board.Controller.call(this, controller, opts);
// `holdtime` is used by an interval to determine
// if the button has been released within a specified
// time frame, in milliseconds.
this.holdtime = opts.holdtime || 500;
// `opts.isPullup` is included as part of an effort to
// phase out "isFoo" options properties
this.pullup = opts.pullup || opts.isPullup || false;
this.pulldown = opts.pulldown || opts.isPulldown || false;
// Turns out some button circuits will send
// 0 for up and 1 for down, and some the inverse,
// so we can invert our function with this option.
// Default to invert in pullup mode, but use opts.invert
// if explicitly defined (even if false)
invert = typeof opts.invert !== "undefined" ?
opts.invert : (this.pullup || false);
if (invert) {
downValue = downValue ^ 1;
upValue = upValue ^ 1;
}
state.last = upValue;
// Create a "state" entry for privately
// storing the state of the button
priv.set(this, state);
Object.defineProperties(this, {
value: {
get: function() {
return Number(this.isDown);
}
},
invert: {
get: function() {
return invert;
},
set: function(value) {
invert = value;
downValue = invert ? 0 : 1;
upValue = invert ? 1 : 0;
state.last = upValue;
}
},
downValue: {
get: function() {
return downValue;
},
set: function(value) {
downValue = value;
upValue = value ^ 1;
invert = value ? true : false;
state.last = upValue;
}
},
upValue: {
get: function() {
return upValue;
},
set: function(value) {
upValue = value;
downValue = value ^ 1;
invert = value ? true : false;
state.last = downValue;
}
},
isDown: {
get: function() {
return this.toBoolean(raw);
}
}
});
/* istanbul ignore else */
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
// Update the raw data value, which
// is used by isDown = toBoolean()
raw = data;
if (!this.isDown) {
/* istanbul ignore else */
if (state.interval) {
clearInterval(state.interval);
}
trigger.call(this, "up");
}
if (this.isDown) {
trigger.call(this, "down");
state.interval = setInterval(function() {
/* istanbul ignore else */
if (this.isDown) {
this.emit("hold");
}
}.bind(this), this.holdtime);
}
state.last = data;
}.bind(this));
}
}
n/a
function Buttons(numsOrObjects) { if (!(this instanceof Buttons)) { return new Buttons(numsOrObjects); } Object.defineProperty(this, "type", { value: Button }); Collection.Emitter.call(this, numsOrObjects); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function Buttons(numsOrObjects) { if (!(this instanceof Buttons)) { return new Buttons(numsOrObjects); } Object.defineProperty(this, "type", { value: Button }); Collection.Emitter.call(this, numsOrObjects); }
n/a
super_ = function (numsOrObjects) {
// Create private state ahead of super call
priv.set(this, {
timing: {
last: Date.now()
}
});
Collection.call(this, numsOrObjects);
// If the Collection.Emitter was created
// with a Shared Properties object, then
// we should abide by the freq or period
// properties...
var interval = null;
var period = 5;
if (!Array.isArray(numsOrObjects) &&
(typeof numsOrObjects === "object" && numsOrObjects !== null)) {
period = numsOrObjects.freq || numsOrObjects.period || period;
// _However_, looking to the future, we
// need to start thinking about replacing
// the garbage named _freq_ (the value is
// actually a period), with real _frequency_
// in Hz.
// If provided, convert frequency to period
/* istanbul ignore else */
if (numsOrObjects.frequency) {
period = (1 / numsOrObjects.frequency) * 1000;
}
}
Object.defineProperties(this, {
period: {
get: function() {
return period;
},
set: function(value) {
if (period !== value) {
period = value;
}
if (interval) {
clearInterval(interval);
}
interval = setInterval(function() {
this.emit("data", this);
}.bind(this), period);
}
},
});
this.period = period;
this.on("newListener", function(event) {
if (event === "change" || event === "data") {
return;
}
this.forEach(function(input) {
input.on(event, function(data) {
this.emit(event, input, data);
}.bind(this));
}, this);
});
}
n/a
function Collection(numsOrObjects) {
var Type = this.type;
var initObjects = [];
this.length = 0;
if (Array.isArray(numsOrObjects)) {
initObjects = numsOrObjects;
} else {
// Initialize with a Shared Properties object
/* istanbul ignore else */
if (Array.isArray(numsOrObjects.pins)) {
var keys = Object.keys(numsOrObjects).filter(function(key) {
return key !== "pins";
});
initObjects = numsOrObjects.pins.map(function(pin) {
var obj = {};
if (Array.isArray(pin)) {
obj.pins = pin;
} else {
obj.pin = pin;
}
return keys.reduce(function(accum, key) {
accum[key] = numsOrObjects[key];
return accum;
}, obj);
});
}
}
/* istanbul ignore else */
if (initObjects.length) {
while (initObjects.length) {
var numOrObject = initObjects.shift();
// When a Type exists, respect it!
if (typeof Type === "function") {
if (!(numOrObject instanceof Type || numOrObject instanceof this.constructor)) {
numOrObject = new Type(numOrObject);
}
}
this.add(numOrObject);
}
}
}
n/a
add = function () {
var inputs = Array.from(arguments);
/* istanbul ignore else */
if (inputs.length) {
Collection.prototype.add.apply(this, inputs);
inputs.forEach(function(input) {
if (input) {
input.on("change", function() {
this.emit("change", input);
}.bind(this));
}
}, this);
}
return this.length;
// return (this.length = length);
}
n/a
function addListener(type, listener) { return _addListener(this, type, listener, false); }
n/a
function emit(type) { var er, handler, len, args, i, events, domain; var needDomainExit = false; var doError = (type === 'error'); events = this._events; if (events) doError = (doError && events.error == null); else if (!doError) return false; domain = this.domain; // If there is no 'error' event listener then throw. if (doError) { er = arguments[1]; if (domain) { if (!er) er = new Error('Uncaught, unspecified "error" event'); er.domainEmitter = this; er.domain = domain; er.domainThrown = false; domain.emit('error', er); } else if (er instanceof Error) { throw er; // Unhandled 'error' event } else { // At least give some kind of context to the user var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); err.context = er; throw err; } return false; } handler = events[type]; if (!handler) return false; if (domain && this !== process) { domain.enter(); needDomainExit = true; } var isFn = typeof handler === 'function'; len = arguments.length; switch (len) { // fast cases case 1: emitNone(handler, isFn, this); break; case 2: emitOne(handler, isFn, this, arguments[1]); break; case 3: emitTwo(handler, isFn, this, arguments[1], arguments[2]); break; case 4: emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]); break; // slower default: args = new Array(len - 1); for (i = 1; i < len; i++) args[i - 1] = arguments[i]; emitMany(handler, isFn, this, args); } if (needDomainExit) domain.exit(); return true; }
...
var data = {
euler: this.euler,
quarternion: this.quarternion,
calibration: this.calibration
};
this.emit("data", data);
if (didOrientationChange) {
this.emit("change", data);
}
//not sure how we can get this event into other drivers
if (didCalibrationChange) {
...
function eventNames() { return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : []; }
n/a
function getMaxListeners() { return $getMaxListeners(this); }
n/a
function listenerCount(type) { const events = this._events; if (events) { const evlistener = events[type]; if (typeof evlistener === 'function') { return 1; } else if (evlistener) { return evlistener.length; } } return 0; }
n/a
function listeners(type) { var evlistener; var ret; var events = this._events; if (!events) ret = []; else { evlistener = events[type]; if (!evlistener) ret = []; else if (typeof evlistener === 'function') ret = [evlistener]; else ret = arrayClone(evlistener, evlistener.length); } return ret; }
n/a
function addListener(type, listener) { return _addListener(this, type, listener, false); }
...
The ubiquitous "Hello World" program of the microcontroller and SoC world is "blink an LED". The following code
demonstrates how this is done using the Johnny-Five framework.
```javascript
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
...
function once(type, listener) { if (typeof listener !== 'function') throw new TypeError('"listener" argument must be a function'); this.on(type, _onceWrap(this, type, listener)); return this; }
...
// Calibrate will store the min/max values for this sensor array
// It should be called many times in order to get a lot of readings
// on light and dark areas. See calibrateUntil for a convenience
// for looping until a condition is met.
ReflectanceArray.prototype.calibrate = function() {
var state = priv.get(this);
this.once("data", function(values) {
setCalibration(state.calibration, values);
this.emit("calibrated");
});
return this;
};
...
function prependListener(type, listener) { return _addListener(this, type, listener, true); }
n/a
function prependOnceListener(type, listener) { if (typeof listener !== 'function') throw new TypeError('"listener" argument must be a function'); this.prependListener(type, _onceWrap(this, type, listener)); return this; }
n/a
function removeAllListeners(type) { var listeners, events; events = this._events; if (!events) return this; // not listening for removeListener, no need to emit if (!events.removeListener) { if (arguments.length === 0) { this._events = new EventHandlers(); this._eventsCount = 0; } else if (events[type]) { if (--this._eventsCount === 0) this._events = new EventHandlers(); else delete events[type]; } return this; } // emit removeListener for all listeners on all events if (arguments.length === 0) { var keys = Object.keys(events); for (var i = 0, key; i < keys.length; ++i) { key = keys[i]; if (key === 'removeListener') continue; this.removeAllListeners(key); } this.removeAllListeners('removeListener'); this._events = new EventHandlers(); this._eventsCount = 0; return this; } listeners = events[type]; if (typeof listeners === 'function') { this.removeListener(type, listeners); } else if (listeners) { // LIFO order do { this.removeListener(type, listeners[listeners.length - 1]); } while (listeners[0]); } return this; }
n/a
function removeListener(type, listener) { var list, events, position, i, originalListener; if (typeof listener !== 'function') throw new TypeError('"listener" argument must be a function'); events = this._events; if (!events) return this; list = events[type]; if (!list) return this; if (list === listener || list.listener === listener) { if (--this._eventsCount === 0) this._events = new EventHandlers(); else { delete events[type]; if (events.removeListener) this.emit('removeListener', type, list.listener || listener); } } else if (typeof list !== 'function') { position = -1; for (i = list.length; i-- > 0;) { if (list[i] === listener || list[i].listener === listener) { originalListener = list[i].listener; position = i; break; } } if (position < 0) return this; if (list.length === 1) { list[0] = undefined; if (--this._eventsCount === 0) { this._events = new EventHandlers(); return this; } else { delete events[type]; } } else { spliceOne(list, position); } if (events.removeListener) this.emit('removeListener', type, originalListener || listener); } return this; }
n/a
function setMaxListeners(n) { if (typeof n !== 'number' || n < 0 || isNaN(n)) throw new TypeError('"n" argument must be a positive number'); this._maxListeners = n; return this; }
n/a
function Collection(numsOrObjects) {
var Type = this.type;
var initObjects = [];
this.length = 0;
if (Array.isArray(numsOrObjects)) {
initObjects = numsOrObjects;
} else {
// Initialize with a Shared Properties object
/* istanbul ignore else */
if (Array.isArray(numsOrObjects.pins)) {
var keys = Object.keys(numsOrObjects).filter(function(key) {
return key !== "pins";
});
initObjects = numsOrObjects.pins.map(function(pin) {
var obj = {};
if (Array.isArray(pin)) {
obj.pins = pin;
} else {
obj.pin = pin;
}
return keys.reduce(function(accum, key) {
accum[key] = numsOrObjects[key];
return accum;
}, obj);
});
}
}
/* istanbul ignore else */
if (initObjects.length) {
while (initObjects.length) {
var numOrObject = initObjects.shift();
// When a Type exists, respect it!
if (typeof Type === "function") {
if (!(numOrObject instanceof Type || numOrObject instanceof this.constructor)) {
numOrObject = new Type(numOrObject);
}
}
this.add(numOrObject);
}
}
}
n/a
Emitter = function (numsOrObjects) {
// Create private state ahead of super call
priv.set(this, {
timing: {
last: Date.now()
}
});
Collection.call(this, numsOrObjects);
// If the Collection.Emitter was created
// with a Shared Properties object, then
// we should abide by the freq or period
// properties...
var interval = null;
var period = 5;
if (!Array.isArray(numsOrObjects) &&
(typeof numsOrObjects === "object" && numsOrObjects !== null)) {
period = numsOrObjects.freq || numsOrObjects.period || period;
// _However_, looking to the future, we
// need to start thinking about replacing
// the garbage named _freq_ (the value is
// actually a period), with real _frequency_
// in Hz.
// If provided, convert frequency to period
/* istanbul ignore else */
if (numsOrObjects.frequency) {
period = (1 / numsOrObjects.frequency) * 1000;
}
}
Object.defineProperties(this, {
period: {
get: function() {
return period;
},
set: function(value) {
if (period !== value) {
period = value;
}
if (interval) {
clearInterval(interval);
}
interval = setInterval(function() {
this.emit("data", this);
}.bind(this), period);
}
},
});
this.period = period;
this.on("newListener", function(event) {
if (event === "change" || event === "data") {
return;
}
this.forEach(function(input) {
input.on(event, function(data) {
this.emit(event, input, data);
}.bind(this));
}, this);
});
}
n/a
installMethodForwarding = function (target, source) { return Object.keys(source).reduce(function(accum, method) { // Create Inputs wrappers for each method listed. // This will allow us control over all Input instances // simultaneously. accum[method] = function() { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }; return accum; }, target); }
n/a
add = function () { var length = this.length; var aLen = arguments.length; for (var i = 0; i < aLen; i++) { // When a Type exists, respect it! if (this.type) { if (arguments[i] instanceof this.type || arguments[i] instanceof this.constructor) { this[length++] = arguments[i]; } } else { // Otherwise allow user to directly instantiate // Collection or Collection.Emitter to create // a mixed collection this[length++] = arguments[i]; } } return (this.length = length); }
n/a
byId = function (id) { return [].find.call(this, function(entry) { return entry.id !== undefined && entry.id === id; }); }
n/a
each = function (callbackFn) { var length = this.length; for (var i = 0; i < length; i++) { callbackFn.call(this[i], this[i], i); } return this; }
n/a
forEach = function () { [].forEach.apply(this, arguments); }
...
setInterval(function() {
if (raw === null) {
return;
}
var didOrientationChange = false;
var didCalibrationChange = false;
["heading", "roll", "pitch"].forEach(function(el) {
if (state.euler[el] !== raw.orientation.euler[el]) {
didOrientationChange = true;
}
state.euler[el] = raw.orientation.euler[el];
});
["w", "x", "y", "z"].forEach(function(el) {
...
includes = function () { return [].includes.apply(this, arguments); }
...
address = EVS.BANK_A;
bank = "a";
} else {
address = EVS.BANK_B;
bank = "b";
}
if (pin.includes("M")) {
motor = pin.endsWith("M1") ? EVS.S1 : EVS.S2;
}
if (pin.includes("S")) {
endsWithS1 = pin.endsWith("S1");
// Used for reading 2 byte integer values from raw sensors
...
indexOf = function () { return [].indexOf.apply(this, arguments); }
...
Object.defineProperty(Array.prototype, "includes", {
value: function(entry) {
return this.indexOf(entry) !== -1;
},
enumerable: false,
configurable: false,
writable: false
});
...
map = function () { return [].map.apply(this, arguments); }
...
}
state.emitter = new Led({
board: this.board,
pin: this.opts.emitter
});
state.sensorStates = this.pins.map(function(pin) {
var sensorState = {
sensor: new Sensor({
board: this.board,
freq: this.freq,
pin: pin
}),
rawValue: 0,
...
slice = function () { return new this.constructor([].slice.apply(this, arguments)); }
n/a
function Color(opts) { if (!(this instanceof Color)) { return new Color(opts); } var controller = null; var state = {}; var freq = opts.freq || 25; var raw = 0; var last = null; Board.Component.call( this, opts = Board.Options(opts) ); if (typeof opts.controller === "string") { controller = Controllers[opts.controller]; } else { controller = opts.controller; } if (controller == null) { throw new Error("Color expects a valid controller"); } priv.set(this, state); Board.Controller.call(this, controller, opts); if (!this.toRGB) { this.toRGB = opts.toRGB || function(x) { return x; }; } Object.defineProperties(this, { value: { get: function() { return raw; } }, rgb: { get: function() { return this.toRGB(raw).reduce(function(accum, value, index) { accum[colorNames[index]] = value; return accum; }, {}); } } }); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { raw = data; }); } setInterval(function() { if (raw === undefined) { return; } var data = { rgb: this.rgb, }; this.emit("data", data); if (raw !== last) { last = raw; this.emit("change", data); } }.bind(this), freq); }
n/a
hexCode = function (rgb) { if (rgb.red === undefined || rgb.green === undefined || rgb.blue === undefined) { return null; } return rgb.length === 0 ? "unknown" : colorNames.reduce(function(accum, name) { return accum += pad(rgb[name].toString(16), 2); }, ""); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function Compass(opts) {
if (!(this instanceof Compass)) {
return new Compass(opts);
}
Board.Component.call(
this, opts = Board.Options(opts)
);
var freq = opts.freq || 25;
var controller = null;
var raw = {
x: null,
y: null,
z: null,
};
var state = {
x: 0,
y: 0,
z: 0,
scale: 0,
register: 0,
heading: 0
};
if (opts.controller && typeof opts.controller === "string") {
controller = Controllers[opts.controller.toUpperCase()];
} else {
controller = opts.controller;
}
if (controller == null) {
throw new Error("Compass expects a valid controller");
}
Board.Controller.call(this, controller, opts);
if (!this.toScaledHeading) {
this.toScaledHeading = opts.toScaledHeading || function(raw) {
return raw;
};
}
priv.set(this, state);
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
raw = data;
});
}
setInterval(function() {
if (raw.x === null) {
return;
}
var isChange = false;
state.x = raw.x;
state.y = raw.y;
state.z = raw.z;
var heading = this.heading;
if (heading !== state.heading) {
state.heading = heading;
isChange = true;
}
this.emit("data", {
heading: state.heading
});
if (isChange) {
this.emit("change", {
heading: state.heading
});
}
}.bind(this), freq);
Object.defineProperties(this, {
/**
* [read-only] Bearing information
* @name bearing
* @property
* @type Object
*
*
name
abbr
low
mid
high
heading
*
*/
bearing: {
get: function() {
var length = Compass.Points.length;
var heading = Math.floor(this.heading);
var point;
for (var i = 0; i < length; i++) {
point = Compass.Points[i];
if (point.range.includes(heading)) {
// Specify fields to return to avoid returning the
// range array (too much noisy data)
return {
name: point.name,
abbr: point.abbr,
low: point.low,
high: point.high,
heading: heading
};
}
}
}
},
/**
* [read-only] Heading (azimuth)
* @name heading
* @property
* @type number
*/
heading: {
get: function() {
return this.toScaledHeading(raw);
}
}
});
}
n/a
Scale = function (gauss) { if (gauss === 0.88) { this.register = 0x00; this.scale = 0.73; } else if (gauss === 1.3) { this.register = 0x01; this.scale = 0.92; } else if (gauss === 1.9) { this.register = 0x02; this.scale = 1.22; } else if (gauss === 2.5) { this.register = 0x03; this.scale = 1.52; } else if (gauss === 4.0) { this.register = 0x04; this.scale = 2.27; } else if (gauss === 4.7) { this.register = 0x05; this.scale = 2.56; } else if (gauss === 5.6) { this.register = 0x06; this.scale = 3.03; } else if (gauss === 8.1) { this.register = 0x07; this.scale = 4.35; } else { this.register = 0x00; this.scale = 1; } // Setting is in the top 3 bits of the register. this.register = this.register << 5; }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function ESC(opts) { if (!(this instanceof ESC)) { return new ESC(opts); } var controller = null; var pinValue; var device; var state = { // All speed history for this ESC // history = [ // { // timestamp: Date.now(), // speed: speed // } // ]; history: [], value: 0 }; Board.Component.call( this, opts = Board.Options(opts) ); priv.set(this, state); this.startAt = typeof opts.startAt !== "undefined" ? opts.startAt : null; this.neutral = opts.neutral; this.range = opts.range || [0, 100]; this.pwmRange = opts.pwmRange || [544, 2400]; this.interval = null; // StandardFirmata on Arduino allows controlling // servos from analog pins. // If we're currently operating with an Arduino // and the user has provided an analog pin name // (eg. "A0", "A5" etc.), parse out the numeric // value and capture the fully qualified analog // pin number. if (typeof opts.controller === "undefined" && Pins.isFirmata(this)) { if (typeof pinValue === "string" && pinValue[0] === "A") { pinValue = this.io.analogPins[+pinValue.slice(1)]; } pinValue = +pinValue; // If the board's default pin normalization // came up with something different, use the // the local value. if (!Number.isNaN(pinValue) && this.pin !== pinValue) { this.pin = pinValue; } } // Allow users to pass in custom device types device = typeof opts.device === "string" ? Devices[opts.device] : opts.device; if (!device) { device = Devices.FORWARD; } if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (!controller) { controller = Controllers.DEFAULT; } Object.defineProperties(this, Object.assign({}, device, controller, { value: { get: function() { return state.value; } }, history: { get: function() { return state.history.slice(-5); } }, last: { get: function() { return state.history[state.history.length - 1] || { last: null }; } } })); this.initialize(opts); if (this.deviceName !== "FORWARD") { if (Number.isNaN(+this.neutral)) { throw new Error("Directional speed controllers require a neutral point from 0-100 (number)"); } this.startAt = this.neutral; } // Match either null or undefined, but not 0 if (this.startAt !== null && this.startAt !== undefined) { this.speed(this.startAt); } }
n/a
function ESCs(numsOrObjects) { if (!(this instanceof ESCs)) { return new ESCs(numsOrObjects); } Object.defineProperty(this, "type", { value: ESC }); Collection.call(this, numsOrObjects); }
n/a
function ESCs(numsOrObjects) { if (!(this instanceof ESCs)) { return new ESCs(numsOrObjects); } Object.defineProperty(this, "type", { value: ESC }); Collection.call(this, numsOrObjects); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
brake = function () { var state = priv.get(this); var speed = this.neutral || 0; this.speed(speed); state.history.push({ timestamp: Date.now(), speed: speed }); return this; }
n/a
forward = function (speed) { this.dir(speed, dir); return this; }
n/a
fwd = function (speed) { this.dir(speed, dir); return this; }
n/a
rev = function (speed) { this.dir(speed, dir); return this; }
n/a
reverse = function (speed) { this.dir(speed, dir); return this; }
n/a
speed = function (speed) { var state = priv.get(this); var history = state.history; var noInterval = false; var steps = 0; var lspeed, hspeed; speed = Fn.constrain(speed, this.range[0], this.range[1]); if (this.interval) { // Bail out if speed is the same as whatever was // last _provided_ if (this.value === speed) { return this; } else { clearInterval(this.interval); this.interval = null; } } state.value = speed; // This is the very first speed command being received. // Safe to assume that the ESC and Brushless motor are // not yet moving. if (history.length === 0) { noInterval = true; } // Bail out if speed is the same as whatever was // last _written_ if (this.last.speed === speed) { return this; } lspeed = this.last.speed; hspeed = speed; steps = Math.ceil(Math.abs(lspeed - hspeed)); if (!steps || steps === 1) { noInterval = true; } if (noInterval) { this.write(this.pin, Fn.fscale(speed, 0, 100, 0, 180)); history.push({ timestamp: Date.now(), speed: speed }); return this; } var throttle = lspeed; this.interval = setInterval(function() { if (hspeed > throttle) { throttle++; } else { throttle--; } this.write(this.pin, (throttle * 180 / 100)); history.push({ timestamp: Date.now(), speed: throttle }); if (steps) { steps--; if (!steps) { clearInterval(this.interval); this.interval = null; } } }.bind(this), 1); return this; }
n/a
stop = function () { var state = priv.get(this); var history = state.history; var speed = this.type === "bidirectional" ? this.neutral : 0; this.write(this.pin, Fn.fscale(speed, 0, 100, 0, 180)); history.push({ timestamp: Date.now(), speed: speed }); return this; }
n/a
function ESCs(numsOrObjects) { if (!(this instanceof ESCs)) { return new ESCs(numsOrObjects); } Object.defineProperty(this, "type", { value: ESC }); Collection.call(this, numsOrObjects); }
n/a
function Collection(numsOrObjects) {
var Type = this.type;
var initObjects = [];
this.length = 0;
if (Array.isArray(numsOrObjects)) {
initObjects = numsOrObjects;
} else {
// Initialize with a Shared Properties object
/* istanbul ignore else */
if (Array.isArray(numsOrObjects.pins)) {
var keys = Object.keys(numsOrObjects).filter(function(key) {
return key !== "pins";
});
initObjects = numsOrObjects.pins.map(function(pin) {
var obj = {};
if (Array.isArray(pin)) {
obj.pins = pin;
} else {
obj.pin = pin;
}
return keys.reduce(function(accum, key) {
accum[key] = numsOrObjects[key];
return accum;
}, obj);
});
}
}
/* istanbul ignore else */
if (initObjects.length) {
while (initObjects.length) {
var numOrObject = initObjects.shift();
// When a Type exists, respect it!
if (typeof Type === "function") {
if (!(numOrObject instanceof Type || numOrObject instanceof this.constructor)) {
numOrObject = new Type(numOrObject);
}
}
this.add(numOrObject);
}
}
}
n/a
brake = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
forward = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
fwd = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
rev = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
reverse = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
speed = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
stop = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
function Expander(opts) { if (!(this instanceof Expander)) { return new Expander(opts); } Base.call(this); var expander = null; var addressError = "Expander cannot reuse an active address"; var controller = null; var state = {}; var controllerValue; if (typeof opts === "string") { controllerValue = opts; } Board.Component.call( this, opts = Board.Options(opts), { normalizePin: false, requestPin: false } ); if (nonAddressable.includes(opts.controller) && typeof this.address === "undefined") { this.address = Fn.uid(); } expander = active.get(this.address); if (expander) { if (this.bus && (expander.bus !== undefined && expander.bus === this.bus)) { addressError += " on this bus"; } throw new Error(addressError); } if (typeof opts.controller === "undefined" && controllerValue) { opts.controller = controllerValue; } if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { throw new Error("Expander expects a valid controller"); } Board.Controller.call(this, controller, opts); priv.set(this, state); if (typeof this.initialize === "function") { this.initialize(opts); } active.set(this.address, this); }
n/a
byAddress = function (address) { return active.get(address); }
n/a
byController = function (name) { var controller = null; active.forEach(function(value) { if (value.name === name.toUpperCase()) { controller = value; } }); return controller; }
n/a
get = function (required) { if (!required.address || !required.controller) { throw new Error("Expander.get(...) requires an address and controller"); } if (required.address !== undefined) { required.address = Number(required.address); } if (Number.isNaN(required.address)) { throw new Error("Expander.get(...) expects address to be a number"); } if (typeof required.controller !== "string") { throw new Error("Expander.get(...) expects controller name to be a string"); } // If no address was sent them assume the request wants // to re-use an active Expander, by controller name. // if (!required.address) { // return Expander.byController(required.controller); // } var expander = active.get(required.address); if (expander && (expander.name === required.controller.toUpperCase())) { return expander; } return new Expander(required); }
...
var Controllers = {
BNO055: {
initialize: {
value: function(opts, dataHandler) {
var IMU = require("./imu"),
driver = IMU.Drivers.get(this.board, "BNO055", opts);
driver.on("data", function(data) {
dataHandler(data);
});
}
},
toScaledEuler: {
...
hasController = function (key) { return Controllers[key] !== undefined; }
n/a
function Base() { Emitter.call(this); this.HIGH = 1; this.LOW = 0; this.isReady = false; this.MODES = {}; this.pins = []; this.analogPins = []; }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
_BV = function (bit) { return 1 << bit; }
n/a
bitSize = function (n) { return Math.round(Math.log2(n)); }
n/a
bitValue = function (bit) { return 1 << bit; }
n/a
bv = function (bit) { return 1 << bit; }
n/a
function cloneDeep(value) { return baseClone(value, true, true); }
n/a
constrain = function (value, lower, upper) { return Math.min(upper, Math.max(lower, value)); }
...
function calibratedValues() {
return this.raw.map(function(value, i) {
var max = this.calibration.max[i],
min = this.calibration.min[i];
var scaled = __.scale(value, min, max, CALIBRATED_MIN_VALUE, CALIBRATED_MAX_VALUE);
return __.constrain(scaled, CALIBRATED_MIN_VALUE, CALIBRATED_MAX_VALUE);
}, this);
}
function maxLineValue() {
return (this.sensors.length - 1) * CALIBRATED_MAX_VALUE;
}
...
function debounce(func, wait, options) { var lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } wait = toNumber(wait) || 0; if (isObject(options)) { leading = !!options.leading; maxing = 'maxWait' in options; maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; trailing = 'trailing' in options ? !!options.trailing : trailing; } function invokeFunc(time) { var args = lastArgs, thisArg = lastThis; lastArgs = lastThis = undefined; lastInvokeTime = time; result = func.apply(thisArg, args); return result; } function leadingEdge(time) { // Reset any `maxWait` timer. lastInvokeTime = time; // Start the timer for the trailing edge. timerId = setTimeout(timerExpired, wait); // Invoke the leading edge. return leading ? invokeFunc(time) : result; } function remainingWait(time) { var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime, result = wait - timeSinceLastCall; return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result; } function shouldInvoke(time) { var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the // trailing edge, the system time has gone backwards and we're treating // it as the trailing edge, or we've hit the `maxWait` limit. return (lastCallTime === undefined || (timeSinceLastCall >= wait) || (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); } function timerExpired() { var time = now(); if (shouldInvoke(time)) { return trailingEdge(time); } // Restart the timer. timerId = setTimeout(timerExpired, remainingWait(time)); } function trailingEdge(time) { timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been // debounced at least once. if (trailing && lastArgs) { return invokeFunc(time); } lastArgs = lastThis = undefined; return result; } function cancel() { if (timerId !== undefined) { clearTimeout(timerId); } lastInvokeTime = 0; lastArgs = lastCallTime = lastThis = timerId = undefined; } function flush() { return timerId === undefined ? result : trailingEdge(now()); } function debounced() { var time = now(), isInvoking = shouldInvoke(time); lastArgs = arguments; lastThis = this; lastCallTime = time; if (isInvoking) { if (timerId === undefined) { return leadingEdge(lastCallTime); } if (maxing) { // Handle invocations in a tight loop. timerId = setTimeout(timerExpired, wait); return invokeFunc(lastCallTime); } } if (timerId === undefined) { timerId = setTimeout(timerExpired, wait); } return result; } debounced.cancel = cancel; debounced.flush = flush; return debounced; }
n/a
fma = function (a, b, c) { var aHigh = 134217729 * a; var aLow; aHigh = aHigh + (a - aHigh); aLow = a - aHigh; var bHigh = 134217729 * b; var bLow; bHigh = bHigh + (b - bHigh); bLow = b - bHigh; var r1 = a * b; var r2 = -r1 + aHigh * bHigh + aHigh * bLow + aLow * bHigh + aLow * bLow; var s = r1 + c; var t = (r1 - (s - c)) + (c - (s - r1)); return s + (t + r2); }
n/a
fmap = function (value, fromLow, fromHigh, toLow, toHigh) { f32A[0] = (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow; return f32A[0]; }
n/a
fscale = function (value, fromLow, fromHigh, toLow, toHigh) { f32A[0] = (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow; return f32A[0]; }
n/a
inRange = function (value, lower, upper) { return value >= lower && value <= upper; }
n/a
int16 = function (msb, lsb) { var result = (msb << 8) | lsb; // Check highest bit for sign. If on, value is negative return result >> 15 ? ((result ^ 0xFFFF) + 1) * -1 : result; }
n/a
int24 = function (b16, b8, b0) { var result = (b16 << 16) | (b8 << 8) | b0; // Check highest bit for sign. If on, value is negative return result >> 23 ? ((result ^ 0xFFFFFF) + 1) * -1 : result; }
n/a
int32 = function (b24, b16, b8, b0) { var result = (b24 << 24) | (b16 << 16) | (b8 << 8) | b0; // Check highest bit for sign. If on, value is negative return result >> 31 ? ((result ^ 0xFFFFFFFF) + 1) * -1 : result; }
n/a
map = function (value, fromLow, fromHigh, toLow, toHigh) { return ((value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow) | 0; }
...
}
state.emitter = new Led({
board: this.board,
pin: this.opts.emitter
});
state.sensorStates = this.pins.map(function(pin) {
var sensorState = {
sensor: new Sensor({
board: this.board,
freq: this.freq,
pin: pin
}),
rawValue: 0,
...
range = function (lower, upper, tick) { if (arguments.length === 1) { upper = lower - 1; lower = 0; } lower = lower || 0; upper = upper || 0; tick = tick || 1; var len = Math.max(Math.ceil((upper - lower) / tick), 0), idx = 0, range = []; while (idx <= len) { range[idx++] = lower; lower += tick; } return range; }
n/a
s10 = function (value) { if (value > halfMinusOne) { value -= decimal; } return Fn.constrain(value, -half, halfMinusOne); }
n/a
s12 = function (value) { if (value > halfMinusOne) { value -= decimal; } return Fn.constrain(value, -half, halfMinusOne); }
n/a
s16 = function (value) { if (value > halfMinusOne) { value -= decimal; } return Fn.constrain(value, -half, halfMinusOne); }
n/a
s20 = function (value) { if (value > halfMinusOne) { value -= decimal; } return Fn.constrain(value, -half, halfMinusOne); }
n/a
s24 = function (value) { if (value > halfMinusOne) { value -= decimal; } return Fn.constrain(value, -half, halfMinusOne); }
n/a
s32 = function (value) { if (value > halfMinusOne) { value -= decimal; } return Fn.constrain(value, -half, halfMinusOne); }
n/a
s4 = function (value) { if (value > halfMinusOne) { value -= decimal; } return Fn.constrain(value, -half, halfMinusOne); }
n/a
s8 = function (value) { if (value > halfMinusOne) { value -= decimal; } return Fn.constrain(value, -half, halfMinusOne); }
n/a
scale = function (value, fromLow, fromHigh, toLow, toHigh) { return ((value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow) | 0; }
...
function calibratedValues() {
return this.raw.map(function(value, i) {
var max = this.calibration.max[i],
min = this.calibration.min[i];
var scaled = __.scale(value, min, max, CALIBRATED_MIN_VALUE, CALIBRATED_MAX_VALUE
);
return __.constrain(scaled, CALIBRATED_MIN_VALUE, CALIBRATED_MAX_VALUE);
}, this);
}
function maxLineValue() {
return (this.sensors.length - 1) * CALIBRATED_MAX_VALUE;
}
...
square = function (x) { return x * x; }
n/a
function sum(values) { var vals; if (Array.isArray(values)) { vals = values; } else { vals = [].slice.call(arguments); } return vals.reduce(function(accum, value) { return accum + value; }, 0); }
n/a
toFixed = function (number, digits) { // Guard against error when number is null or undefined // Cast result as number return +(number || 0).toFixed(digits); }
n/a
u10 = function (value) { if (value < 0) { value += decimal; } return Fn.constrain(value, 0, decimal - 1); }
n/a
u12 = function (value) { if (value < 0) { value += decimal; } return Fn.constrain(value, 0, decimal - 1); }
n/a
u16 = function (value) { if (value < 0) { value += decimal; } return Fn.constrain(value, 0, decimal - 1); }
n/a
u20 = function (value) { if (value < 0) { value += decimal; } return Fn.constrain(value, 0, decimal - 1); }
n/a
u24 = function (value) { if (value < 0) { value += decimal; } return Fn.constrain(value, 0, decimal - 1); }
n/a
u32 = function (value) { if (value < 0) { value += decimal; } return Fn.constrain(value, 0, decimal - 1); }
n/a
u4 = function (value) { if (value < 0) { value += decimal; } return Fn.constrain(value, 0, decimal - 1); }
n/a
u8 = function (value) { if (value < 0) { value += decimal; } return Fn.constrain(value, 0, decimal - 1); }
n/a
uid = function () { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(chr) { var rnd = Math.random() * 16 | 0; return (chr === "x" ? rnd : (rnd & 0x3 | 0x8)).toString(16); }).toUpperCase(); }
n/a
uint16 = function (msb, lsb) { return (msb << 8) | lsb; }
n/a
uint24 = function (b16, b8, b0) { return (b16 << 16) | (b8 << 8) | b0; }
n/a
uint32 = function (b24, b16, b8, b0) { // Note: If you left-shift a byte by 24 in JS and that byte's // MSbit is 1, the resulting value will be negative because JS casts // bitwise operands (temporarily) to SIGNED 32-bit numbers. The // final >>> 0 causes the sign bit to be disregarded, making sure our // result is non-negative. return ((b24 << 24) | (b16 << 16) | (b8 << 8) | b0) >>> 0; }
n/a
function GPS(opts) { var breakout, receiver, chip, state; if (!(this instanceof GPS)) { return new GPS(opts); } // Allow users to pass in a 2 element array for rx and tx pins if (Array.isArray(opts)) { opts = { pins: { rx: opts[0], tx: opts[1], onOff: opts[2] } }; } if (typeof opts.pins === "undefined") { opts.pins = {}; } Board.Component.call( this, opts = Board.Options(opts) ); // Get user values for breakout, receiver and chip breakout = opts.breakout || {}; receiver = opts.receiver; chip = opts.chip; // If a breakout is defined check for receiver and chip if (Breakouts[breakout]) { if (!receiver && Breakouts[breakout].receiver) { receiver = Breakouts[breakout].receiver.value; } if (!chip && Breakouts[breakout].chip) { chip = Breakouts[breakout].chip.value; } } // If a receiver was defined or derived but chip was not if (!chip) { if (receiver && Receivers[receiver].chip) { chip = Receivers[receiver].chip.value; } else { chip = "DEFAULT"; } } // Allow users to pass in custom chip types chip = typeof chip === "string" ? Chips[chip] : opts.chip; // Allow users to pass in custom receiver types receiver = typeof receiver === "string" ? Receivers[receiver] : opts.receiver; // Chip decorates the instance Object.defineProperties(this, chip); // Receiver decorates this instance if (receiver) { Object.defineProperties(this, receiver); } // breakout decorates the instance if (opts.breakout) { breakout = typeof opts.breakout === "string" ? Breakouts[opts.breakout] : opts.breakout; Board.Controller.call(this, breakout, opts); } // If necessary set default property values this.fixed = opts.fixed || 6; this.baud = opts.baud || this.baud; // Create a "state" entry for privately // storing the state of the instance state = { sat: {}, latitude: 0.0, longitude: 0.0, altitude: 0.0, speed: 0.0, course: 0.0, frequency: 1, lowPowerMode: false }; priv.set(this, state); // Getters for private state values Object.defineProperties(this, { latitude: { get: function() { return state.latitude; } }, longitude: { get: function() { return state.longitude; } }, altitude: { get: function() { return state.altitude; } }, sat: { get: function() { return state.sat; } }, speed: { get: function() { return state.speed; } }, course: { get: function() { return state.course; } }, time: { get: function() { return state.time; } } }); if (this.initialize) { this.initialize(opts); } }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
initialize = function (opts) { var state = priv.get(this); state.portId = opts.serialPort || opts.portId || opts.port || opts.bus || this.io.SERIAL_PORT_IDs.DEFAULT; // Set the pin modes ["tx", "rx"].forEach(function(pin) { if (this.pins[pin]) { this.io.pinMode(this.pins[pin], this.io.MODES.SERIAL); } }, this); if (this.pins.onOff) { this.io.pinMode(this.pins.onOff, this.io.MODES.OUTPUT); this.onOff = new Pin(this.pins.onOff); } this.io.serialConfig({ portId: state.portId, baud: this.baud, rxPin: this.pins.rx, txPin: this.pins.tx }); if (this.configure) { this.configure(function() { this.listen(); if (opts.frequency) { this.frequency = opts.frequency; } }.bind(this)); } }
...
return raw;
};
}
priv.set(this, state);
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
raw = data;
});
}
setInterval(function() {
if (raw === null) {
return;
...
listen = function () { var state = priv.get(this); var input = ""; // Start the read loop this.io.serialRead(state.portId, function(data) { input += new Buffer(data).toString("ascii"); var sentences = input.split("\r\n"); if (sentences.length > 1) { for (var i = 0; i < sentences.length - 1; i++) { this.parseNmeaSentence(sentences[i]); } input = sentences[sentences.length - 1]; } }.bind(this)); }
n/a
parseNmeaSentence = function (sentence) { var state = priv.get(this); var cksum = sentence.split("*"); // Check for valid sentence if (cksum[1] !== getNmeaChecksum(cksum[0].substring(1))) { return; } this.emit("sentence", sentence); var segments = cksum[0].split(","); var last = { latitude: state.latitude, longitude: state.longitude, altitude: state.altitude, speed: state.speed, course: state.course }; switch (segments[0]) { case "$GPGGA": // Time, position and fix related data state.time = segments[1]; state.latitude = degToDec(segments[2], 2, segments[3], this.fixed); state.longitude = degToDec(segments[4], 3, segments[5], this.fixed); state.altitude = Number(segments[9]); break; case "$GPGSA": // Operating details state.sat.satellites = segments.slice(3, 15); state.sat.pdop = Number(segments[15]); state.sat.hdop = Number(segments[16]); state.sat.vdop = Number(segments[17]); this.emit("operations", sentence); break; case "$GPRMC": // GPS & Transit data state.time = segments[1]; state.latitude = degToDec(segments[3], 2, segments[4], this.fixed); state.longitude = degToDec(segments[5], 3, segments[6], this.fixed); state.course = Number(segments[8]); state.speed = toFixed(segments[7] * 0.514444, this.fixed); break; case "$GPVTG": // Track Made Good and Ground Speed state.course = Number(segments[1]); state.speed = toFixed(segments[5] * 0.514444, this.fixed); break; case "$GPGSV": // Satellites in view break; case "$PGACK": // Acknowledge command this.emit("acknowledge", sentence); break; default: this.emit("unknown", sentence); break; } this.emit("data", { latitude: state.latitude, longitude: state.longitude, altitude: state.altitude, speed: state.speed, course: state.course, sat: state.sat, time: state.time }); if (last.latitude !== state.latitude || last.longitude !== state.longitude || last.altitude !== state.altitude) { this.emit("change", { latitude: state.latitude, longitude: state.longitude, altitude: state.altitude }); } if (last.speed !== state.speed || last.course !== state.course) { this.emit("navigation", { speed: state.speed, course: state.course }); } }
n/a
sendCommand = function (string) { var state = priv.get(this); var cc = []; // Convert the string to a charCode array for (var i = 0; i < string.length; ++i) { cc[i] = string.charCodeAt(i); } // Append *, checksum and cr/lf var hexsum = getNmeaChecksum(string.substring(1)); cc.push(42, hexsum.charCodeAt(0), hexsum.charCodeAt(1), 13, 10); this.io.serialWrite(state.portId, cc); }
n/a
function Gripper(opts) { if (!(this instanceof Gripper)) { return new Gripper(opts); } // Default options mode, assume only when opts is a pin number if (typeof opts === "number") { opts = { servo: { pin: opts, range: [0, 180] }, scale: [0, 10] }; } // Default set() args to 0-10 this.scale = opts.scale || [0, 10]; // Setup servo // Allows pre-constructed servo or creating new servo. // Defaults for new Servo creation fall back to Servo defaults this.servo = opts.servo instanceof Servo ? opts.servo : new Servo(opts.servo); }
n/a
close = function () { return this.servo.to( api.args.apply(this, [].slice.call(arguments)) ); }
n/a
open = function () { return this.servo.to( api.args.apply(this, [].slice.call(arguments)) ); }
n/a
set = function () { return this.servo.to( api.args.apply(this, [].slice.call(arguments)) ); }
...
if (!this.toScaledEuler) {
this.toScaledEuler = opts.toScaledEuler || function(raw) {
return raw;
};
}
priv.set(this, state);
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
raw = data;
});
}
...
function Gyro(opts) { if (!(this instanceof Gyro)) { return new Gyro(opts); } var controller = null; var isCalibrated = false; var sampleSize = 100; var state = { x: { angle: 0, value: 0, previous: 0, calibration: [], stash: [0, 0, 0, 0, 0], center: 0, hasValue: false }, y: { angle: 0, value: 0, previous: 0, calibration: [], stash: [0, 0, 0, 0, 0], center: 0, hasValue: false }, z: { angle: 0, value: 0, previous: 0, calibration: [], stash: [0, 0, 0, 0, 0], center: 0, hasValue: false } }; Board.Component.call( this, opts = Board.Options(opts) ); if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.ANALOG; } Board.Controller.call(this, controller, opts); if (!this.toNormal) { this.toNormal = opts.toNormal || function(raw) { return raw; }; } if (!this.toDegreesPerSecond) { this.toDegreesPerSecond = opts.toDegreesPerSecond || function(raw) { return raw; }; } priv.set(this, state); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { var isChange = false; Object.keys(data).forEach(function(axis) { var value = data[axis]; var sensor = state[axis]; sensor.previous = sensor.value; sensor.stash.shift(); sensor.stash.push(value); sensor.hasValue = true; sensor.value = (sum(sensor.stash) / 5) | 0; if (!isCalibrated && (state.x.calibration.length === sampleSize && state.y.calibration.length === sampleSize && (this.z === undefined || state.z.calibration.length === sampleSize))) { isCalibrated = true; state.x.center = (sum(state.x.calibration) / sampleSize) | 0; state.y.center = (sum(state.y.calibration) / sampleSize) | 0; state.z.center = (sum(state.z.calibration) / sampleSize) | 0; state.x.calibration.length = 0; state.y.calibration.length = 0; state.z.calibration.length = 0; } else { if (sensor.calibration.length < sampleSize) { sensor.calibration.push(value); } } if (sensor.previous !== sensor.value) { isChange = true; } }, this); if (isCalibrated) { state.x.angle += this.rate.x / 100; state.y.angle += this.rate.y / 100; state.z.angle += this.rate.z / 100; this.emit("data", { x: this.x, y: this.y, z: this.z }); if (isChange) { this.emit("change", { x: this.x, y: this.y, z: this.z }); } } }.bind(this)); } Object.defineProperties(this, { isCalibrated: { get: function() { return isCalibrated; }, set: function(value) { if (typeof value === "boolean") { isCalibrated = value; } } }, pitch: { get: function() { return { rate: toFixed(this.rate.y, 2), angle: toFixed(state.y.angle, 2) }; } }, roll: { get: function() { return { rate: toFixed(this.rate.x, 2), angle: toFixed(state.x.angle, 2) }; } }, yaw: { get: function() { return { rate: this.z !== undefined ? toFixed(this.rate.z, 2) : 0, angle: this.z !== undefined ? toFixed(state.z.angle, 2) : 0 }; } }, x: { get: function() { return toFixed(this.toNormal(state.x.value), 4); } }, y: { get: function() { return toFixed(this.toNormal(state.y.value), 4); } }, z: { get: function() { return state.z.hasValue ? toFixed(this.toNormal(state. ...
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
recalibrate = function () { this.isCalibrated = false; }
n/a
function Hygrometer(opts) { if (!(this instanceof Hygrometer)) { return new Hygrometer(opts); } var controller = null; var last = null; var raw = null; Board.Component.call( this, opts = Board.Options(opts) ); var freq = opts.freq || 25; if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { throw new Error("Missing Hygrometer controller"); } priv.set(this, {}); Board.Controller.call(this, controller, opts); if (!this.toRelativeHumidity) { this.toRelativeHumidity = opts.toRelativeHumidity || function(x) { return x; }; } var propDescriptors = { relativeHumidity: { get: function() { return this.toRelativeHumidity(raw); } } }; // Convenience aliases propDescriptors.RH = propDescriptors.relativeHumidity; Object.defineProperties(this, propDescriptors); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { raw = data; }); } setInterval(function() { if (raw == null) { return; } if (Number.isNaN(this.relativeHumidity)) { return; } var data = {}; data.RH = data.relativeHumidity = this.relativeHumidity; this.emit("data", data); if (this.relativeHumidity !== last) { last = this.relativeHumidity; this.emit("change", data); } }.bind(this), freq); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function IMU(opts) { if (!(this instanceof IMU)) { return new IMU(opts); } var controller, state; Board.Component.call( this, opts = Board.Options(opts) ); if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { throw new Error("Missing IMU/Multi controller"); } this.freq = opts.freq || 20; state = {}; priv.set(this, state); Board.Controller.call(this, controller, opts); if (typeof this.initialize === "function") { this.initialize(opts); } // The IMU/Multi isn't considered "ready" // until one of the components has notified via // a change event. this.isReady = false; setInterval(function() { if (this.isReady) { this.emit("data", this); } }.bind(this), this.freq); var awaiting = this.components.slice(); if (this.components && this.components.length > 0) { this.components.forEach(function(component) { if (!(this[component] instanceof Emitter)) { return; } this[component].on("change", function() { if (awaiting.length) { var index = awaiting.indexOf(component); if (index !== -1) { awaiting.splice(index, 1); } } if (!awaiting.length && !this.isReady) { this.isReady = true; } if (this.isReady) { this.emit("change", this, component); } }.bind(this)); }, this); } }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
clear = function () { activeDrivers.clear(); }
n/a
get = function (board, driverName, opts) { var drivers, driverKey, driver; if (!activeDrivers.has(board)) { activeDrivers.set(board, {}); } opts = opts || {}; drivers = activeDrivers.get(board); driverKey = Drivers[driverName].identifier.value(opts); if (!drivers[driverKey]) { driver = new Emitter(); Object.defineProperties(driver, Drivers[driverName]); driver.initialize(board, opts); drivers[driverKey] = driver; } return drivers[driverKey]; }
...
var Controllers = {
BNO055: {
initialize: {
value: function(opts, dataHandler) {
var IMU = require("./imu"),
driver = IMU.Drivers.get(this.board, "BNO055", opts);
driver.on("data", function(data) {
dataHandler(data);
});
}
},
toScaledEuler: {
...
IR = function () { throw new Error("IR has been removed. Use Motion or Proximity instead."); }
n/a
Distance = function () { throw new Error("IR.Distance has been removed. Use Proximity instead."); }
n/a
Motion = function () { throw new Error("IR.Motion has been removed. Use Motion instead."); }
n/a
Proximity = function () { throw new Error("IR.Proximity has been removed. Use Proximity instead."); }
n/a
function ReflectanceArray(opts) { if (!(this instanceof ReflectanceArray)) { return new ReflectanceArray(opts); } this.opts = Board.Options(opts); Board.Component.call( this, this.opts, { requestPin: false } ); // Read event throttling this.freq = opts.freq || 25; // Make private data entry var state = { lastLine: 0, isOn: false, calibration: { min: [], max: [] }, autoCalibrate: opts.autoCalibrate || false }; priv.set(this, state); initialize.call(this); Object.defineProperties(this, { isOn: { get: function() { return state.emitter.isOn; } }, isCalibrated: { get: function() { return calibrationIsValid(this.calibration, this.sensors); } }, isOnLine: { get: function() { var line = this.line; return line > CALIBRATED_MIN_VALUE && line < maxLineValue.call(this); } }, sensors: { get: function() { return state.sensorStates.map(function(sensorState) { return sensorState.sensor; }); } }, calibration: { get: function() { return state.calibration; } }, raw: { get: function() { return state.sensorStates.map(function(sensorState) { return sensorState.rawValue; }); } }, values: { get: function() { return this.isCalibrated ? calibratedValues.call(this) : this.raw; } }, line: { get: function() { return this.isCalibrated ? getLine.call(this) : 0; } } }); }
n/a
function ReflectanceArray(opts) { if (!(this instanceof ReflectanceArray)) { return new ReflectanceArray(opts); } this.opts = Board.Options(opts); Board.Component.call( this, this.opts, { requestPin: false } ); // Read event throttling this.freq = opts.freq || 25; // Make private data entry var state = { lastLine: 0, isOn: false, calibration: { min: [], max: [] }, autoCalibrate: opts.autoCalibrate || false }; priv.set(this, state); initialize.call(this); Object.defineProperties(this, { isOn: { get: function() { return state.emitter.isOn; } }, isCalibrated: { get: function() { return calibrationIsValid(this.calibration, this.sensors); } }, isOnLine: { get: function() { var line = this.line; return line > CALIBRATED_MIN_VALUE && line < maxLineValue.call(this); } }, sensors: { get: function() { return state.sensorStates.map(function(sensorState) { return sensorState.sensor; }); } }, calibration: { get: function() { return state.calibration; } }, raw: { get: function() { return state.sensorStates.map(function(sensorState) { return sensorState.rawValue; }); } }, values: { get: function() { return this.isCalibrated ? calibratedValues.call(this) : this.raw; } }, line: { get: function() { return this.isCalibrated ? getLine.call(this) : 0; } } }); }
n/a
calibrate = function () { var state = priv.get(this); this.once("data", function(values) { setCalibration(state.calibration, values); this.emit("calibrated"); }); return this; }
...
};
// This will continue to calibrate until the predicate is true.
// Allows the user to calibrate n-times, or wait for user input,
// or base it on calibration heuristics. However the user wants.
ReflectanceArray.prototype.calibrateUntil = function(predicate) {
var loop = function() {
this.calibrate();
this.once("calibrated", function() {
if (!predicate()) {
loop();
}
});
}.bind(this);
...
calibrateUntil = function (predicate) { var loop = function() { this.calibrate(); this.once("calibrated", function() { if (!predicate()) { loop(); } }); }.bind(this); loop(); return this; }
n/a
disable = function () { var state = priv.get(this); state.emitter.off(); return this; }
n/a
enable = function () { var state = priv.get(this); state.emitter.on(); return this; }
n/a
loadCalibration = function (calibration) { var state = priv.get(this); if (!calibrationIsValid(calibration, this.sensors)) { throw new Error("Calibration data not properly set: {min: [], max: []}"); } state.calibration = calibration; return this; }
n/a
function Joystick(opts) { if (!(this instanceof Joystick)) { return new Joystick(opts); } var controller = null; var state = { x: { invert: false, value: 0, previous: 0, zeroV: 0, calibrated: false }, y: { invert: false, value: 0, previous: 0, zeroV: 0, calibrated: false } }; Board.Component.call( this, opts = Board.Options(opts) ); if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.ANALOG; } Board.Controller.call(this, controller, opts); if (!this.toAxis) { this.toAxis = opts.toAxis || function(raw) { return raw; }; } state.x.zeroV = opts.zeroV === undefined ? 0 : (opts.zeroV.x || 0); state.y.zeroV = opts.zeroV === undefined ? 0 : (opts.zeroV.y || 0); state.x.invert = opts.invertX || opts.invert || false; state.y.invert = opts.invertY || opts.invert || false; priv.set(this, state); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { var isChange = false; var computed = { x: null, y: null }; Object.keys(data).forEach(function(axis) { var value = data[axis]; var sensor = state[axis]; // Set the internal ADC reading value... sensor.value = value; if (!state[axis].calibrated) { state[axis].calibrated = true; state[axis].zeroV = value; isChange = true; } // ... Get the computed axis value. computed[axis] = this[axis]; var absAxis = Math.abs(computed[axis]); var absPAxis = Math.abs(sensor.previous); if ((absAxis < absPAxis) || (absAxis > absPAxis)) { isChange = true; } sensor.previous = computed[axis]; }, this); this.emit("data", { x: computed.x, y: computed.y }); if (isChange) { this.emit("change", { x: computed.x, y: computed.y }); } }.bind(this)); } Object.defineProperties(this, { x: { get: function() { return this.toAxis(state.x.value, "x") * (state.x.invert ? -1 : 1); } }, y: { get: function() { return this.toAxis(state.y.value, "y") * (state.y.invert ? -1 : 1); } } }); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function Keypad(opts) { if (!(this instanceof Keypad)) { return new Keypad(opts); } // Initialize a Device instance on a Board Board.Component.call( this, opts = Board.Options(opts) ); var raw = null; var controller = null; var state = { touches: null, timeout: null, length: null, keys: null, mapping: null, holdtime: null, }; var trigger = Fn.debounce(function(type, value) { var event = { type: type, which: value, timestamp: Date.now() }; aliases[type].forEach(function(type) { this.emit(type, event); }, this); this.emit("change", Object.assign({}, event)); }, 5); if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.ANALOG; } Board.Controller.call(this, controller, opts); state.holdtime = opts.holdtime ? opts.holdtime : 500; priv.set(this, state); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { raw = data; var now = Date.now(); var indices = this.toIndices(data); var kLength = state.length; var lists = { down: [], hold: [], up: [], }; var target = null; var alias = null; for (var k = 0; k < kLength; k++) { alias = this.toAlias(k); if (indices.includes(k)) { if (state.touches[k].value === 0) { state.touches[k].timeout = now + state.holdtime; lists.down.push(alias); } else if (state.touches[k].value === 1) { if (state.touches[k].timeout !== null && now > state.touches[k].timeout) { state.touches[k].timeout = now + state.holdtime; lists.hold.push(alias); } } state.touches[k].value = 1; } else { if (state.touches[k].value === 1) { state.touches[k].timeout = null; lists.up.push(alias); } state.touches[k].value = 0; } target = null; alias = null; } Object.keys(lists).forEach(function(key) { var list = lists[key]; if (list.length) { trigger.call(this, key, list); } }, this); }.bind(this)); } Object.defineProperties(this, { isMultitouch: { get: function() { return state.isMultitouch; } }, value: { get: function() { return raw; } }, }); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function LCD(opts) { if (!(this instanceof LCD)) { return new LCD(opts); } Board.Component.call( this, opts = Board.Options(opts) ); var controller = null; if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.PARALLEL; } Board.Controller.call(this, controller, opts); this.ctype = opts.controller; if (this.initialize) { this.initialize(opts); } Object.defineProperties(this, { characters: { get: function() { return Object.assign({}, priv.get(this).characters); }, }, }); }
n/a
autoscroll = function () { var state = priv.get(this); state.display |= this.REGISTER.ENTRYSHIFTINCREMENT; this.command(this.REGISTER.ENTRY | state.display); return this; }
n/a
backlight = function (highOrLow) { var state = priv.get(this); highOrLow = typeof highOrLow === "undefined" ? true : false; if (state.backlight.pin instanceof Pin) { if (highOrLow) { state.backlight.pin.high(); } else { state.backlight.pin.low(); } } if (highOrLow) { state.display |= this.REGISTER.DISPLAYON; } else { state.display &= ~this.REGISTER.DISPLAYON; } this.command(state.display); return this; }
n/a
blink = function () { var state = priv.get(this); state.display |= this.REGISTER.BLINKON; this.command(state.display); return this; }
...
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
<img src="https://github.com/rwaldron/johnny-five/raw/master/assets/led-blink.gif">
> Note: Node will crash if you try to run johnny-five in the node REPL, but board instances will create their own contextual
REPL. Put your script in a file.
...
clear = function () { this.command(this.REGISTER.CLEAR); sleep(2); return this; }
n/a
command = function (mode, value) { if (typeof value === "undefined") { value = mode; mode = 0x80; } if (this.bitMode === 4) { this.send(value >> 4); } this.send(value); return this; }
n/a
createChar = function (name, charMap) { // Ensure location is never above 7 var state = priv.get(this); var address; if (typeof name === "number") { address = name & 0x07; } else { address = state.index; state.index--; if (state.index === -1) { state.index = this.REGISTER.MEMORYLIMIT - 1; } } this.command(this.REGISTER.SETCGRAMADDR | (address << 3)); this.hilo(function() { for (var i = 0; i < 8; i++) { this.command(this.REGISTER.DATA, charMap[i]); } }); // Fill in address state.characters[name] = address; return address; }
n/a
cursor = function (row, col) { // When provided with col & row, cursor will behave like setCursor, // except that it has row and col in the order that most people // intuitively expect it to be in. if (typeof col !== "undefined" && typeof row !== "undefined") { return this.setCursor(col, row); } var state = priv.get(this); state.display |= this.REGISTER.CURSORON; this.command(state.display); return this; }
n/a
hilo = function (callback) { // RS High for write mode this.io.digitalWrite(this.pins.rs, this.io.HIGH); callback.call(this); // RS Low for command mode this.io.digitalWrite(this.pins.rs, this.io.LOW); }
n/a
home = function () { this.command(this.REGISTER.HOME); sleep(2); return this; }
n/a
noAutoscroll = function () { var state = priv.get(this); state.display &= ~this.REGISTER.ENTRYSHIFTINCREMENT; this.command(this.REGISTER.ENTRY | state.display); return this; }
n/a
noBacklight = function () { var state = priv.get(this); if (state.backlight.pin instanceof Pin) { state.backlight.pin.high(); } // if (highOrLow) { // state.display |= this.REGISTER.DISPLAYON; // } else { // state.display &= ~this.REGISTER.DISPLAYON; // } // this.command(state.display); return this.backlight(false); }
n/a
noBlink = function () { var state = priv.get(this); state.display &= ~this.REGISTER.BLINKON; this.command(state.display); return this; }
n/a
noCursor = function () { var state = priv.get(this); state.display &= ~this.REGISTER.CURSORON; this.command(state.display); return this; }
n/a
off = function () { var state = priv.get(this); state.display &= ~this.REGISTER.DISPLAYON; this.command(state.display); return this; }
...
return this;
};
ReflectanceArray.prototype.disable = function() {
var state = priv.get(this);
state.emitter.off();
return this;
};
// Calibrate will store the min/max values for this sensor array
// It should be called many times in order to get a lot of readings
// on light and dark areas. See calibrateUntil for a convenience
...
on = function () { var state = priv.get(this); state.display |= this.REGISTER.DISPLAYON; this.command(state.display); return this; }
...
The ubiquitous "Hello World" program of the microcontroller and SoC world is "blink an LED". The following code
demonstrates how this is done using the Johnny-Five framework.
```javascript
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
...
print = function (message, opts) { var state, dontProcessSpecials, hasCharacters, processed; message = message + ""; opts = opts || {}; state = priv.get(this); dontProcessSpecials = opts.dontProcessSpecials || false; hasCharacters = !dontProcessSpecials && RE_SPECIALS.test(message); if (message.length === 1) { this.hilo(function() { this.command(this.REGISTER.DATA, message.charCodeAt(0)); }); } else { if (hasCharacters) { processed = message.replace(RE_SPECIALS, function(match, name) { var address = state.characters[name]; return typeof address === "number" ? String.fromCharCode(address) : match; }); this.print(processed, { dontProcessSpecials: true }); } else { this.hilo(function() { Array.from(message).forEach(function(character) { this.command(this.REGISTER.DATA, character.charCodeAt(0)); }, this); }); } } return this; }
n/a
send = function (value) { var pin = 0; var mask = { 4: 8, 8: 128 }[this.bitMode]; for (; mask > 0; mask = mask >> 1) { this.io.digitalWrite( this.pins.data[pin], this.io[value & mask ? "HIGH" : "LOW"] ); pin++; } ["LOW", "HIGH", "LOW"].forEach(function(val) { this.io.digitalWrite(this.pins.en, this.io[val]); }, this); return this; }
n/a
setCursor = function (col, row) { var rowOffsets = [0x00, 0x40, 0x14, 0x54]; this.command(this.REGISTER.SETDDRAMADDR | (col + rowOffsets[row])); return this; }
n/a
useChar = function (name) { var state = priv.get(this); if (typeof state.characters[name] === "undefined") { // Create the character in LCD memory and var newCharIndex = this.createChar(name, this.CHARS[name]); // If character's index already used, remove this character in current LCD character map // because it's not in LCD memory anymore. for (var oldName in state.characters) { if (name !== oldName && state.characters[oldName] === newCharIndex) { delete state.characters[oldName]; break; } } // Add character to current LCD character map state.characters[name] = newCharIndex; } return this; }
n/a
write = function (charCode) { this.hilo.call(this, function() { this.command(this.REGISTER.DATA, charCode); }); return this; }
...
EVS.isRawSensor = function(port) {
return port.analog === EVS.S1_ANALOG || port.analog === EVS.S2_ANALOG;
};
util.inherits(EVS, Emitter);
EVS.prototype.setup = function(port, type) {
this.bank[port.bank].write(port.mode, [type]);
};
EVS.prototype.read = function(port, register, numBytes, callback) {
if (port.sensor && port.offset && !EVS.isRawSensor(port)) {
register += port.offset;
}
...
function Led(opts) {
if (!(this instanceof Led)) {
return new Led(opts);
}
var pinValue = typeof opts === "object" ? opts.pin : opts;
var controller = null;
Board.Component.call(
this, opts = Board.Options(opts)
);
if (opts.controller && typeof opts.controller === "string") {
controller = Controllers[opts.controller.toUpperCase()];
} else {
controller = opts.controller;
}
if (controller == null) {
controller = Controllers.DEFAULT;
}
Object.defineProperties(this, controller);
var state = {
isAnode: opts.isAnode,
isOn: false,
isRunning: false,
value: null,
direction: 1,
mode: null,
intensity: 0,
interval: null
};
priv.set(this, state);
Object.defineProperties(this, {
value: {
get: function() {
return state.value;
}
},
mode: {
get: function() {
return state.mode;
}
},
isOn: {
get: function() {
return !!state.value;
}
},
isRunning: {
get: function() {
return state.isRunning;
}
},
animation: {
get: function() {
return state.animation;
}
}
});
/* istanbul ignore else */
if (typeof this.initialize === "function") {
this.initialize(opts, pinValue);
}
}
...
```javascript
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
<img src="https://github.com/rwaldron/johnny-five/raw/master/assets/led-blink.gif">
...
function Leds(numsOrObjects) { if (!(this instanceof Leds)) { return new Leds(numsOrObjects); } Object.defineProperty(this, "type", { value: Led }); Collection.call(this, numsOrObjects); }
n/a
function Leds(numsOrObjects) { if (!(this instanceof Leds)) { return new Leds(numsOrObjects); } Object.defineProperty(this, "type", { value: Led }); Collection.call(this, numsOrObjects); }
n/a
function Digits(opts) { opts.isMatrix = false; return new LedControl(opts); }
n/a
function Matrix(opts) { opts.isMatrix = true; return new LedControl(opts); }
n/a
function RGB(opts) { if (!(this instanceof RGB)) { return new RGB(opts); } var controller = null; if (Array.isArray(opts)) { // RGB([Byte, Byte, Byte]) shorthand // Convert to opts.pins array definition opts = { pins: opts }; // If opts.pins is an object, convert to array } else if (typeof opts.pins === "object" && !Array.isArray(opts.pins)) { opts.pins = [opts.pins.red, opts.pins.green, opts.pins.blue]; } Board.Component.call( this, opts = Board.Options(opts) ); if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.DEFAULT; } // The default color is #ffffff, but the light will be off var state = { red: 255, green: 255, blue: 255, intensity: 100, isAnode: opts.isAnode || false, interval: null }; // red, green, and blue store the raw color set via .color() // values takes state into account, such as on/off and intensity state.values = { red: state.red, green: state.green, blue: state.blue }; priv.set(this, state); Board.Controller.call(this, controller, opts); Object.defineProperties(this, { isOn: { get: function() { return RGB.colors.some(function(color) { return state[color] > 0; }); } }, isRunning: { get: function() { return !!state.interval; } }, isAnode: { get: function() { return state.isAnode; } }, values: { get: function() { return Object.assign({}, state.values); } }, update: { value: function(colors) { var state = priv.get(this); colors = colors || this.color(); state.values = RGB.ToScaledRGB(state.intensity, colors); this.write(state.values); Object.assign(state, colors); } } }); this.initialize(opts); this.off(); }
n/a
function RGBs(numsOrObjects) { if (!(this instanceof RGBs)) { return new RGBs(numsOrObjects); } Object.defineProperty(this, "type", { value: RGB }); Collection.call(this, numsOrObjects); }
n/a
function RGB(opts) { if (!(this instanceof RGB)) { return new RGB(opts); } var controller = null; if (Array.isArray(opts)) { // RGB([Byte, Byte, Byte]) shorthand // Convert to opts.pins array definition opts = { pins: opts }; // If opts.pins is an object, convert to array } else if (typeof opts.pins === "object" && !Array.isArray(opts.pins)) { opts.pins = [opts.pins.red, opts.pins.green, opts.pins.blue]; } Board.Component.call( this, opts = Board.Options(opts) ); if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.DEFAULT; } // The default color is #ffffff, but the light will be off var state = { red: 255, green: 255, blue: 255, intensity: 100, isAnode: opts.isAnode || false, interval: null }; // red, green, and blue store the raw color set via .color() // values takes state into account, such as on/off and intensity state.values = { red: state.red, green: state.green, blue: state.blue }; priv.set(this, state); Board.Controller.call(this, controller, opts); Object.defineProperties(this, { isOn: { get: function() { return RGB.colors.some(function(color) { return state[color] > 0; }); } }, isRunning: { get: function() { return !!state.interval; } }, isAnode: { get: function() { return state.isAnode; } }, values: { get: function() { return Object.assign({}, state.values); } }, update: { value: function(colors) { var state = priv.get(this); colors = colors || this.color(); state.values = RGB.ToScaledRGB(state.intensity, colors); this.write(state.values); Object.assign(state, colors); } } }); this.initialize(opts); this.off(); }
n/a
function RGBs(numsOrObjects) { if (!(this instanceof RGBs)) { return new RGBs(numsOrObjects); } Object.defineProperty(this, "type", { value: RGB }); Collection.call(this, numsOrObjects); }
n/a
ToRGB = function (red, green, blue) {
var update = {};
var flags = 0;
var input;
if (typeof red !== "undefined") {
// 0b100
flags |= 1 << 2;
}
if (typeof green !== "undefined") {
// 0b010
flags |= 1 << 1;
}
if (typeof blue !== "undefined") {
// 0b001
flags |= 1 << 0;
}
if ((flags | 0x04) === 0x04) {
input = red;
if (input == null) {
throw new Error("Invalid color (" + input + ")");
}
/* istanbul ignore else */
if (Array.isArray(input)) {
// color([Byte, Byte, Byte])
update = {
red: input[0],
green: input[1],
blue: input[2]
};
} else if (typeof input === "object") {
// color({
// red: Byte,
// green: Byte,
// blue: Byte
// });
update = {
red: input.red,
green: input.green,
blue: input.blue
};
} else if (typeof input === "string") {
// color("#ffffff") or color("ffffff")
if (/^#?[0-9A-Fa-f]{6}$/.test(input)) {
// remove the leading # if there is one
if (input.length === 7 && input[0] === "#") {
input = input.slice(1);
}
update = {
red: parseInt(input.slice(0, 2), 16),
green: parseInt(input.slice(2, 4), 16),
blue: parseInt(input.slice(4, 6), 16)
};
} else {
// color("rgba(r, g, b, a)") or color("rgb(r, g, b)")
// color("rgba(r g b a)") or color("rgb(r g b)")
if (/^rgb/.test(input)) {
var args = input.match(/^rgba?\(([^)]+)\)$/)[1].split(/[\s,]+/);
// If the values were %...
if (isPercentString(args[0])) {
args.forEach(function(value, index) {
// Only convert the first 3 values
if (index <= 2) {
args[index] = Math.round((parseInt(value, 10) / 100) * 255);
}
});
}
update = {
red: parseInt(args[0], 10),
green: parseInt(args[1], 10),
blue: parseInt(args[2], 10)
};
// If rgba(...)
if (args.length > 3) {
if (isPercentString(args[3])) {
args[3] = parseInt(args[3], 10) / 100;
}
update = RGB.ToScaledRGB(100 * parseFloat(args[3]), update);
}
} else {
// color name
return RGB.ToRGB(converter.keyword.rgb(input.toLowerCase()));
}
}
}
} else {
// color(red, green, blue)
update = {
red: red,
green: green,
blue: blue
};
}
return update;
}
n/a
ToScaledRGB = function (intensity, colors) { var scale = intensity / 100; return RGB.colors.reduce(function(current, color) { return (current[color] = Math.round(colors[color] * scale), current); }, {}); }
n/a
blink = function (duration, callback) { var state = priv.get(this); // Avoid traffic jams this.stop(); if (typeof duration === "function") { callback = duration; duration = null; } state.interval = setInterval(function() { this.toggle(); if (typeof callback === "function") { callback(); } }.bind(this), duration || 100); return this; }
...
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
<img src="https://github.com/rwaldron/johnny-five/raw/master/assets/led-blink.gif">
> Note: Node will crash if you try to run johnny-five in the node REPL, but board instances will create their own contextual
REPL. Put your script in a file.
...
color = function (red, green, blue) { var state = priv.get(this); var colors; if (arguments.length === 0) { // Return a copy of the state values, // not a reference to the state object itself. colors = this.isOn ? state : state.prev; return RGB.colors.reduce(function(current, color) { return (current[color] = Math.round(colors[color]), current); }, {}); } var update = RGB.ToRGB(red, green, blue); // Validate all color values before writing any values RGB.colors.forEach(function(color) { var value = update[color]; if (value == null) { throw new Error("Led.RGB.color: invalid color ([" + [update.red, update.green, update.blue].join(",") + "])"); } value = Fn.constrain(value, 0, 255); update[color] = value; }, this); this.update(update); return this; }
n/a
intensity = function (intensity) { var state = priv.get(this); if (arguments.length === 0) { return state.intensity; } state.intensity = Fn.constrain(intensity, 0, 100); this.update(); return this; }
n/a
off = function () {
var state = priv.get(this);
// If it's already off, do nothing so the pervious state stays intact
/* istanbul ignore else */
if (this.isOn) {
state.prev = RGB.colors.reduce(function(current, color) {
return (current[color] = state[color], current);
}.bind(this), {});
this.update({
red: 0,
green: 0,
blue: 0
});
}
return this;
}
...
return this;
};
ReflectanceArray.prototype.disable = function() {
var state = priv.get(this);
state.emitter.off();
return this;
};
// Calibrate will store the min/max values for this sensor array
// It should be called many times in order to get a lot of readings
// on light and dark areas. See calibrateUntil for a convenience
...
on = function () {
var state = priv.get(this);
var colors;
// If it's not already on, we set them to the previous color
if (!this.isOn) {
/* istanbul ignore next */
colors = state.prev || {
red: 255,
green: 255,
blue: 255
};
state.prev = null;
this.update(colors);
}
return this;
}
...
The ubiquitous "Hello World" program of the microcontroller and SoC world is "blink an LED". The following code
demonstrates how this is done using the Johnny-Five framework.
```javascript
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
...
stop = function () {
var state = priv.get(this);
if (state.interval) {
clearInterval(state.interval);
}
/* istanbul ignore if */
if (state.animation) {
state.animation.stop();
}
state.interval = null;
return this;
}
n/a
strobe = function (duration, callback) { var state = priv.get(this); // Avoid traffic jams this.stop(); if (typeof duration === "function") { callback = duration; duration = null; } state.interval = setInterval(function() { this.toggle(); if (typeof callback === "function") { callback(); } }.bind(this), duration || 100); return this; }
n/a
toggle = function () { return this[this.isOn ? "off" : "on"](); }
n/a
function RGBs(numsOrObjects) { if (!(this instanceof RGBs)) { return new RGBs(numsOrObjects); } Object.defineProperty(this, "type", { value: RGB }); Collection.call(this, numsOrObjects); }
n/a
function Collection(numsOrObjects) {
var Type = this.type;
var initObjects = [];
this.length = 0;
if (Array.isArray(numsOrObjects)) {
initObjects = numsOrObjects;
} else {
// Initialize with a Shared Properties object
/* istanbul ignore else */
if (Array.isArray(numsOrObjects.pins)) {
var keys = Object.keys(numsOrObjects).filter(function(key) {
return key !== "pins";
});
initObjects = numsOrObjects.pins.map(function(pin) {
var obj = {};
if (Array.isArray(pin)) {
obj.pins = pin;
} else {
obj.pin = pin;
}
return keys.reduce(function(accum, key) {
accum[key] = numsOrObjects[key];
return accum;
}, obj);
});
}
}
/* istanbul ignore else */
if (initObjects.length) {
while (initObjects.length) {
var numOrObject = initObjects.shift();
// When a Type exists, respect it!
if (typeof Type === "function") {
if (!(numOrObject instanceof Type || numOrObject instanceof this.constructor)) {
numOrObject = new Type(numOrObject);
}
}
this.add(numOrObject);
}
}
}
n/a
blink = function (duration, callback) {
var length = this.length;
var signals = [];
var led;
if (typeof duration === "function") {
callback = duration;
duration = 1000;
}
if (typeof callback !== "function") {
callback = noop;
}
for (var i = 0; i < length; i++) {
led = this[i];
signals.push(
/* jshint ignore:start */
new Promise(function(resolve) {
led[method](duration, function() {
resolve();
});
})
/* jshint ignore:end */
);
}
Promise.all(signals).then(callback);
return this;
}
...
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
<img src="https://github.com/rwaldron/johnny-five/raw/master/assets/led-blink.gif">
> Note: Node will crash if you try to run johnny-five in the node REPL, but board instances will create their own contextual
REPL. Put your script in a file.
...
color = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
intensity = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
off = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
...
return this;
};
ReflectanceArray.prototype.disable = function() {
var state = priv.get(this);
state.emitter.off();
return this;
};
// Calibrate will store the min/max values for this sensor array
// It should be called many times in order to get a lot of readings
// on light and dark areas. See calibrateUntil for a convenience
...
on = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
...
The ubiquitous "Hello World" program of the microcontroller and SoC world is "blink an LED". The following code
demonstrates how this is done using the Johnny-Five framework.
```javascript
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
...
stop = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
strobe = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
toggle = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
blink = function (duration, callback) { var state = priv.get(this); // Avoid traffic jams this.stop(); if (typeof duration === "function") { callback = duration; duration = null; } state.isRunning = true; state.interval = setInterval(function() { this.toggle(); if (typeof callback === "function") { callback(); } }.bind(this), duration || 100); return this; }
...
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
<img src="https://github.com/rwaldron/johnny-five/raw/master/assets/led-blink.gif">
> Note: Node will crash if you try to run johnny-five in the node REPL, but board instances will create their own contextual
REPL. Put your script in a file.
...
brightness = function (brightness) { var state = priv.get(this); state.value = brightness; this.update(); return this; }
n/a
fade = function (val, duration, callback) {
var state = priv.get(this);
this.stop();
var options = {
duration: typeof duration === "number" ? duration : 1000,
keyFrames: [null, typeof val === "number" ? val : 0xff],
easing: "outSine",
oncomplete: function() {
state.isRunning = false;
/* istanbul ignore else */
if (typeof callback === "function") {
callback();
}
}
};
if (typeof val === "object") {
Object.assign(options, val);
}
if (typeof val === "function") {
callback = val;
}
if (typeof duration === "object") {
Object.assign(options, duration);
}
if (typeof duration === "function") {
callback = duration;
}
state.isRunning = true;
state.animation = state.animation || new Animation(this);
state.animation.enqueue(options);
return this;
}
n/a
fadeIn = function (duration, callback) { return this.fade(255, duration || 1000, callback); }
n/a
fadeOut = function (duration, callback) { return this.fade(0, duration || 1000, callback); }
n/a
intensity = function (intensity) { var state = priv.get(this); if (arguments.length === 0) { return state.intensity; } state.intensity = Fn.constrain(intensity, 0, 100); return this.brightness(Fn.scale(state.intensity, 0, 100, 0, 255)); }
n/a
off = function () { var state = priv.get(this); state.value = 0; this.update(); return this; }
...
return this;
};
ReflectanceArray.prototype.disable = function() {
var state = priv.get(this);
state.emitter.off();
return this;
};
// Calibrate will store the min/max values for this sensor array
// It should be called many times in order to get a lot of readings
// on light and dark areas. See calibrateUntil for a convenience
...
on = function () { var state = priv.get(this); if (state.mode === this.io.MODES.OUTPUT) { state.value = this.io.HIGH; } if (state.mode === this.io.MODES.PWM) { // Assume we need to simply turn this all the way on, when: // ...state.value is null if (state.value === null) { state.value = 255; } // ...there is no active interval if (!state.interval) { state.value = 255; } // ...the last value was 0 if (state.value === 0) { state.value = 255; } } this.update(); return this; }
...
The ubiquitous "Hello World" program of the microcontroller and SoC world is "blink an LED". The following code
demonstrates how this is done using the Johnny-Five framework.
```javascript
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
...
pulse = function (duration, callback) {
var state = priv.get(this);
this.stop();
var options = {
duration: typeof duration === "number" ? duration : 1000,
keyFrames: [0, 0xff],
metronomic: true,
loop: true,
easing: "inOutSine",
onloop: function() {
/* istanbul ignore else */
if (typeof callback === "function") {
callback();
}
}
};
if (typeof duration === "object") {
Object.assign(options, duration);
}
if (typeof duration === "function") {
callback = duration;
}
state.isRunning = true;
state.animation = state.animation || new Animation(this);
state.animation.enqueue(options);
return this;
}
n/a
stop = function () { var state = priv.get(this); if (state.interval) { clearInterval(state.interval); } if (state.animation) { state.animation.stop(); } state.interval = null; state.isRunning = false; return this; }
n/a
strobe = function (duration, callback) { var state = priv.get(this); // Avoid traffic jams this.stop(); if (typeof duration === "function") { callback = duration; duration = null; } state.isRunning = true; state.interval = setInterval(function() { this.toggle(); if (typeof callback === "function") { callback(); } }.bind(this), duration || 100); return this; }
n/a
toggle = function () { return this[this.isOn ? "off" : "on"](); }
n/a
function LedControl(opts) {
Board.Component.call(
this, opts = Board.Options(opts)
);
/*
device instance uses an interface from Controllers:
either MAX 7219 (default) or HT16K33
*/
var controller = null;
if (typeof opts.controller === "string") {
controller = Controllers[opts.controller];
} else {
controller = opts.controller;
}
if (typeof controller === "undefined") {
controller = Controllers.DEFAULT;
}
// functions from Controller interface
this.clear = controller.clear;
this.led = controller.led;
this.row = controller.row;
this.scanLimit = controller.scanLimit;
this.send = controller.send;
this.sendDigit = controller.sendDigit;
this.initialize = controller.initialize;
// controller specific op codes
this.OP = controller.OP;
// digit indexes may be ordered left to right (1) or reversed (-1)
this.digitOrder = 1;
// Does the device have a built-in colon?
/* istanbul ignore else */
if (!this.isMatrix) {
this.colon = opts.colon || false;
}
// extra functions for HT16K33 devices only
if (controller.writeDisplay) {
this.writeDisplay = controller.writeDisplay;
}
if (controller.blink) {
this.blink = controller.blink;
}
/*
devices variable indicates number of connected LED devices
Here's an example of multiple devices:
http://tronixstuff.com/2013/10/11/tutorial-arduino-max7219-led-display-driver-ic/
*/
var devices = opts.devices || (opts.addresses ? opts.addresses.length : 1);
this.memory = Array(64).fill(0);
opts.dims = opts.dims || LedControl.MATRIX_DIMENSIONS["8x8"];
if (typeof opts.dims === "string") {
opts.dims = LedControl.MATRIX_DIMENSIONS[opts.dims];
}
if (Array.isArray(opts.dims)) {
opts.dims = {
rows: opts.dims[0],
columns: opts.dims[1],
};
}
var state = {
devices: devices,
digits: opts.digits || 8,
isMatrix: !!opts.isMatrix,
isBicolor: !!opts.isBicolor,
rows: opts.dims.rows,
columns: opts.dims.columns
};
if (!(state.columns === 8 || state.columns === 16) || !(state.rows === 8 || state.rows === 16) || (state.columns + state.rows ===
32)) {
throw new Error("Invalid matrix dimensions specified: must be 8x8, 16x8 or 8x16");
}
Object.defineProperties(this, {
devices: {
get: function() {
return state.devices;
}
},
digits: {
get: function() {
return state.digits;
}
},
isMatrix: {
get: function() {
return state.isMatrix;
}
},
isBicolor: {
get: function() {
return state.isBicolor;
}
},
rows: {
get: function() {
return state.rows;
}
},
columns: {
get: function() {
return state.columns;
}
}
});
priv.set(this, state);
controller.initialize.call(this, opts);
}
n/a
brightness = function (addr, val) { if (arguments.length === 1) { val = addr; this.each(function(device) { this.brightness(device, val); }); } else { this.send(addr, this.OP.BRIGHTNESS || LedControl.OP.BRIGHTNESS, Board.map(val, 0, 100, 0, 15)); } return this; }
n/a
function deprecated() { warned = exports.printDeprecationMessage(msg, warned, deprecated); if (new.target) { return Reflect.construct(fn, arguments, new.target); } return fn.apply(this, arguments); }
n/a
column = function (addr, col, value) { var state; if (!this.isMatrix) { throw new Error("The `column` method is only supported for Matrix devices"); } if (arguments.length === 2) { value = col; col = addr; this.each(function(device) { this.column(device, col, value); }); } else { for (var row = 0; row < this.rows; row++) { state = value >> ((this.rows - 1) - row); state = state & 0x01; this.led(addr, row, col, state); } } return this; }
n/a
device = function (addr) {
var bound = {};
/* keys from prototype */
Object.keys(LedControl.prototype).forEach(function(key) {
bound[key] = this[key].bind(this, addr);
}, this);
/* functions from interface */
Object.getOwnPropertyNames(this).forEach(function(key) {
if (this[key] && typeof this[key] === "function") {
bound[key] = this[key].bind(this, addr);
}
}, this);
return bound;
}
n/a
digit = function (addr, position, chr) { var args, offset, index, character, value; var hasDecimal = false; if (arguments.length < 3) { args = Array.from(arguments); this.each(function(device) { this.digit.apply(this, (args.unshift(device), args)); }); return this; } if (this.isMatrix) { // Not sure this is the best path, will check when segment // devices are available. this.draw.apply(this, arguments); return this; } offset = addr * this.digits; character = String(chr); position = Number(position); // If controller's indexes are ordered right to left, flip // the index around. index = position; if (this.digitOrder === -1) { index = this.digits - index - 1; } if (character.length === 2 && character[1] === ".") { hasDecimal = true; character = character[0]; } value = LedControl.DIGIT_CHARS[character]; if (!value) { value = Math.abs(Number(character)); } if (hasDecimal) { value = value | LedControl.DIGIT_CHARS["."]; } this.memory[offset + index] = value; this.sendDigit(addr, index, value); return this; }
n/a
draw = function (addr, chr) {
// in matrix mode, this takes two arguments:
// addr and the character to display
var character;
if (arguments.length === 1) {
chr = addr;
this.each(function(device) {
this.draw(device, chr);
});
} else {
if (this.isMatrix) {
if (Array.isArray(chr)) {
character = chr;
} else {
character = ledCharacters.MATRIX_CHARS[chr];
}
/* istanbul ignore else */
if (character !== undefined) {
if (character.length !== this.rows && character.length !== this.columns) {
throw new Error("Invalid character: " + character);
}
// pad character to match number of rows suppported by device
var charLength = character.length;
for (var i = 0; i < (this.rows - charLength); i++) {
/* istanbul ignore next */
character.push(0);
}
character.forEach(function(rowData, idx) {
this.row(addr, idx, rowData);
}, this);
}
} else {
// in seven-segment mode, this takes four arguments, which
// are just passed through to digit
this.digit.apply(this, arguments);
}
}
return this;
}
n/a
each = function (callbackfn) { for (var i = 0; i < this.devices; i++) { callbackfn.call(this, i); } }
n/a
off = function (addr) { if (typeof addr === "undefined") { this.each(function(device) { this.off(device); }); } else { this.send(addr, this.OP.SHUTDOWN || LedControl.OP.SHUTDOWN, 0); } return this; }
...
return this;
};
ReflectanceArray.prototype.disable = function() {
var state = priv.get(this);
state.emitter.off();
return this;
};
// Calibrate will store the min/max values for this sensor array
// It should be called many times in order to get a lot of readings
// on light and dark areas. See calibrateUntil for a convenience
...
on = function (addr) { if (typeof addr === "undefined") { this.each(function(device) { this.on(device); }); } else { this.send(addr, this.OP.SHUTDOWN || LedControl.OP.SHUTDOWN, 1); } return this; }
...
The ubiquitous "Hello World" program of the microcontroller and SoC world is "blink an LED". The following code
demonstrates how this is done using the Johnny-Five framework.
```javascript
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
...
print = function (message, opts) {
var rdigchars = /([0-9A-Za-z][.]|[0-9A-Za-z:]|[\s])/g;
var characters;
opts = opts || {
device: 0
};
if (this.isMatrix) {
// figure out what to do with Matrix displays
throw new Error("Led.Matrix does not yet support the print method");
}
if (typeof message !== "string") {
message = String(message);
}
characters = message.match(rdigchars);
// When a device has a built-in colon, ie. "00:00",
// then attempt to make it less awkward to print words across
// the display by splicing in a " " placeholder, but only
// when necessary.
if (this.colon) {
if (characters.length > 2 &&
(characters[2] !== ":" && characters[2] !== " ")) {
characters.splice(2, 0, " ");
}
}
/* istanbul ignore next */
(characters || []).forEach(function(character, position) {
this.digit(opts.device, position, character);
}, this);
return this;
}
n/a
function deprecated() { warned = exports.printDeprecationMessage(msg, warned, deprecated); if (new.target) { return Reflect.construct(fn, arguments, new.target); } return fn.apply(this, arguments); }
n/a
function Leds(numsOrObjects) { if (!(this instanceof Leds)) { return new Leds(numsOrObjects); } Object.defineProperty(this, "type", { value: Led }); Collection.call(this, numsOrObjects); }
n/a
function Collection(numsOrObjects) {
var Type = this.type;
var initObjects = [];
this.length = 0;
if (Array.isArray(numsOrObjects)) {
initObjects = numsOrObjects;
} else {
// Initialize with a Shared Properties object
/* istanbul ignore else */
if (Array.isArray(numsOrObjects.pins)) {
var keys = Object.keys(numsOrObjects).filter(function(key) {
return key !== "pins";
});
initObjects = numsOrObjects.pins.map(function(pin) {
var obj = {};
if (Array.isArray(pin)) {
obj.pins = pin;
} else {
obj.pin = pin;
}
return keys.reduce(function(accum, key) {
accum[key] = numsOrObjects[key];
return accum;
}, obj);
});
}
}
/* istanbul ignore else */
if (initObjects.length) {
while (initObjects.length) {
var numOrObject = initObjects.shift();
// When a Type exists, respect it!
if (typeof Type === "function") {
if (!(numOrObject instanceof Type || numOrObject instanceof this.constructor)) {
numOrObject = new Type(numOrObject);
}
}
this.add(numOrObject);
}
}
}
n/a
blink = function (duration, callback) {
var length = this.length;
var signals = [];
var led;
if (typeof duration === "function") {
callback = duration;
duration = 1000;
}
if (typeof callback !== "function") {
callback = noop;
}
for (var i = 0; i < length; i++) {
led = this[i];
signals.push(
/* jshint ignore:start */
new Promise(function(resolve) {
led[method](duration, function() {
resolve();
});
})
/* jshint ignore:end */
);
}
Promise.all(signals).then(callback);
return this;
}
...
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
<img src="https://github.com/rwaldron/johnny-five/raw/master/assets/led-blink.gif">
> Note: Node will crash if you try to run johnny-five in the node REPL, but board instances will create their own contextual
REPL. Put your script in a file.
...
brightness = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
fade = function (duration, callback) {
var length = this.length;
var signals = [];
var led;
if (typeof duration === "function") {
callback = duration;
duration = 1000;
}
if (typeof callback !== "function") {
callback = noop;
}
for (var i = 0; i < length; i++) {
led = this[i];
signals.push(
/* jshint ignore:start */
new Promise(function(resolve) {
led[method](duration, function() {
resolve();
});
})
/* jshint ignore:end */
);
}
Promise.all(signals).then(callback);
return this;
}
n/a
fadeIn = function (duration, callback) {
var length = this.length;
var signals = [];
var led;
if (typeof duration === "function") {
callback = duration;
duration = 1000;
}
if (typeof callback !== "function") {
callback = noop;
}
for (var i = 0; i < length; i++) {
led = this[i];
signals.push(
/* jshint ignore:start */
new Promise(function(resolve) {
led[method](duration, function() {
resolve();
});
})
/* jshint ignore:end */
);
}
Promise.all(signals).then(callback);
return this;
}
n/a
fadeOut = function (duration, callback) {
var length = this.length;
var signals = [];
var led;
if (typeof duration === "function") {
callback = duration;
duration = 1000;
}
if (typeof callback !== "function") {
callback = noop;
}
for (var i = 0; i < length; i++) {
led = this[i];
signals.push(
/* jshint ignore:start */
new Promise(function(resolve) {
led[method](duration, function() {
resolve();
});
})
/* jshint ignore:end */
);
}
Promise.all(signals).then(callback);
return this;
}
n/a
intensity = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
off = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
...
return this;
};
ReflectanceArray.prototype.disable = function() {
var state = priv.get(this);
state.emitter.off();
return this;
};
// Calibrate will store the min/max values for this sensor array
// It should be called many times in order to get a lot of readings
// on light and dark areas. See calibrateUntil for a convenience
...
on = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
...
The ubiquitous "Hello World" program of the microcontroller and SoC world is "blink an LED". The following code
demonstrates how this is done using the Johnny-Five framework.
```javascript
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
...
pulse = function (duration, callback) {
var length = this.length;
var signals = [];
var led;
if (typeof duration === "function") {
callback = duration;
duration = 1000;
}
if (typeof callback !== "function") {
callback = noop;
}
for (var i = 0; i < length; i++) {
led = this[i];
signals.push(
/* jshint ignore:start */
new Promise(function(resolve) {
led[method](duration, function() {
resolve();
});
})
/* jshint ignore:end */
);
}
Promise.all(signals).then(callback);
return this;
}
n/a
stop = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
strobe = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
toggle = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
function Light(opts) {
if (!(this instanceof Light)) {
return new Light(opts);
}
var controller = null;
var state = {};
var raw = 0;
var last = 0;
var freq = opts.freq || 25;
Board.Component.call(
this, opts = Board.Options(opts)
);
if (typeof opts.controller === "string") {
controller = Controllers[opts.controller];
} else {
controller = opts.controller || Controllers.DEFAULT;
}
Board.Controller.call(this, controller, opts);
if (!this.toIntensityLevel) {
this.toIntensityLevel = opts.toIntensityLevel || function(x) {
return x;
};
}
if (!this.toLux) {
this.toLux = opts.toLux || function(x) {
return x;
};
}
Object.defineProperties(this, {
value: {
get: function() {
return raw;
},
},
level: {
get: function() {
return this.toIntensityLevel(raw);
},
},
});
priv.set(this, state);
/* istanbul ignore else */
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
raw = data;
});
}
if (typeof this.lux === "undefined") {
Object.defineProperty(this, "lux", {
get: function() {
return this.toLux(raw);
},
});
}
var data = {
level: 0,
lux: 0,
};
setInterval(function() {
data.level = this.level;
data.lux = this.lux;
this.emit("data", data);
if (raw !== last) {
last = raw;
this.emit("change", data);
}
}.bind(this), freq);
}
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
within = function (range, unit, callback) { var upper; if (typeof range === "number") { upper = range; range = [0, upper]; } if (!Array.isArray(range)) { throw new Error("within expected a range array"); } if (typeof unit === "function") { callback = unit; unit = "value"; } if (typeof this[unit] === "undefined") { return this; } // Use the continuous read event for high resolution this.on("data", function() { var value = this[unit]; if (value >= range[0] && value <= range[1]) { callback.call(this, null, value); } }.bind(this)); return this; }
n/a
function Motion(opts) {
if (!(this instanceof Motion)) {
return new Motion(opts);
}
var freq = opts.freq || 25;
var last = false;
var controller;
var state;
Board.Component.call(
this, opts = Board.Options(opts)
);
if (typeof opts.controller === "string") {
controller = Controllers[opts.controller];
} else {
controller = opts.controller || Controllers["PIR"];
}
Board.Controller.call(this, controller, opts);
state = {
value: false,
isCalibrated: false
};
priv.set(this, state);
Object.defineProperties(this, {
/**
* [read-only] Current sensor state
* @property detectedMotion
* @type Boolean
*/
detectedMotion: {
get: function() {
return this.toBoolean(state.value);
}
},
/**
* [read-only] Sensor calibration status
* @property isCalibrated
* @type Boolean
*/
isCalibrated: {
get: function() {
return state.isCalibrated;
}
},
});
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
state.value = data;
});
}
setInterval(function() {
var isChange = false;
var eventData = {
timestamp: Date.now(),
detectedMotion: this.detectedMotion,
isCalibrated: state.isCalibrated
};
if (state.isCalibrated && this.detectedMotion && !last) {
this.emit("motionstart", eventData);
}
if (state.isCalibrated && !this.detectedMotion && last) {
this.emit("motionend", eventData);
}
if (last !== this.detectedMotion) {
isChange = true;
}
this.emit("data", eventData);
if (isChange) {
this.emit("change", eventData);
}
last = this.detectedMotion;
}.bind(this), freq);
}
n/a
Collection = function (numsOrObjects) { if (!(this instanceof Motion.Collection)) { return new Motion.Collection(numsOrObjects); } Object.defineProperty(this, "type", { value: Motion }); Collection.Emitter.call(this, numsOrObjects); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
Collection = function (numsOrObjects) { if (!(this instanceof Motion.Collection)) { return new Motion.Collection(numsOrObjects); } Object.defineProperty(this, "type", { value: Motion }); Collection.Emitter.call(this, numsOrObjects); }
n/a
super_ = function (numsOrObjects) {
// Create private state ahead of super call
priv.set(this, {
timing: {
last: Date.now()
}
});
Collection.call(this, numsOrObjects);
// If the Collection.Emitter was created
// with a Shared Properties object, then
// we should abide by the freq or period
// properties...
var interval = null;
var period = 5;
if (!Array.isArray(numsOrObjects) &&
(typeof numsOrObjects === "object" && numsOrObjects !== null)) {
period = numsOrObjects.freq || numsOrObjects.period || period;
// _However_, looking to the future, we
// need to start thinking about replacing
// the garbage named _freq_ (the value is
// actually a period), with real _frequency_
// in Hz.
// If provided, convert frequency to period
/* istanbul ignore else */
if (numsOrObjects.frequency) {
period = (1 / numsOrObjects.frequency) * 1000;
}
}
Object.defineProperties(this, {
period: {
get: function() {
return period;
},
set: function(value) {
if (period !== value) {
period = value;
}
if (interval) {
clearInterval(interval);
}
interval = setInterval(function() {
this.emit("data", this);
}.bind(this), period);
}
},
});
this.period = period;
this.on("newListener", function(event) {
if (event === "change" || event === "data") {
return;
}
this.forEach(function(input) {
input.on(event, function(data) {
this.emit(event, input, data);
}.bind(this));
}, this);
});
}
n/a
function Motor(opts) {
var device, controller, state;
if (!(this instanceof Motor)) {
return new Motor(opts);
}
Board.Component.call(
this, this.opts = Board.Options(opts)
);
controller = opts.controller || null;
// Derive device based on pins passed
if (typeof this.opts.device === "undefined") {
this.opts.device = (typeof this.opts.pins === "undefined" && typeof this.opts.register !== "object") ?
"NONDIRECTIONAL" : "DIRECTIONAL";
if (this.opts.pins && (this.opts.pins.cdir || this.opts.pins.length > 2)) {
this.opts.device = "CDIR";
}
if (typeof controller === "string" &&
(controller.startsWith("EVS") || controller.startsWith("GROVE_I2C"))) {
this.opts.device = "DIRECTIONAL";
}
}
// Allow users to pass in custom device types
device = typeof this.opts.device === "string" ?
Devices[this.opts.device] : this.opts.device;
this.threshold = typeof this.opts.threshold !== "undefined" ?
this.opts.threshold : 30;
this.invertPWM = typeof this.opts.invertPWM !== "undefined" ?
this.opts.invertPWM : false;
Object.defineProperties(this, device);
if (this.opts.register) {
this.opts.controller = "ShiftRegister";
}
/**
* Note: Controller decorates the device. Used for adding
* special controllers (i.e. PCA9685)
**/
if (this.opts.controller) {
controller = typeof this.opts.controller === "string" ?
Controllers[this.opts.controller] : this.opts.controller;
Board.Controller.call(this, controller, opts);
}
// current just wraps a Sensor
if (this.opts.current) {
this.opts.current.board = this.board;
this.current = new Sensor(this.opts.current);
}
// Create a "state" entry for privately
// storing the state of the motor
state = {
isOn: false,
currentSpeed: typeof this.opts.speed !== "undefined" ?
this.opts.speed : 128,
braking: false,
enabled: true
};
priv.set(this, state);
Object.defineProperties(this, {
// Calculated, read-only motor on/off state
// true|false
isOn: {
get: function() {
return state.isOn;
}
},
currentSpeed: {
get: function() {
return state.currentSpeed;
}
},
braking: {
get: function() {
return state.braking;
}
},
enabled: {
get: function() {
return state.enabled;
}
}
});
// We need to store and initialize the state of the dir pin(s)
this.direction = {
value: 1
};
if (this.initialize) {
this.initialize(opts);
}
this.enable();
this.dir(this.direction);
}
n/a
function Motors(numsOrObjects) { if (!(this instanceof Motors)) { return new Motors(numsOrObjects); } Object.defineProperty(this, "type", { value: Motor }); Collection.call(this, numsOrObjects); }
n/a
function Motors(numsOrObjects) { if (!(this instanceof Motors)) { return new Motors(numsOrObjects); } Object.defineProperty(this, "type", { value: Motor }); Collection.call(this, numsOrObjects); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
brake = function (duration) { if (typeof this.pins.brake === "undefined") { if (this.board.io.name !== "Mock") { console.log("Non-braking motor type"); } this.stop(); } else { this.setPin(this.pins.brake, 1); this.setPin(this.pins.dir, 1); this.speed({ speed: 255, saveSpeed: false, braking: true }); process.nextTick(this.emit.bind(this, "brake")); if (duration) { var motor = this; this.board.wait(duration, function() { motor.resume(); }); } } return this; }
n/a
disable = function () { var state = priv.get(this); if (typeof this.pins.enable !== "undefined" && this.enabled) { this.setPin(this.pins.enable, 0); state.enabled = false; } }
n/a
enable = function () { var state = priv.get(this); if (typeof this.pins.enable !== "undefined" && !this.enabled) { this.setPin(this.pins.enable, 1); state.enabled = true; } }
n/a
forward = function (speed) { this.dir(dir); this.start(speed); return this; }
n/a
fwd = function (speed) { this.dir(dir); this.start(speed); return this; }
n/a
initialize = function () { this.io.pinMode(this.pins.pwm, this.io.MODES.PWM); ["dir", "cdir", "brake", "enable"].forEach(function(pin) { if (typeof this.pins[pin] !== "undefined") { this.io.pinMode(this.pins[pin], this.io.MODES.OUTPUT); } }, this); }
...
return raw;
};
}
priv.set(this, state);
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
raw = data;
});
}
setInterval(function() {
if (raw === null) {
return;
...
release = function () { this.resume(); process.nextTick(this.emit.bind(this, "release")); return this; }
n/a
resume = function () { var speed = this.speed(); this.dir(this.direction); this.start(speed); return this; }
n/a
rev = function (speed) { this.dir(dir); this.start(speed); return this; }
n/a
reverse = function (speed) { this.dir(dir); this.start(speed); return this; }
n/a
setPWM = function (pin, value) { this.io.analogWrite(pin, value); }
n/a
setPin = function (pin, value) { this.io.digitalWrite(pin, value); }
n/a
speed = function (opts) { var state = priv.get(this); if (typeof opts === "undefined") { return state.currentSpeed; } else { if (typeof opts === "number") { opts = { speed: opts }; } opts.speed = Board.constrain(opts.speed, 0, 255); opts.saveSpeed = typeof opts.saveSpeed !== "undefined" ? opts.saveSpeed : true; if (opts.speed < this.threshold) { opts.speed = 0; } state.isOn = opts.speed === 0 ? false : true; if (opts.saveSpeed) { state.currentSpeed = opts.speed; } if (opts.braking) { state.braking = true; } if (this.invertPWM && this.direction.value === 1) { opts.speed ^= 0xff; } this.setPWM(this.pins.pwm, opts.speed); return this; } }
n/a
start = function (speed) { // Send a signal to turn on the motor and run at given speed in whatever // direction is currently set. if (this.pins.brake && this.braking) { this.setPin(this.pins.brake, 0); } // get current speed if nothing provided. speed = typeof speed !== "undefined" ? speed : this.speed(); this.speed({ speed: speed, braking: false }); // "start" event is fired when the motor is started if (speed > 0) { process.nextTick(this.emit.bind(this, "start")); } return this; }
n/a
stop = function () { this.speed({ speed: 0, saveSpeed: false }); process.nextTick(this.emit.bind(this, "stop")); return this; }
n/a
function Motors(numsOrObjects) { if (!(this instanceof Motors)) { return new Motors(numsOrObjects); } Object.defineProperty(this, "type", { value: Motor }); Collection.call(this, numsOrObjects); }
n/a
function Collection(numsOrObjects) {
var Type = this.type;
var initObjects = [];
this.length = 0;
if (Array.isArray(numsOrObjects)) {
initObjects = numsOrObjects;
} else {
// Initialize with a Shared Properties object
/* istanbul ignore else */
if (Array.isArray(numsOrObjects.pins)) {
var keys = Object.keys(numsOrObjects).filter(function(key) {
return key !== "pins";
});
initObjects = numsOrObjects.pins.map(function(pin) {
var obj = {};
if (Array.isArray(pin)) {
obj.pins = pin;
} else {
obj.pin = pin;
}
return keys.reduce(function(accum, key) {
accum[key] = numsOrObjects[key];
return accum;
}, obj);
});
}
}
/* istanbul ignore else */
if (initObjects.length) {
while (initObjects.length) {
var numOrObject = initObjects.shift();
// When a Type exists, respect it!
if (typeof Type === "function") {
if (!(numOrObject instanceof Type || numOrObject instanceof this.constructor)) {
numOrObject = new Type(numOrObject);
}
}
this.add(numOrObject);
}
}
}
n/a
brake = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
disable = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
enable = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
forward = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
fwd = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
initialize = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
...
return raw;
};
}
priv.set(this, state);
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
raw = data;
});
}
setInterval(function() {
if (raw === null) {
return;
...
release = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
resume = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
rev = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
reverse = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
setPWM = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
setPin = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
speed = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
start = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
stop = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
function Piezo(opts) { if (!(this instanceof Piezo)) { return new Piezo(opts); } Board.Component.call( this, opts = Board.Options(opts) ); var controller = null; if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.DEFAULT; } Object.defineProperties(this, controller); Board.Controller.call(this, controller, opts); // Piezo instance properties var state = { isPlaying: false, timeout: null, address: null, }; priv.set(this, state); Object.defineProperties(this, { isPlaying: { get: function() { return state.isPlaying; } } }); if (typeof this.initialize === "function") { this.initialize(opts); } }
n/a
ToFrequency = function (tone) { var toneSeconds = tone / MICROSECONDS_PER_SECOND; var period = toneSeconds * 2; return Math.round(1 / period); }
n/a
ToSong = function (stringSong, beats) { beats = beats || 1; var notes = stringSong.split(" "); var song = []; var note, lastNote; while (notes.length) { note = notes.shift(); if (/^[0-9]+$/.test(note)) { note = parseInt(note, 10); } lastNote = song[song.length - 1]; if (lastNote && lastNote[0] === note) { lastNote[1] += beats; } else { song.push([note, beats]); } } return song; }
n/a
ToTone = function (frequency) { var period = 1 / frequency; var duty = period / 2; return Math.round(duty * MICROSECONDS_PER_SECOND); }
n/a
defaultOctave = function (octave) { if (Piezo.isValidOctave(octave)) { defaultOctave = octave; } return defaultOctave; }
n/a
isValidOctave = function (octave) { return typeof octave === "number" && (octave >= 0 && octave <= 8); }
n/a
beatFromNote = function (note) { var beat = 1; if (Array.isArray(note) && note[1] !== undefined) { // If extant, beat will be second element of note beat = note[1]; } return beat; }
n/a
hzFromInput = function (input) { var output = input; if (Array.isArray(input)) { output = input[0]; } // Is it a valid frequency? if (typeof output === "number" && Piezo.Frequencies[output]) { return output; } // See above: Piezo.Notes { ... } if (typeof output === "string") { output = output.toLowerCase().trim(); // Example: c#, c if (output.endsWith("#") || output.length === 1) { output += defaultOctave; } // There will never be a 0 tone output = Piezo.Notes[output] || null; } // Normalize NaN, null & undefined to null if (isNaN(output)) { output = null; } return output; }
n/a
frequency = function (frequency, duration) { return this.tone(Piezo.ToTone(frequency), duration); }
n/a
note = function (note, duration) { var tone = Piezo.Parsers.hzFromInput(note); return this.tone(tone, duration); }
n/a
off = function () { return this.noTone(); }
...
return this;
};
ReflectanceArray.prototype.disable = function() {
var state = priv.get(this);
state.emitter.off();
return this;
};
// Calibrate will store the min/max values for this sensor array
// It should be called many times in order to get a lot of readings
// on light and dark areas. See calibrateUntil for a convenience
...
play = function (tune, callback) {
if (typeof tune !== "object") {
tune = {
song: tune
};
}
if (typeof tune.song === "string") {
tune.song = Piezo.ToSong(tune.song, tune.beats);
}
if (tune.song && !Array.isArray(tune.song)) {
/*
If `tune.song` was present and not falsy,
but also is not a string (above), or an array
(presently), then it is likely a Hz value, so
normalize song to the appropriate array format:
*/
tune.song = [tune.song];
/*
Note: This path is taken for calls that look
like this:
piezo.play({
song: 262,
}, ...)
Where 262 is a frequency in Hz
*/
}
var state = priv.get(this);
var tempo = tune.tempo || 250;
// Length for a single beat in ms
var beatDuration = Math.round(60000 / tempo);
var song = tune.song || [];
var duration;
var nextNoteIndex = 0;
var next = function() {
if (nextNoteIndex === song.length) {
// No more notes in song:
// Song is over
state.isPlaying = false;
if (typeof callback === "function") {
callback(tune);
}
return;
}
var note = song[nextNoteIndex];
var hz = Piezo.Parsers.hzFromInput(note);
var beat = Piezo.Parsers.beatFromNote(note);
duration = beat * beatDuration;
nextNoteIndex++;
if (hz === null) {
this.noTone();
} else {
this.frequency(hz, duration);
}
state.timeout = setTimeout(next, duration);
}.bind(this);
// We are playing a song
state.isPlaying = true;
next();
return this;
}
n/a
stop = function () {
var state = priv.get(this);
/* istanbul ignore else */
if (state.timeout) {
clearTimeout(state.timeout);
state.timeout = null;
}
return this;
}
n/a
tone = function (tone, duration) { return this.frequency(Piezo.ToFrequency(tone), duration); }
n/a
function Pin(opts) { if (!(this instanceof Pin)) { return new Pin(opts); } if (opts === undefined || (typeof opts === "object" && opts.addr === undefined && opts.pin === undefined)) { throw new Error("Pins must have a pin number"); } var pinValue = typeof opts === "object" ? (opts.addr || opts.pin || 0) : opts; var isAnalogInput = Pin.isAnalog(opts); var isDTOA = false; Board.Component.call( this, opts = Board.Options(opts) ); opts.addr = opts.addr || opts.pin; if (this.io.analogPins.includes(pinValue)) { isAnalogInput = false; isDTOA = true; } var isPin = typeof opts !== "object"; var addr = isDTOA ? pinValue : (isPin ? opts : opts.addr); var type = opts.type || (isAnalogInput ? "analog" : "digital"); // Create a private side table var state = { mode: null, last: null, value: 0 }; priv.set(this, state); // Create read-only "addr(address)" property Object.defineProperties(this, { type: { get: function() { return type; } }, addr: { get: function() { return addr; } }, value: { get: function() { return state.value; } }, mode: { set: function(mode) { var state = priv.get(this); state.mode = mode; this.io.pinMode(this.addr, mode); }, get: function() { return priv.get(this).mode; } } }); this.mode = typeof opts.as !== "undefined" ? opts.as : (typeof opts.mode !== "undefined" ? opts.mode : (isAnalogInput ? 0x02 : 0x01)); this.freq = typeof opts.freq !== "undefined" ? opts.freq : 20; if (this.mode === 0 || this.mode === 2) { read(this); } if (type === "digital") { Object.defineProperties(this, { isHigh: { get: function() { return !!state.value; } }, isLow: { get: function() { return !state.value; } }, }); } }
n/a
function Pins(numsOrObjects) { if (!(this instanceof Pins)) { return new Pins(numsOrObjects); } Object.defineProperty(this, "type", { value: Pin }); Collection.call(this, numsOrObjects); }
n/a
function Pins(numsOrObjects) { if (!(this instanceof Pins)) { return new Pins(numsOrObjects); } Object.defineProperty(this, "type", { value: Pin }); Collection.call(this, numsOrObjects); }
n/a
isAnalog = function (opts) { if (typeof opts === "string" && Pin.isPrefixed(opts, ["I", "A"])) { return true; } if (typeof opts === "object") { return Pin.isAnalog( typeof opts.addr !== "undefined" ? opts.addr : opts.pin ); } }
n/a
isPrefixed = function (value, prefixes) { value = value[0]; return prefixes.reduce(function(resolution, prefix) { if (!resolution) { return prefix === value; } return resolution; }, false); }
n/a
read = function (pin, callback) { // Set the correct mode (INPUT) // This will only set if it needs to be set, otherwise a no-op var isChanging = false; if (pin.type === "digital" && pin.mode !== 0) { isChanging = true; pin.mode = modes.INPUT; } if (pin.type === "analog" && pin.mode !== 2) { isChanging = true; pin.mode = modes.ANALOG; } if (isChanging) { read(pin); } pin.on("data", function() { callback.call(pin, null, pin.value); }); }
...
EVS.prototype.read = function(port, register, numBytes, callback) {
if (port.sensor && port.offset && !EVS.isRawSensor(port)) {
register += port.offset;
}
this.bank[port.bank].read(register, numBytes, callback);
};
EVS.prototype.write = function(port, register, data) {
this.bank[port.bank].write(register, data);
};
/*
...
function EventEmitter() { EventEmitter.init.call(this); }
n/a
write = function (pin, val) { var state = priv.get(pin); state.value = 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.io[pin.type + "Write"](pin.addr, val); pin.emit("write", null, val); }
...
EVS.isRawSensor = function(port) {
return port.analog === EVS.S1_ANALOG || port.analog === EVS.S2_ANALOG;
};
util.inherits(EVS, Emitter);
EVS.prototype.setup = function(port, type) {
this.bank[port.bank].write(port.mode, [type]);
};
EVS.prototype.read = function(port, register, numBytes, callback) {
if (port.sensor && port.offset && !EVS.isRawSensor(port)) {
register += port.offset;
}
...
high = function () { var value = this.type === "analog" ? 255 : 1; Pin.write(this, value); this.emit("high"); return this; }
n/a
low = function () { Pin.write(this, 0); this.emit("low"); return this; }
n/a
query = function (callback) { var index = this.addr; if (this.type === "analog") { index = this.io.analogPins[this.addr]; } function handler() { callback(this.io.pins[index]); } this.io.queryPinState(index, handler.bind(this)); return this; }
n/a
read = function (valOrCallback) { Pin[operation](this, valOrCallback); return this; }
...
EVS.prototype.read = function(port, register, numBytes, callback) {
if (port.sensor && port.offset && !EVS.isRawSensor(port)) {
register += port.offset;
}
this.bank[port.bank].read(register, numBytes, callback);
};
EVS.prototype.write = function(port, register, data) {
this.bank[port.bank].write(register, data);
};
/*
...
write = function (valOrCallback) { Pin[operation](this, valOrCallback); return this; }
...
EVS.isRawSensor = function(port) {
return port.analog === EVS.S1_ANALOG || port.analog === EVS.S2_ANALOG;
};
util.inherits(EVS, Emitter);
EVS.prototype.setup = function(port, type) {
this.bank[port.bank].write(port.mode, [type]);
};
EVS.prototype.read = function(port, register, numBytes, callback) {
if (port.sensor && port.offset && !EVS.isRawSensor(port)) {
register += port.offset;
}
...
function Ping(opts) { if (!(this instanceof Ping)) { return new Ping(opts); } var last = null; Board.Component.call( this, opts = Board.Options(opts) ); this.pin = opts && opts.pin || 7; this.freq = opts.freq || 20; // this.pulse = opts.pulse || 250; var state = { value: null }; // Private settings object var settings = { pin: this.pin, value: this.io.HIGH, pulseOut: 5 }; this.io.setMaxListeners(100); // Interval for polling pulse duration as reported in microseconds setInterval(function() { this.io.pingRead(settings, function(microseconds) { state.value = microseconds; }); }.bind(this), 225); // Interval for throttled event setInterval(function() { if (state.value === null) { return; } // The "read" event has been deprecated in // favor of a "data" event. this.emit("data", state.value); // If the state.value for this interval is not the same as the // state.value in the last interval, fire a "change" event. if (state.value !== last) { this.emit("change", state.value); } // Store state.value for comparison in next interval last = state.value; // Reset samples; // samples.length = 0; }.bind(this), this.freq); Object.defineProperties(this, { value: { get: function() { return state.value; } }, // Based on the round trip travel time in microseconds, // Calculate the distance in inches and centimeters inches: { get: function() { return toFixed(state.value / 74 / 2, 2); } }, in: { get: function() { return this.inches; } }, cm: { get: function() { return toFixed(state.value / 29 / 2, 3); } } }); priv.set(this, state); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
within = function (range, unit, callback) { var upper; if (typeof range === "number") { upper = range; range = [0, upper]; } if (!Array.isArray(range)) { throw new Error("within expected a range array"); } if (typeof unit === "function") { callback = unit; unit = "value"; } if (typeof this[unit] === "undefined") { return this; } // Use the continuous read event for high resolution this.on("data", function() { var value = this[unit]; if (value >= range[0] && value <= range[1]) { callback.call(this, null, value); } }.bind(this)); return this; }
n/a
function Pins(numsOrObjects) { if (!(this instanceof Pins)) { return new Pins(numsOrObjects); } Object.defineProperty(this, "type", { value: Pin }); Collection.call(this, numsOrObjects); }
n/a
function Collection(numsOrObjects) {
var Type = this.type;
var initObjects = [];
this.length = 0;
if (Array.isArray(numsOrObjects)) {
initObjects = numsOrObjects;
} else {
// Initialize with a Shared Properties object
/* istanbul ignore else */
if (Array.isArray(numsOrObjects.pins)) {
var keys = Object.keys(numsOrObjects).filter(function(key) {
return key !== "pins";
});
initObjects = numsOrObjects.pins.map(function(pin) {
var obj = {};
if (Array.isArray(pin)) {
obj.pins = pin;
} else {
obj.pin = pin;
}
return keys.reduce(function(accum, key) {
accum[key] = numsOrObjects[key];
return accum;
}, obj);
});
}
}
/* istanbul ignore else */
if (initObjects.length) {
while (initObjects.length) {
var numOrObject = initObjects.shift();
// When a Type exists, respect it!
if (typeof Type === "function") {
if (!(numOrObject instanceof Type || numOrObject instanceof this.constructor)) {
numOrObject = new Type(numOrObject);
}
}
this.add(numOrObject);
}
}
}
n/a
high = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
low = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
write = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
...
EVS.isRawSensor = function(port) {
return port.analog === EVS.S1_ANALOG || port.analog === EVS.S2_ANALOG;
};
util.inherits(EVS, Emitter);
EVS.prototype.setup = function(port, type) {
this.bank[port.bank].write(port.mode, [type]);
};
EVS.prototype.read = function(port, register, numBytes, callback) {
if (port.sensor && port.offset && !EVS.isRawSensor(port)) {
register += port.offset;
}
...
function Proximity(opts) {
if (!(this instanceof Proximity)) {
return new Proximity(opts);
}
var controller = null;
var state = {};
var raw = 0;
var freq = opts.freq || 25;
var last = 0;
var pinValue = typeof opts === "object" ? opts.pin : opts;
Board.Component.call(
this, opts = Board.Options(opts)
);
if (typeof opts.controller === "string") {
controller = Controllers[opts.controller];
} else {
controller = opts.controller || Controllers["GP2Y0A21YK"];
}
Board.Controller.call(this, controller, opts);
if (!this.toCm) {
this.toCm = opts.toCm || function(x) {
return x;
};
}
priv.set(this, state);
Object.defineProperties(this, {
/**
* [read-only] Calculated centimeter value
* @property centimeters
* @type Number
*/
centimeters: {
get: function() {
return this.toCm(raw);
}
},
cm: {
get: function() {
return this.centimeters;
}
},
/**
* [read-only] Calculated inch value
* @property inches
* @type Number
*/
inches: {
get: function() {
return toFixed(this.centimeters * 0.39, 2);
}
},
in: {
get: function() {
return this.inches;
}
},
});
if (typeof this.initialize === "function") {
opts.pinValue = pinValue;
this.initialize(opts, function(data) {
raw = data;
});
}
setInterval(function() {
if (raw === undefined) {
return;
}
var data = {
cm: this.cm,
centimeters: this.centimeters,
in: this.in,
inches: this.inches
};
this.emit("data", data);
if (raw !== last) {
last = raw;
this.emit("change", data);
}
}.bind(this), freq);
}
n/a
Collection = function (numsOrObjects) { if (!(this instanceof Proximity.Collection)) { return new Proximity.Collection(numsOrObjects); } Object.defineProperty(this, "type", { value: Proximity }); Collection.Emitter.call(this, numsOrObjects); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
Collection = function (numsOrObjects) { if (!(this instanceof Proximity.Collection)) { return new Proximity.Collection(numsOrObjects); } Object.defineProperty(this, "type", { value: Proximity }); Collection.Emitter.call(this, numsOrObjects); }
n/a
super_ = function (numsOrObjects) {
// Create private state ahead of super call
priv.set(this, {
timing: {
last: Date.now()
}
});
Collection.call(this, numsOrObjects);
// If the Collection.Emitter was created
// with a Shared Properties object, then
// we should abide by the freq or period
// properties...
var interval = null;
var period = 5;
if (!Array.isArray(numsOrObjects) &&
(typeof numsOrObjects === "object" && numsOrObjects !== null)) {
period = numsOrObjects.freq || numsOrObjects.period || period;
// _However_, looking to the future, we
// need to start thinking about replacing
// the garbage named _freq_ (the value is
// actually a period), with real _frequency_
// in Hz.
// If provided, convert frequency to period
/* istanbul ignore else */
if (numsOrObjects.frequency) {
period = (1 / numsOrObjects.frequency) * 1000;
}
}
Object.defineProperties(this, {
period: {
get: function() {
return period;
},
set: function(value) {
if (period !== value) {
period = value;
}
if (interval) {
clearInterval(interval);
}
interval = setInterval(function() {
this.emit("data", this);
}.bind(this), period);
}
},
});
this.period = period;
this.on("newListener", function(event) {
if (event === "change" || event === "data") {
return;
}
this.forEach(function(input) {
input.on(event, function(data) {
this.emit(event, input, data);
}.bind(this));
}, this);
});
}
n/a
within = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
within = function (range, unit, callback) { var upper; if (typeof range === "number") { upper = range; range = [0, upper]; } if (!Array.isArray(range)) { throw new Error("within expected a range array"); } if (typeof unit === "function") { callback = unit; unit = "value"; } if (typeof this[unit] === "undefined") { return this; } // Use the continuous read event for high resolution this.on("data", function() { var value = this[unit]; if (value >= range[0] && value <= range[1]) { callback.call(this, null, value); } }.bind(this)); return this; }
n/a
function Relay(opts) { var state; if (!(this instanceof Relay)) { return new Relay(opts); } Board.Component.call( this, opts = Board.Options(opts) ); opts.type = opts.type || "NO"; state = { isInverted: opts.type === "NC", isOn: false, value: null, }; priv.set(this, state); Object.defineProperties(this, { value: { get: function() { return Number(this.isOn); } }, type: { get: function() { return state.isInverted ? "NC" : "NO"; } }, isOn: { get: function() { return state.isOn; } } }); }
n/a
function Relays(numsOrObjects) { if (!(this instanceof Relays)) { return new Relays(numsOrObjects); } Object.defineProperty(this, "type", { value: Relay }); Collection.call(this, numsOrObjects); }
n/a
function Relays(numsOrObjects) { if (!(this instanceof Relays)) { return new Relays(numsOrObjects); } Object.defineProperty(this, "type", { value: Relay }); Collection.call(this, numsOrObjects); }
n/a
close = function () { var state = priv.get(this); this.io.digitalWrite( this.pin, state.isInverted ? this.io.LOW : this.io.HIGH ); state.isOn = true; return this; }
n/a
off = function () { var state = priv.get(this); this.io.digitalWrite( this.pin, state.isInverted ? this.io.HIGH : this.io.LOW ); state.isOn = false; return this; }
...
return this;
};
ReflectanceArray.prototype.disable = function() {
var state = priv.get(this);
state.emitter.off();
return this;
};
// Calibrate will store the min/max values for this sensor array
// It should be called many times in order to get a lot of readings
// on light and dark areas. See calibrateUntil for a convenience
...
on = function () { var state = priv.get(this); this.io.digitalWrite( this.pin, state.isInverted ? this.io.LOW : this.io.HIGH ); state.isOn = true; return this; }
...
The ubiquitous "Hello World" program of the microcontroller and SoC world is "blink an LED". The following code
demonstrates how this is done using the Johnny-Five framework.
```javascript
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
...
open = function () { var state = priv.get(this); this.io.digitalWrite( this.pin, state.isInverted ? this.io.HIGH : this.io.LOW ); state.isOn = false; return this; }
n/a
toggle = function () { var state = priv.get(this); if (state.isOn) { this.off(); } else { this.on(); } return this; }
n/a
function Relays(numsOrObjects) { if (!(this instanceof Relays)) { return new Relays(numsOrObjects); } Object.defineProperty(this, "type", { value: Relay }); Collection.call(this, numsOrObjects); }
n/a
function Collection(numsOrObjects) {
var Type = this.type;
var initObjects = [];
this.length = 0;
if (Array.isArray(numsOrObjects)) {
initObjects = numsOrObjects;
} else {
// Initialize with a Shared Properties object
/* istanbul ignore else */
if (Array.isArray(numsOrObjects.pins)) {
var keys = Object.keys(numsOrObjects).filter(function(key) {
return key !== "pins";
});
initObjects = numsOrObjects.pins.map(function(pin) {
var obj = {};
if (Array.isArray(pin)) {
obj.pins = pin;
} else {
obj.pin = pin;
}
return keys.reduce(function(accum, key) {
accum[key] = numsOrObjects[key];
return accum;
}, obj);
});
}
}
/* istanbul ignore else */
if (initObjects.length) {
while (initObjects.length) {
var numOrObject = initObjects.shift();
// When a Type exists, respect it!
if (typeof Type === "function") {
if (!(numOrObject instanceof Type || numOrObject instanceof this.constructor)) {
numOrObject = new Type(numOrObject);
}
}
this.add(numOrObject);
}
}
}
n/a
close = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
off = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
...
return this;
};
ReflectanceArray.prototype.disable = function() {
var state = priv.get(this);
state.emitter.off();
return this;
};
// Calibrate will store the min/max values for this sensor array
// It should be called many times in order to get a lot of readings
// on light and dark areas. See calibrateUntil for a convenience
...
on = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
...
The ubiquitous "Hello World" program of the microcontroller and SoC world is "blink an LED". The following code
demonstrates how this is done using the Johnny-Five framework.
```javascript
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
// Create an Led on pin 13
var led = new five.Led(13);
// Blink every half second
led.blink(500);
});
```
...
open = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
toggle = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
function Repl(opts) { if (!Repl.isActive) { Repl.isActive = true; if (!(this instanceof Repl)) { return new Repl(opts); } // Store context values in instance property // this will be used for managing scope when // injecting new values into an existing Repl // session. this.context = {}; this.ready = false; var state = { opts: opts, board: opts.board, }; priv.set(this, state); // Store an accessible copy of the Repl instance // on a static property. This is later used by the // Board constructor to automattically setup Repl // sessions for all programs, which reduces the // boilerplate requirement. Repl.ref = this; } else { return Repl.ref; } }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
close = function () { this.cmd.emit("exit"); }
n/a
initialize = function (callback) {
var state = priv.get(this);
process.stdin.resume();
process.stdin.setEncoding("utf8");
var replDefaults = {
prompt: ">> ",
useGlobal: false
};
// Call this immediately before repl.start to
// avoid crash on Intel Edison
state.board.info("Repl", "Initialized");
// Initialize the REPL session with the default
// repl settings.
// Assign the returned repl instance to "cmd"
var cmd = repl.start(replDefaults);
this.ready = true;
// Assign a reference to the REPL's "content" object
// This will be use later by the Repl.prototype.inject
// method for allowing user programs to inject their
// own explicit values and reference
this.cmd = cmd;
this.context = cmd.context;
cmd.on("exit", function() {
state.board.emit("exit");
state.board.warn("Board", "Closing.");
var interval = setInterval(function() {
/* istanbul ignore else */
if (!state.board.io.pending) {
clearInterval(interval);
process.nextTick(process.reallyExit);
}
}, 1);
});
this.inject(state.opts);
/* istanbul ignore else */
if (callback) {
process.nextTick(callback);
}
}
...
return raw;
};
}
priv.set(this, state);
if (typeof this.initialize === "function") {
this.initialize(opts, function(data) {
raw = data;
});
}
setInterval(function() {
if (raw === null) {
return;
...
inject = function (obj) { Object.keys(obj).forEach(function(key) { Object.defineProperty( this.context, key, Object.getOwnPropertyDescriptor(obj, key) ); }, this); }
n/a
function Sensor(opts) {
if (!(this instanceof Sensor)) {
return new Sensor(opts);
}
// Defaults to 10-bit resolution
var resolution = 0x3FF;
var raw = null;
var last = -1;
var samples = [];
Board.Component.call(
this, opts = Board.Options(opts)
);
if (!opts.type) {
opts.type = "analog";
}
if (this.io.RESOLUTION &&
(this.io.RESOLUTION.ADC &&
(this.io.RESOLUTION.ADC !== resolution))) {
resolution = this.io.RESOLUTION.ADC;
}
// Set the pin to ANALOG (INPUT) mode
this.mode = opts.type === "digital" ?
this.io.MODES.INPUT :
this.io.MODES.ANALOG;
this.io.pinMode(this.pin, this.mode);
// Create a "state" entry for privately
// storing the state of the sensor
var state = {
enabled: typeof opts.enabled === "undefined" ? true : opts.enabled,
booleanBarrier: opts.type === "digital" ? 0 : null,
intervalId: null,
scale: null,
value: 0,
median: 0,
freq: opts.freq || 25,
previousFreq: opts.freq || 25,
};
// Put a reference where the prototype methods defined in this file have access
priv.set(this, state);
// Sensor instance properties
this.range = opts.range || [0, resolution];
this.limit = opts.limit || null;
this.threshold = opts.threshold === undefined ? 1 : opts.threshold;
this.isScaled = false;
this.io[opts.type + "Read"](this.pin, function(data) {
raw = data;
// Only append to the samples when noise filtering can/will be used
if (opts.type !== "digital") {
samples.push(raw);
}
}.bind(this));
// Throttle
// TODO: The event (interval) processing function should be outside of the Sensor
// constructor function (with appropriate passed (and bound?) arguments), to
// avoid creating a separate copy (of the function) for each Sensor instance.
var eventProcessing = function() {
var err, boundary;
err = null;
// For digital sensors, skip the analog
// noise filtering provided below.
if (opts.type === "digital") {
this.emit("data", raw);
/* istanbul ignore else */
if (last !== raw) {
this.emit("change", raw);
last = raw;
}
return;
}
// Keep the previous calculated value if there were no new readings
if (samples.length > 0) {
// Filter the accumulated sample values to reduce analog reading noise
state.median = median(samples);
}
this.emit("data", state.median);
// If the filtered (state.median) value for this interval is at least ± the
// configured threshold from last, fire change events
if (state.median <= (last - this.threshold) || state.median >= (last + this.threshold)) {
this.emit("change", state.median);
// Update the instance-local `last` value (only) when a new change event
// has been emitted. For comparison in the next interval
last = state.median;
}
if (this.limit) {
if (state.median <= this.limit[0]) {
boundary = "lower";
}
if (state.median >= this.limit[1]) {
boundary = "upper";
}
if (boundary) {
this.emit("limit", {
boundary: boundary,
value: state.median
});
this.emit("limit:" + boundary, state.median);
}
}
// Reset samples
samples.length = 0;
}.bind(this); // ./function eventProcessing()
Object.defineProperties(this, {
raw: {
get: function() {
return raw;
}
},
analog: {
get: function() {
if (opts.type === "digital") {
return raw;
}
return raw === null ? 0 :
Fn.map(this.raw, 0, resolution, 0, 255) | 0;
},
},
constrained: {
get: function() {
if (opts.type === "digital") {
return raw;
}
return raw === null ? 0 :
Fn.constrain(this.raw, 0, 255);
}
},
boolean: {
get: function() {
var state = priv.get(this);
var booleanBarrier = state.booleanBarrier;
var scale = state.scale || [0, resolution];
if (boolean ...
n/a
Analog = function (opts) { return new module.exports.Sensor(opts); }
n/a
function Sensors(numsOrObjects) { if (!(this instanceof Sensors)) { return new Sensors(numsOrObjects); } Object.defineProperty(this, "type", { value: Sensor }); Collection.Emitter.call(this, numsOrObjects); }
n/a
Digital = function (opts) { var pin; if (typeof opts === "number" || typeof opts === "string") { pin = opts; opts = { type: "digital", pin: pin }; } else { opts.type = opts.type || "digital"; } return new module.exports.Sensor(opts); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
booleanAt = function (barrier) { priv.get(this).booleanBarrier = barrier; return this; }
n/a
disable = function () {
var state = priv.get(this);
/* istanbul ignore else */
if (state.enabled) {
state.enabled = false;
state.previousFreq = state.freq;
this.freq = null;
}
return this;
}
n/a
enable = function () {
var state = priv.get(this);
/* istanbul ignore else */
if (!state.enabled) {
this.freq = state.freq || state.previousFreq;
}
return this;
}
n/a
fscaleTo = function (low, high) { var scale = Array.isArray(low) ? low : [low, high]; return Fn.fmap(this.raw, 0, this.resolution, scale[0], scale[1]); }
n/a
scale = function (low, high) { this.isScaled = true; priv.get(this).scale = Array.isArray(low) ? low : [low, high]; return this; }
...
function calibratedValues() {
return this.raw.map(function(value, i) {
var max = this.calibration.max[i],
min = this.calibration.min[i];
var scaled = __.scale(value, min, max, CALIBRATED_MIN_VALUE, CALIBRATED_MAX_VALUE
);
return __.constrain(scaled, CALIBRATED_MIN_VALUE, CALIBRATED_MAX_VALUE);
}, this);
}
function maxLineValue() {
return (this.sensors.length - 1) * CALIBRATED_MAX_VALUE;
}
...
scaleTo = function (low, high) { var scale = Array.isArray(low) ? low : [low, high]; return Fn.map(this.raw, 0, this.resolution, scale[0], scale[1]); }
n/a
within = function (range, unit, callback) { var upper; if (typeof range === "number") { upper = range; range = [0, upper]; } if (!Array.isArray(range)) { throw new Error("within expected a range array"); } if (typeof unit === "function") { callback = unit; unit = "value"; } if (typeof this[unit] === "undefined") { return this; } // Use the continuous read event for high resolution this.on("data", function() { var value = this[unit]; if (value >= range[0] && value <= range[1]) { callback.call(this, null, value); } }.bind(this)); return this; }
n/a
function Sensors(numsOrObjects) { if (!(this instanceof Sensors)) { return new Sensors(numsOrObjects); } Object.defineProperty(this, "type", { value: Sensor }); Collection.Emitter.call(this, numsOrObjects); }
n/a
super_ = function (numsOrObjects) {
// Create private state ahead of super call
priv.set(this, {
timing: {
last: Date.now()
}
});
Collection.call(this, numsOrObjects);
// If the Collection.Emitter was created
// with a Shared Properties object, then
// we should abide by the freq or period
// properties...
var interval = null;
var period = 5;
if (!Array.isArray(numsOrObjects) &&
(typeof numsOrObjects === "object" && numsOrObjects !== null)) {
period = numsOrObjects.freq || numsOrObjects.period || period;
// _However_, looking to the future, we
// need to start thinking about replacing
// the garbage named _freq_ (the value is
// actually a period), with real _frequency_
// in Hz.
// If provided, convert frequency to period
/* istanbul ignore else */
if (numsOrObjects.frequency) {
period = (1 / numsOrObjects.frequency) * 1000;
}
}
Object.defineProperties(this, {
period: {
get: function() {
return period;
},
set: function(value) {
if (period !== value) {
period = value;
}
if (interval) {
clearInterval(interval);
}
interval = setInterval(function() {
this.emit("data", this);
}.bind(this), period);
}
},
});
this.period = period;
this.on("newListener", function(event) {
if (event === "change" || event === "data") {
return;
}
this.forEach(function(input) {
input.on(event, function(data) {
this.emit(event, input, data);
}.bind(this));
}, this);
});
}
n/a
booleanAt = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
disable = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
enable = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
fscaleTo = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
scale = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
...
function calibratedValues() {
return this.raw.map(function(value, i) {
var max = this.calibration.max[i],
min = this.calibration.min[i];
var scaled = __.scale(value, min, max, CALIBRATED_MIN_VALUE, CALIBRATED_MAX_VALUE
);
return __.constrain(scaled, CALIBRATED_MIN_VALUE, CALIBRATED_MAX_VALUE);
}, this);
}
function maxLineValue() {
return (this.sensors.length - 1) * CALIBRATED_MAX_VALUE;
}
...
scaleTo = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
within = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
function Servo(opts) { if (!(this instanceof Servo)) { return new Servo(opts); } var history = []; var pinValue = typeof opts === "object" ? opts.pin : opts; var controller = null; Board.Component.call( this, opts = Board.Options(opts) ); this.range = opts.range || [0, 180]; this.deadband = opts.deadband || [90, 90]; this.fps = opts.fps || 100; this.offset = opts.offset || 0; this.mode = this.io.MODES.SERVO; this.interval = null; this.value = null; // StandardFirmata on Arduino allows controlling // servos from analog pins. // If we're currently operating with an Arduino // and the user has provided an analog pin name // (eg. "A0", "A5" etc.), parse out the numeric // value and capture the fully qualified analog // pin number. if (typeof opts.controller === "undefined" && Pins.isFirmata(this)) { if (typeof pinValue === "string" && pinValue[0] === "A") { pinValue = this.io.analogPins[+pinValue.slice(1)]; } pinValue = +pinValue; // If the board's default pin normalization // came up with something different, use the // the local value. if (!Number.isNaN(pinValue) && this.pin !== pinValue) { this.pin = pinValue; } } // The type of servo determines certain alternate // behaviours in the API this.type = opts.type || "standard"; // Invert the value of all servoWrite operations // eg. 80 => 100, 90 => 90, 0 => 180 if (opts.isInverted) { console.warn("The 'isInverted' property has been renamed 'invert'"); } this.invert = opts.isInverted || opts.invert || false; // Allow "setup"instructions to come from // constructor options properties this.startAt = 90; // Collect all movement history for this servo // history = [ // { // timestamp: Date.now(), // degrees: degrees // } // ]; if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.Standard; } priv.set(this, { history: history }); Board.Controller.call(this, controller, opts); Object.defineProperties(this, { history: { get: function() { return history.slice(-5); } }, last: { get: function() { return history[history.length - 1]; } }, position: { get: function() { return history.length ? history[history.length - 1].degrees : -1; } } }); this.initialize(opts); // If "startAt" is defined and center is falsy // set servo to min or max degrees if (opts.startAt !== undefined) { this.startAt = opts.startAt; this.to(opts.startAt); } // If "center" true set servo to 90deg if (opts.center) { this.center(); } if (opts.type === "continuous") { this.stop(); } }
n/a
function Servos(numsOrObjects) { if (!(this instanceof Servos)) { return new Servos(numsOrObjects); } Object.defineProperty(this, "type", { value: Servo }); Collection.call(this, numsOrObjects); }
n/a
function Servos(numsOrObjects) { if (!(this instanceof Servos)) { return new Servos(numsOrObjects); } Object.defineProperty(this, "type", { value: Servo }); Collection.call(this, numsOrObjects); }
n/a
Continuous = function (pinOrOpts) { var opts = {}; if (typeof pinOrOpts === "object") { Object.assign(opts, pinOrOpts); } else { opts.pin = pinOrOpts; } opts.type = "continuous"; return new Servo(opts); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
ccw = function (rate) {
var range;
rate = rate === undefined ? 1 : rate;
/* istanbul ignore if */
if (this.type !== "continuous") {
this.board.error(
"Servo",
"Servo.prototype." + api + " is only available for continuous servos"
);
}
if (api === "cw" || api === "clockWise") {
range = [rate, 0, 1, this.deadband[1] + 1, this.range[1]];
} else {
range = [rate, 0, 1, this.deadband[0] - 1, this.range[0]];
}
return this.to(Fn.scale.apply(null, range) | 0);
}
n/a
center = function (time, rate) { return this.to(Math.abs((this.range[0] + this.range[1]) / 2), time, rate); }
n/a
clockWise = function (rate) {
var range;
rate = rate === undefined ? 1 : rate;
/* istanbul ignore if */
if (this.type !== "continuous") {
this.board.error(
"Servo",
"Servo.prototype." + api + " is only available for continuous servos"
);
}
if (api === "cw" || api === "clockWise") {
range = [rate, 0, 1, this.deadband[1] + 1, this.range[1]];
} else {
range = [rate, 0, 1, this.deadband[0] - 1, this.range[0]];
}
return this.to(Fn.scale.apply(null, range) | 0);
}
n/a
counterClockwise = function (rate) {
var range;
rate = rate === undefined ? 1 : rate;
/* istanbul ignore if */
if (this.type !== "continuous") {
this.board.error(
"Servo",
"Servo.prototype." + api + " is only available for continuous servos"
);
}
if (api === "cw" || api === "clockWise") {
range = [rate, 0, 1, this.deadband[1] + 1, this.range[1]];
} else {
range = [rate, 0, 1, this.deadband[0] - 1, this.range[0]];
}
return this.to(Fn.scale.apply(null, range) | 0);
}
n/a
cw = function (rate) {
var range;
rate = rate === undefined ? 1 : rate;
/* istanbul ignore if */
if (this.type !== "continuous") {
this.board.error(
"Servo",
"Servo.prototype." + api + " is only available for continuous servos"
);
}
if (api === "cw" || api === "clockWise") {
range = [rate, 0, 1, this.deadband[1] + 1, this.range[1]];
} else {
range = [rate, 0, 1, this.deadband[0] - 1, this.range[0]];
}
return this.to(Fn.scale.apply(null, range) | 0);
}
n/a
home = function () { return this.to(this.startAt); }
n/a
max = function (time, rate) { return this.to(this.range[1], time, rate); }
n/a
min = function (time, rate) { return this.to(this.range[0], time, rate); }
n/a
move = function (degrees, time) { console.warn("Servo.prototype.move has been renamed to Servo.prototype.to"); return this.to(degrees, time); }
n/a
step = function (degrees, time) { return this.to(this.last.target + degrees, time); }
n/a
stop = function () { var state = priv.get(this); if (state.animation) { state.animation.stop(); } if (this.type === "continuous") { this.to( this.deadband.reduce(function(a, b) { return Math.round((a + b) / 2); }) ); } else { clearInterval(this.interval); } return this; }
n/a
sweep = function (opts) {
var options = {
keyFrames: [{
value: this.range[0]
}, {
value: this.range[1]
}],
metronomic: true,
loop: true,
easing: "inOutSine"
};
// If opts is an array, then assume a range was passed
if (Array.isArray(opts)) {
options.keyFrames = rangeToKeyFrames(opts);
} else {
if (typeof opts === "object" && opts !== null) {
Object.assign(options, opts);
/* istanbul ignore else */
if (Array.isArray(options.range)) {
options.keyFrames = rangeToKeyFrames(options.range);
}
}
}
return this.to(options);
}
n/a
to = function (degrees, time, rate) { var state = priv.get(this); var options = {}; if (typeof degrees === "object") { Object.assign(options, degrees); options.duration = degrees.duration || degrees.interval || 1000; options.cuePoints = degrees.cuePoints || [0, 1.0]; options.keyFrames = degrees.keyFrames || [ null, { value: typeof degrees.degrees === "number" ? degrees.degrees : this.startAt } ]; options.oncomplete = function() { // Enforce async execution for user "oncomplete" process.nextTick(function() { if (typeof degrees.oncomplete === "function") { degrees.oncomplete(); } this.emit("move:complete"); }.bind(this)); }.bind(this); state.isRunning = true; state.animation = state.animation || new Animation(this); state.animation.enqueue(options); } else { var target = degrees; // Enforce limited range of motion degrees = Fn.constrain(degrees, this.range[0], this.range[1]); degrees += this.offset; this.value = degrees; if (this.invert) { degrees = Fn.map( degrees, 0, 180, 180, 0 ); } if (typeof time !== "undefined") { options.duration = time; options.keyFrames = [null, { degrees: degrees }]; options.fps = rate || this.fps; this.to(options); } else { this.update(degrees); if (state.history.length > 5) { state.history.shift(); } state.history.push({ timestamp: Date.now(), degrees: degrees, target: target }); } } // return this instance return this; }
n/a
write = function (degrees, time) { console.warn("Servo.prototype.move has been renamed to Servo.prototype.to"); return this.to(degrees, time); }
...
EVS.isRawSensor = function(port) {
return port.analog === EVS.S1_ANALOG || port.analog === EVS.S2_ANALOG;
};
util.inherits(EVS, Emitter);
EVS.prototype.setup = function(port, type) {
this.bank[port.bank].write(port.mode, [type]);
};
EVS.prototype.read = function(port, register, numBytes, callback) {
if (port.sensor && port.offset && !EVS.isRawSensor(port)) {
register += port.offset;
}
...
function Servos(numsOrObjects) { if (!(this instanceof Servos)) { return new Servos(numsOrObjects); } Object.defineProperty(this, "type", { value: Servo }); Collection.call(this, numsOrObjects); }
n/a
function Collection(numsOrObjects) {
var Type = this.type;
var initObjects = [];
this.length = 0;
if (Array.isArray(numsOrObjects)) {
initObjects = numsOrObjects;
} else {
// Initialize with a Shared Properties object
/* istanbul ignore else */
if (Array.isArray(numsOrObjects.pins)) {
var keys = Object.keys(numsOrObjects).filter(function(key) {
return key !== "pins";
});
initObjects = numsOrObjects.pins.map(function(pin) {
var obj = {};
if (Array.isArray(pin)) {
obj.pins = pin;
} else {
obj.pin = pin;
}
return keys.reduce(function(accum, key) {
accum[key] = numsOrObjects[key];
return accum;
}, obj);
});
}
}
/* istanbul ignore else */
if (initObjects.length) {
while (initObjects.length) {
var numOrObject = initObjects.shift();
// When a Type exists, respect it!
if (typeof Type === "function") {
if (!(numOrObject instanceof Type || numOrObject instanceof this.constructor)) {
numOrObject = new Type(numOrObject);
}
}
this.add(numOrObject);
}
}
}
n/a
ccw = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
center = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
clockWise = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
counterClockwise = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
cw = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
home = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
max = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
min = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
move = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
step = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
stop = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
sweep = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
to = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
function ShiftRegister(opts) { if (!(this instanceof ShiftRegister)) { return new ShiftRegister(opts); } if (Array.isArray(opts)) { // [Data, Clock, Latch, Reset] opts = { pins: { data: opts[0], clock: opts[1], latch: opts[2], reset: opts.length === 4 ? opts[3] : null, } }; } else if (typeof opts.pins === "object" && Array.isArray(opts.pins)) { opts.pins = { data: opts.pins[0], clock: opts.pins[1], latch: opts.pins[2], reset: opts.pins.length === 4 ? opts.pins[3] : null, }; } Board.Component.call( this, opts = Board.Options(opts) ); this.size = opts.size || 1; this.pins.reset = typeof opts.pins.reset !== "undefined" ? opts.pins.reset : null; var isAnode = typeof opts.isAnode !== "undefined" ? opts.isAnode : false; var clear = isAnode ? 255 : 0; var state = { isAnode: isAnode, value: new Array(this.size).fill(clear), encoded: encoded[isAnode ? "anode" : "cathode"], clear: clear, }; priv.set(this, state); Object.defineProperties(this, { isAnode: { get: function() { return isAnode; } }, value: { get: function() { return state.value; } }, }); }
n/a
function ShiftRegisters(numsOrObjects) { if (!(this instanceof ShiftRegisters)) { return new ShiftRegisters(numsOrObjects); } Object.defineProperty(this, "type", { value: ShiftRegister }); Collection.call(this, numsOrObjects); }
n/a
function ShiftRegisters(numsOrObjects) { if (!(this instanceof ShiftRegisters)) { return new ShiftRegisters(numsOrObjects); } Object.defineProperty(this, "type", { value: ShiftRegister }); Collection.call(this, numsOrObjects); }
n/a
function Collection(numsOrObjects) {
var Type = this.type;
var initObjects = [];
this.length = 0;
if (Array.isArray(numsOrObjects)) {
initObjects = numsOrObjects;
} else {
// Initialize with a Shared Properties object
/* istanbul ignore else */
if (Array.isArray(numsOrObjects.pins)) {
var keys = Object.keys(numsOrObjects).filter(function(key) {
return key !== "pins";
});
initObjects = numsOrObjects.pins.map(function(pin) {
var obj = {};
if (Array.isArray(pin)) {
obj.pins = pin;
} else {
obj.pin = pin;
}
return keys.reduce(function(accum, key) {
accum[key] = numsOrObjects[key];
return accum;
}, obj);
});
}
}
/* istanbul ignore else */
if (initObjects.length) {
while (initObjects.length) {
var numOrObject = initObjects.shift();
// When a Type exists, respect it!
if (typeof Type === "function") {
if (!(numOrObject instanceof Type || numOrObject instanceof this.constructor)) {
numOrObject = new Type(numOrObject);
}
}
this.add(numOrObject);
}
}
}
n/a
clear = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
display = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
reset = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
send = function () { var length = this.length; for (var i = 0; i < length; i++) { this[i][method].apply(this[i], arguments); } return this; }
n/a
clear = function () { var state = priv.get(this); return this.send(Array(this.size).fill(state.clear)); }
n/a
display = function (value) { var state = priv.get(this); var chars; if (typeof value === "number") { // 1, 20, etc. return this.display(String(value)); } if (typeof value === "string") { var matches = value.match(/([0-9]{1}\.*)/g); if (matches && matches.length) { chars = matches.map(function(char) { // "1" if (char.length === 1) { return state.encoded[char] | (1 << 7); } // "1.?.?" return state.encoded[char[0]]; }); } } this.send(chars); state.value = chars; return this; }
n/a
reset = function () { if (this.pins.reset === null) { throw new Error("ShiftRegister was not initialized with a reset pin"); } this.io.digitalWrite(this.pins.clock, this.io.LOW); this.io.digitalWrite(this.pins.reset, this.io.LOW); this.io.digitalWrite(this.pins.clock, this.io.HIGH); this.io.digitalWrite(this.pins.reset, this.io.HIGH); return this; }
n/a
send = function (value) { var state = priv.get(this); var args = Array.from(arguments); if (args.length === 1) { args = [value]; } if (Array.isArray(value)) { args = value; } // open latch to fill register with data this.io.digitalWrite(this.pins.latch, this.io.LOW); args.forEach(function(arg) { if (typeof arg === "string") { arg = arg.charCodeAt(0); } if (this.isAnode && (arg !== 255 && !state.encoded.includes(arg) && !state.encoded.includes(arg & ~(1 << 7)))) { var index = encoded.anode.findIndex(function(value) { return value === arg; }); if (index !== -1) { arg = encoded.cathode[index]; } } this.board.shiftOut(this.pins.data, this.pins.clock, true, arg); }, this); // close latch to commit bits into register. this.io.digitalWrite(this.pins.latch, this.io.HIGH); state.value = args; return this; }
n/a
function Sonar(opts) { if (!(this instanceof Sonar)) { return new Sonar(opts); } Board.Component.call( this, opts = Board.Options(opts) ); var device, state; // Sonar instance properties this.freq = opts.freq || 100; this.value = null; state = { last: 0, median: 0, samples: [] }; priv.set(this, state); if (typeof opts.device === "string") { device = Devices[opts.device]; } else { device = opts.device; } if (typeof device === "undefined") { device = Devices.DEFAULT; } device.initialize.call(this, opts); if (!device.descriptor.inches) { device.descriptor.inches = { get: function() { return +(this.cm * 0.39).toFixed(2); } }; } device.descriptor.in = device.descriptor.inches; Object.defineProperties(this, device.descriptor); // Throttle setInterval(function() { // Nothing read since previous interval if (state.samples.length === 0) { return; } state.median = state.samples.sort()[Math.floor(state.samples.length / 2)]; this.value = state.median; this.emit("data", state.median); // If the state.median value for this interval is not the same as the // state.median value in the last interval, fire a "change" event. // if (state.last && state.median && (state.median.toFixed(1) !== state.last.toFixed(1))) { this.emit("change", state.median); } // Store this media value for comparison // in next interval state.last = state.median; // Reset state.samples; state.samples.length = 0; }.bind(this), this.freq); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
within = function (range, unit, callback) { var upper; if (typeof range === "number") { upper = range; range = [0, upper]; } if (!Array.isArray(range)) { throw new Error("within expected a range array"); } if (typeof unit === "function") { callback = unit; unit = "value"; } if (typeof this[unit] === "undefined") { return this; } // Use the continuous read event for high resolution this.on("data", function() { var value = this[unit]; if (value >= range[0] && value <= range[1]) { callback.call(this, null, value); } }.bind(this)); return this; }
n/a
function Stepper(opts) { var state, params = []; if (!(this instanceof Stepper)) { return new Stepper(opts); } Board.Component.call( this, opts = Board.Options(opts) ); if (!isSupported(this.io)) { throw new Error( "Stepper is not supported" ); } if (!opts.pins) { throw new Error( "Stepper requires a `pins` object or array" ); } if (!opts.stepsPerRev) { throw new Error( "Stepper requires a `stepsPerRev` number value" ); } steppers.set(this.board, steppers.get(this.board) || []); this.id = steppers.get(this.board).length; if (this.id >= MAXSTEPPERS) { throw new Error( "Stepper cannot exceed max steppers (" + MAXSTEPPERS + ")" ); } // Convert an array of pins to the appropriate named pin if (Array.isArray(this.pins)) { if (this.pins.length === 2) { // Using an array of 2 pins requres a TYPE // to disambiguate DRIVER and TWO_WIRE if (!opts.type) { throw new Error( "Stepper requires a `type` number value (DRIVER, TWO_WIRE)" ); } } if (opts.type === Stepper.TYPE.DRIVER) { this.pins = { step: this.pins[0], dir: this.pins[1] }; } else { this.pins = new MotorPins(this.pins); } } // Attempt to guess the type if none is provided if (!opts.type) { if (this.pins.dir) { opts.type = Stepper.TYPE.DRIVER; } else { if (this.pins.motor3) { opts.type = Stepper.TYPE.FOUR_WIRE; } else { opts.type = Stepper.TYPE.TWO_WIRE; } } } // Initial Stepper config params (same for all 3 types) params.push(this.id, opts.type, opts.stepsPerRev); if (opts.type === Stepper.TYPE.DRIVER) { if (typeof this.pins.dir === "undefined" || typeof this.pins.step === "undefined") { throw new Error( "Stepper.TYPE.DRIVER expects: `pins.dir`, `pins.step`" ); } params.push( this.pins.dir, this.pins.step ); } if (opts.type === Stepper.TYPE.TWO_WIRE) { if (typeof this.pins.motor1 === "undefined" || typeof this.pins.motor2 === "undefined") { throw new Error( "Stepper.TYPE.TWO_WIRE expects: `pins.motor1`, `pins.motor2`" ); } params.push( this.pins.motor1, this.pins.motor2 ); } if (opts.type === Stepper.TYPE.FOUR_WIRE) { if (typeof this.pins.motor1 === "undefined" || typeof this.pins.motor2 === "undefined" || typeof this.pins.motor3 === "undefined" || typeof this.pins.motor4 === "undefined") { throw new Error( "Stepper.TYPE.FOUR_WIRE expects: `pins.motor1`, `pins.motor2`, `pins.motor3`, `pins.motor4`" ); } params.push( this.pins.motor1, this.pins.motor2, this.pins.motor3, this.pins.motor4 ); } // Iterate the params and set each pin's mode to MODES.STEPPER // Params: // [deviceNum, type, stepsPerRev, dirOrMotor1Pin, stepOrMotor2Pin, motor3Pin, motor4Pin] // The first 3 are required, the remaining 2-4 will be pins params.slice(3).forEach(function(pin) { this.io.pinMode(pin, this.io.MODES.STEPPER); }, this); this.io.stepperConfig.apply(this.io, params); steppers.get(this.board).push(this); state = Step.PROPERTIES.reduce(function(state, key, i) { return (state[key] = typeof opts[key] !== "undefined" ? opts[key] : Step.DEFAULTS[i], state); }, { isRunning: false, type: opts.type, pins: this.pins }); priv.set(this, state); Object.defineProperties(this, { type: { get: function() { return state.type; } }, pins: { get: function() { return state.pins; } } }); }
n/a
accel = function (value) { var state = priv.get(this); if (typeof value === "undefined") { return state[prop]; } state[prop] = value; return this; }
n/a
ccw = function () { return this.direction(0); }
n/a
cw = function () { return this.direction(1); }
n/a
decel = function (value) { var state = priv.get(this); if (typeof value === "undefined") { return state[prop]; } state[prop] = value; return this; }
n/a
direction = function (value) { var state = priv.get(this); if (typeof value === "undefined") { return state[prop]; } state[prop] = value; return this; }
n/a
rpm = function (rpm) { var state = priv.get(this); if (typeof rpm === "undefined") { return state.rpm; } state.rpm = rpm; state.speed = Math.round(rpm * TAU * 100 / 60); return this; }
n/a
speed = function (speed) { var state = priv.get(this); if (typeof speed === "undefined") { return state.speed; } state.speed = speed; state.rpm = Math.round(speed / TAU / 100 * 60); return this; }
n/a
step = function (stepsOrOpts, callback) { var steps, step, state, params, isValidStep; steps = typeof stepsOrOpts === "object" ? (stepsOrOpts.steps || 0) : Math.floor(stepsOrOpts); step = new Step(this); state = priv.get(this); params = []; isValidStep = true; function failback(error) { isValidStep = false; if (callback) { callback(error); } } params.push(steps); if (typeof stepsOrOpts === "object") { // If an object of property values has been provided, // call the correlating method with the value argument. Step.PROPERTIES.forEach(function(key) { if (typeof stepsOrOpts[key] !== "undefined") { this[key](stepsOrOpts[key]); } }, this); } if (!state.speed) { this.rpm(state.rpm); step.speed = this.speed(); } // Ensure that the property params are set in the // correct order, but without rpm Step.PROPERTIES.slice(1).forEach(function(key) { params.push(step[key] = this[key]()); }, this); if (steps === 0) { failback( new Error( "Must set a number of steps when calling `step()`" ) ); } if (step.direction < 0) { failback( new Error( "Must set a direction before calling `step()`" ) ); } if (isValidStep) { state.isRunning = true; params.push(function(complete) { state.isRunning = false; callback(null, complete); }); step.move.apply(step, params); } return this; }
n/a
function Switch(opts) { if (!(this instanceof Switch)) { return new Switch(opts); } // Create a 5 ms debounce boundary on event triggers // this avoids button events firing on // press noise and false positives var trigger = Fn.debounce(function(key) { aliases[key].forEach(function(type) { this.emit(type, null); }, this); }, 5); // Resolve the default type to Normally Open opts.type = opts.type || "NO"; // Is this instance Normally Open? var isNormallyOpen = opts.type === "NO"; var raw = null; var invert = typeof opts.invert !== "undefined" ? opts.invert : (isNormallyOpen || false); // Logical Defaults var closeValue = 1; var openValue = 0; if (invert) { closeValue ^= 1; openValue ^= 1; } Board.Component.call( this, opts = Board.Options(opts) ); this.io.pinMode(this.pin, this.io.MODES.INPUT); if (isNormallyOpen) { this.io.digitalWrite(this.pin, this.io.HIGH); } this.io.digitalRead(this.pin, function(data) { raw = data; trigger.call(this, this.isOpen ? "open" : "close"); }.bind(this)); Object.defineProperties(this, { value: { get: function() { return Number(this.isOpen); } }, invert: { get: function() { return invert; }, set: function(value) { invert = value; closeValue = invert ? 0 : 1; openValue = invert ? 1 : 0; } }, closeValue: { get: function() { return closeValue; }, set: function(value) { closeValue = value; openValue = value ^ 1; } }, openValue: { get: function() { return openValue; }, set: function(value) { openValue = value; closeValue = value ^ 1; } }, isOpen: { get: function() { return raw === openValue; } }, isClosed: { get: function() { return raw === closeValue; } }, }); }
n/a
function Switches(numsOrObjects) { if (!(this instanceof Switches)) { return new Switches(numsOrObjects); } Object.defineProperty(this, "type", { value: Switch }); Collection.Emitter.call(this, numsOrObjects); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function Switches(numsOrObjects) { if (!(this instanceof Switches)) { return new Switches(numsOrObjects); } Object.defineProperty(this, "type", { value: Switch }); Collection.Emitter.call(this, numsOrObjects); }
n/a
super_ = function (numsOrObjects) {
// Create private state ahead of super call
priv.set(this, {
timing: {
last: Date.now()
}
});
Collection.call(this, numsOrObjects);
// If the Collection.Emitter was created
// with a Shared Properties object, then
// we should abide by the freq or period
// properties...
var interval = null;
var period = 5;
if (!Array.isArray(numsOrObjects) &&
(typeof numsOrObjects === "object" && numsOrObjects !== null)) {
period = numsOrObjects.freq || numsOrObjects.period || period;
// _However_, looking to the future, we
// need to start thinking about replacing
// the garbage named _freq_ (the value is
// actually a period), with real _frequency_
// in Hz.
// If provided, convert frequency to period
/* istanbul ignore else */
if (numsOrObjects.frequency) {
period = (1 / numsOrObjects.frequency) * 1000;
}
}
Object.defineProperties(this, {
period: {
get: function() {
return period;
},
set: function(value) {
if (period !== value) {
period = value;
}
if (interval) {
clearInterval(interval);
}
interval = setInterval(function() {
this.emit("data", this);
}.bind(this), period);
}
},
});
this.period = period;
this.on("newListener", function(event) {
if (event === "change" || event === "data") {
return;
}
this.forEach(function(input) {
input.on(event, function(data) {
this.emit(event, input, data);
}.bind(this));
}, this);
});
}
n/a
function Thermometer(opts) { if (!(this instanceof Thermometer)) { return new Thermometer(opts); } var controller = null; var last = null; var raw = null; Board.Component.call( this, opts = Board.Options(opts) ); var freq = opts.freq || 25; // Analog Reference Voltage (default to board.io.aref || 5) this.aref = opts.aref || this.io.aref || 5; if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller == null) { controller = Controllers.ANALOG; } priv.set(this, {}); Board.Controller.call(this, controller, opts); if (!this.toCelsius) { this.toCelsius = opts.toCelsius || function(x) { return x; }; } var descriptors = { celsius: { get: function() { return this.toCelsius(raw); } }, fahrenheit: { get: function() { return toFixed((this.celsius * 9 / 5) + 32, 2); } }, kelvin: { get: function() { return toFixed(this.celsius + CELSIUS_TO_KELVIN, 2); } } }; // Convenience aliases descriptors.C = descriptors.celsius; descriptors.F = descriptors.fahrenheit; descriptors.K = descriptors.kelvin; Object.defineProperties(this, descriptors); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { raw = data; }); } setInterval(function() { if (raw == null) { return; } var data = {}; data.C = data.celsius = this.celsius; data.F = data.fahrenheit = this.fahrenheit; data.K = data.kelvin = this.kelvin; this.emit("data", data); if (this.celsius !== last) { last = this.celsius; this.emit("change", data); } }.bind(this), freq); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
clear = function () { activeDrivers.clear(); }
n/a
get = function (board, driverName, opts) { var drivers, driver; if (!activeDrivers.has(board)) { activeDrivers.set(board, {}); } drivers = activeDrivers.get(board); if (!drivers[driverName]) { driver = new Emitter(); Object.defineProperties(driver, Drivers[driverName]); driver.initialize(board, opts); drivers[driverName] = driver; } return drivers[driverName]; }
...
var Controllers = {
BNO055: {
initialize: {
value: function(opts, dataHandler) {
var IMU = require("./imu"),
driver = IMU.Drivers.get(this.board, "BNO055", opts);
driver.on("data", function(data) {
dataHandler(data);
});
}
},
toScaledEuler: {
...
function Wii(opts) { if (!(this instanceof Wii)) { return new Wii(opts); } Board.Component.call(this, opts); // Derive device definition from Devices var device = Devices[opts.device]; var address = device.address; var bytes = device.bytes; var delay = device.delay; var data = device.data.bind(this); var setup = device.setup; var preread = device.preread; // Wii controller instance properties this.freq = opts.freq || 100; // Button instance properties this.holdtime = opts.holdtime || 500; this.threshold = opts.threshold || 10; // Initialize components device.initialize.call(this); // Set initial "last data" byte array last.set(this, [0, 0, 0, 0, 0, 0, 0]); // Set up I2C data connection this.io.i2cConfig(opts); // Iterate and write each set of setup instructions setup.forEach(function(bytes) { this.io.i2cWrite(address, bytes); }, this); // Unthrottled i2c read request loop setInterval(function() { // Send this command to get all sensor data and store into // the 6-byte register within Wii controller. // This must be execute before reading data from the Wii. // Iterate and write each set of setup instructions preread.forEach(function(bytes) { this.io.i2cWrite(address, bytes); }, this); // Request six bytes of data from the controller this.io.i2cReadOnce(address, bytes, data); // Use the high-frequency data read loop as the change event // emitting loop. This drastically improves change event // frequency and sensitivity // // Emit change events if any delta is greater than // the threshold // RVL-005 does not have a read method at this time. if (typeof device.read !== "undefined") { device.read.call(this); } }.bind(this), delay || this.freq); // Throttled "read" event loop setInterval(function() { var event = new Board.Event({ target: this }); this.emit("data", event); }.bind(this), this.freq); }
n/a
Classic = function (opts) { opts = opts || {}; opts.device = "RVL-005"; return new Wii(opts); }
n/a
Nunchuk = function (opts) { opts = opts || {}; opts.device = "RVL-004"; return new Wii(opts); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
Accelerometer = function (controller) { if (!(this instanceof Wii.Components.Accelerometer)) { return new Wii.Components.Accelerometer(controller); } this.controller = controller; var state, accessors; // Initialize empty state object state = {}; // Initialize empty accessors object accessors = {}; // Enumerate Joystick properties ["x", "y", "z", "dx", "dy", "dz"].forEach(function(key) { state[key] = 0; // Define accessors for each property in Joystick list accessors[key] = { get: function() { return state[key]; } }; }, this); // Store private state cache priv.set(this, state); // Register newly defined accessors Object.defineProperties(this, accessors); }
n/a
Button = function (which, controller) { if (!(this instanceof Wii.Components.Button)) { return new Wii.Components.Button(which, controller); } // c or z. this.which = which; // reference to parent controller this.controller = controller; // Set initial values for state tracking var state = { isDown: false }; priv.set(this, state); Object.defineProperties(this, { // is the button up (not pressed)? isUp: { get: function() { return !state.isDown; } }, // is the button pressed? isDown: { get: function() { return state.isDown; } } }); }
n/a
Joystick = function (controller) { if (!(this instanceof Wii.Components.Joystick)) { return new Wii.Components.Joystick(controller); } this.controller = controller; var state, accessors; // Initialize empty state object state = {}; // Initialize empty accessors object accessors = {}; // Enumerate Joystick properties ["x", "y", "dx", "dy"].forEach(function(key) { state[key] = 0; // Define accessors for each property in Joystick list accessors[key] = { get: function() { return state[key]; } }; }, this); // Store private state cache priv.set(this, state); // Register newly defined accessors Object.defineProperties(this, accessors); }
n/a
function EVS(options) { if (shared) { return shared; } this.bank = { a: new Bank({ address: EVS.BANK_A, io: options.io, }), b: new Bank({ address: EVS.BANK_B, io: options.io, }) }; shared = this; }
n/a
isRawSensor = function (port) { return port.analog === EVS.S1_ANALOG || port.analog === EVS.S2_ANALOG; }
...
EVS.prototype.setup = function(port, type) {
this.bank[port.bank].write(port.mode, [type]);
};
EVS.prototype.read = function(port, register, numBytes, callback) {
if (port.sensor && port.offset && !EVS.isRawSensor(port)) {
register += port.offset;
}
this.bank[port.bank].read(register, numBytes, callback);
};
EVS.prototype.write = function(port, register, data) {
...
shieldPort = function (pin) { var port = EVS[pin]; if (port === undefined) { throw new Error("Invalid EVShield pin name"); } var address, analog, bank, motor, mode, offset, sensor; var endsWithS1 = false; if (pin.startsWith("BA")) { address = EVS.BANK_A; bank = "a"; } else { address = EVS.BANK_B; bank = "b"; } if (pin.includes("M")) { motor = pin.endsWith("M1") ? EVS.S1 : EVS.S2; } if (pin.includes("S")) { endsWithS1 = pin.endsWith("S1"); // Used for reading 2 byte integer values from raw sensors analog = endsWithS1 ? EVS.S1_ANALOG : EVS.S2_ANALOG; // Sensor Mode (1 or 2?) mode = endsWithS1 ? EVS.S1_MODE : EVS.S2_MODE; // Used for read registers offset = endsWithS1 ? EVS.S1_OFFSET : EVS.S2_OFFSET; // Used to address "sensor type" sensor = endsWithS1 ? EVS.S1 : EVS.S2; } return { address: address, analog: analog, bank: bank, mode: mode, motor: motor, offset: offset, port: port, sensor: sensor, }; }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
read = function (port, register, numBytes, callback) { if (port.sensor && port.offset && !EVS.isRawSensor(port)) { register += port.offset; } this.bank[port.bank].read(register, numBytes, callback); }
...
EVS.prototype.read = function(port, register, numBytes, callback) {
if (port.sensor && port.offset && !EVS.isRawSensor(port)) {
register += port.offset;
}
this.bank[port.bank].read(register, numBytes, callback);
};
EVS.prototype.write = function(port, register, data) {
this.bank[port.bank].write(register, data);
};
/*
...
setup = function (port, type) { this.bank[port.bank].write(port.mode, [type]); }
n/a
write = function (port, register, data) { this.bank[port.bank].write(register, data); }
...
EVS.isRawSensor = function(port) {
return port.analog === EVS.S1_ANALOG || port.analog === EVS.S2_ANALOG;
};
util.inherits(EVS, Emitter);
EVS.prototype.setup = function(port, type) {
this.bank[port.bank].write(port.mode, [type]);
};
EVS.prototype.read = function(port, register, numBytes, callback) {
if (port.sensor && port.offset && !EVS.isRawSensor(port)) {
register += port.offset;
}
...
function Orientation(opts) { if (!(this instanceof Orientation)) { return new Orientation(opts); } Board.Component.call( this, opts = Board.Options(opts) ); var freq = opts.freq || 25; var controller = null; var raw = null; var state = { euler: { heading: 0, roll: 0, pitch: 0, }, quarternion: { w: 0, x: 0, y: 0, z: 0, }, calibration: 0, }; if (opts.controller && typeof opts.controller === "string") { controller = Controllers[opts.controller.toUpperCase()]; } else { controller = opts.controller; } if (controller === null || typeof controller !== "object") { throw new Error("Missing valid Orientation controller"); } Board.Controller.call(this, controller, opts); if (!this.toScaledQuarternion) { this.toScaledQuarternion = opts.toScaledQuarternion || function(raw) { return raw; }; } if (!this.toScaledEuler) { this.toScaledEuler = opts.toScaledEuler || function(raw) { return raw; }; } priv.set(this, state); if (typeof this.initialize === "function") { this.initialize(opts, function(data) { raw = data; }); } setInterval(function() { if (raw === null) { return; } var didOrientationChange = false; var didCalibrationChange = false; ["heading", "roll", "pitch"].forEach(function(el) { if (state.euler[el] !== raw.orientation.euler[el]) { didOrientationChange = true; } state.euler[el] = raw.orientation.euler[el]; }); ["w", "x", "y", "z"].forEach(function(el) { if (state.quarternion[el] !== raw.orientation.quarternion[el]) { didOrientationChange = true; } state.quarternion[el] = raw.orientation.quarternion[el]; }); //if we have a raw calibration state... // not sure if this is the best place... some devices may not have a calibration state... if (raw.calibration) { if (state.calibration !== raw.calibration) { didCalibrationChange = true; } state.calibration = raw.calibration; } var data = { euler: this.euler, quarternion: this.quarternion, calibration: this.calibration }; this.emit("data", data); if (didOrientationChange) { this.emit("change", data); } //not sure how we can get this event into other drivers if (didCalibrationChange) { this.emit("calibration", this.calibration); } }.bind(this), freq); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function ReflectanceArray(opts) { if (!(this instanceof ReflectanceArray)) { return new ReflectanceArray(opts); } this.opts = Board.Options(opts); Board.Component.call( this, this.opts, { requestPin: false } ); // Read event throttling this.freq = opts.freq || 25; // Make private data entry var state = { lastLine: 0, isOn: false, calibration: { min: [], max: [] }, autoCalibrate: opts.autoCalibrate || false }; priv.set(this, state); initialize.call(this); Object.defineProperties(this, { isOn: { get: function() { return state.emitter.isOn; } }, isCalibrated: { get: function() { return calibrationIsValid(this.calibration, this.sensors); } }, isOnLine: { get: function() { var line = this.line; return line > CALIBRATED_MIN_VALUE && line < maxLineValue.call(this); } }, sensors: { get: function() { return state.sensorStates.map(function(sensorState) { return sensorState.sensor; }); } }, calibration: { get: function() { return state.calibration; } }, raw: { get: function() { return state.sensorStates.map(function(sensorState) { return sensorState.rawValue; }); } }, values: { get: function() { return this.isCalibrated ? calibratedValues.call(this) : this.raw; } }, line: { get: function() { return this.isCalibrated ? getLine.call(this) : 0; } } }); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
nano = function (ns) { var start = process.hrtime(); while (process.hrtime() < start + ns) {} }
n/a
within = function (range, unit, callback) { var upper; if (typeof range === "number") { upper = range; range = [0, upper]; } if (!Array.isArray(range)) { throw new Error("within expected a range array"); } if (typeof unit === "function") { callback = unit; unit = "value"; } if (typeof this[unit] === "undefined") { return this; } // Use the continuous read event for high resolution this.on("data", function() { var value = this[unit]; if (value >= range[0] && value <= range[1]) { callback.call(this, null, value); } }.bind(this)); return this; }
n/a