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