j5-rc-receiver
Version:
Nintendo RC Receiver component class plugin for Johnny-Five
154 lines (121 loc) • 3.93 kB
JavaScript
if (!Array.from || !Map || !Object.assign || !global.Symbol) {
require("es6-shim");
}
var Emitter = require("events").EventEmitter;
var util = require("util");
var priv = new Map();
var iterator = "@@iterator";
// TODO: should be customizable?
var channelNames = ["throttle", "aileron", "elevator", "rudder", "gear", "aux1", "aux2", "aux3"];
var addresses = [0x0A, 0x0B, 0x0C, 0x0D];
/* jshint unused: false */
var Controllers = {
// We'll migrate to this model once we know more
// about each type of Receiver that we want to support
};
function Channel(name, channel, value, previous) {
this.name = name;
this.channel = channel;
this.value = value;
this.previous = previous;
}
module.exports = function(five) {
return (function() {
function Receiver(opts) {
if (!(this instanceof Receiver)) {
return new Receiver(opts);
}
five.Board.Component.call(
this, opts = five.Board.Options(opts)
);
var address = opts.address || addresses[0];
var channels = opts.channels || 6;
var names = channelNames.slice();
if (Array.isArray(channels)) {
// TODO: add support for custom channel names
names = channels.slice();
channels = channels.length;
}
var state = {
names: names,
channels: Array(channels).fill(0).map(function(value, index) {
return new Channel(names[index], index + 1, value, value);
}),
};
priv.set(this, state);
// Ensure the address is passed through
opts.address = address;
var channelsDescriptor = state.channels.reduce(function(accum, channel, index) {
accum[index + 1] = {
get: function() {
return state.channels[index].value;
}
};
return accum;
}, {});
Object.defineProperties(this, channelsDescriptor);
this.io.i2cConfig(opts);
// Send a reset command
this.io.i2cWrite(address, 0x01);
// Request channel data from bus
this.io.i2cRead(address, channels * 2, function(data) {
for (var i = 0; i < channels; i++) {
state.channels[i].previous = state.channels[i].value;
state.channels[i].value = five.Fn.uint16(data[i * 2], data[i * 2 + 1]);
if (state.channels[i].value !== state.channels[i].previous) {
var change = Object.assign({}, state.channels[i]);
this.emit("change", change);
this.emit("change:" + change.name, change);
}
}
this.emit("data", Object.assign({}, this));
}.bind(this));
}
util.inherits(Receiver, Emitter);
if (typeof Symbol !== "undefined" && typeof Symbol.iterator !== "undefined") {
iterator = Symbol.iterator;
}
Receiver.prototype[iterator] = function() {
var channel = 0;
var receiver = this;
return {
next: function() {
return ++channel in receiver ? {
value: receiver[channel],
done: false
} : {
done: true
};
},
};
};
Receiver.prototype.channel = function(channel) {
var state = priv.get(this);
var index = -1;
if (typeof channel === "string") {
index = state.names.indexOf(channel.toLowerCase());
} else {
// `channel` is expected to be 1-8 (as in, not zero indexed)
index = channel - 1;
}
if (index < 0) {
return null;
}
return this.channelAt(index);
};
Receiver.prototype.channelAt = function(index) {
var state = priv.get(this);
var channel = state.channels[index];
return new Channel(channel.name, index + 1, channel.value, channel.previous);
};
return Receiver;
}());
};
/**
* To use the plugin in a program:
*
* var five = require("johnny-five");
* var Receiver = require("j5-rc-receiver")(five);
*
*
*/