firmata.js
firmata.js copied to clipboard
Multiple Digital Writes: Feature Proposal
On digitalWrites I would like to be able to call writeToTransport once instead of once for each pin.
My plan was to either overload digitalWrite with arrays or create a new method (i.e. digitalWriteMulti).
For example:
// digitalWriteMulti(pins, values);
digitalWriteMulti([1,2,3,4], [1,0,1,0]);
// Results in one writeToTransport on nextTick
- or -
digitalWriteMulti([1,2,9,11], [1,0,1,0]);
// Results in two writeToTransports on nextTick. One for each port
I want this because I believe that I can get a reasonable speed on stepper motors with whole or half steps using just standardFirmata.
Perhaps there is already a way to do this?
One way to do this would be to add a writeDigitalPort(portNumber, portValue) method. You can set up to 8 pins at once this way, each pin is a bit. You'd just have to make sure that the motor is wired to pins in the same port. In firmata ports are allocated per 8 digital pins in order counting up from 0 so port0 is pins D0-D7, port1 is pins D8-D15, etc.
I thought about that, but the 8-pins per port is unique to firmata and I need to create something that will work for all the different IO plugins. writeDigitalPort doesn't make sense on other platforms. That's the reason I wanted to handle the pin to port stuff in firmata.js
What about an enqueueDigitalWrite(pin, value) method that builds a list of write commands and updates the ports on next tick? That way we would only have to write once during each pass through the event loop. Client libraries would not have to manage ports/port states, they could just check for the existence of enqueueDigitalWrite and if it exists use it instead of digitalWrite.
// psuedocoding
let digitalWriteQueue = [];
Board.prototype.enqueueDigitalWrite = function(pin, value) {
if (!digitalWriteQueue.length) {
process.nextTick(processDIgitalWriteQueue);
}
digitalWriteQueue.push([pin, value]);
};
function processDigitalWriteQueue() {
let portsToWrite = [];
digitalWriteQueue.forEach(command => {
let port = command[0] >> 3;
portsToWrite.push(port);
let bit = 1 << (command[0] & 0x07);
this.pins[pin].value = value;
if (value) {
this.ports[port] |= bit;
} else {
this.ports[port] &= ~bit;
}
});
portsToWrite.forEach(port => writeDigitalPort);
});
function digitalWritePort(port) {
writeToTransport(this, [
DIGITAL_MESSAGE | port,
this.ports[port] & 0x7F,
(this.ports[port] >> 7) & 0x7F
]);
}
I've finally got the new stepper class in J5 far enough along that I was able to test this with a full J5 stack and it doubled the speed that I could move a stepper using standardFirmata. Gonna submit a PR soon.