firmata.js icon indicating copy to clipboard operation
firmata.js copied to clipboard

Multiple Digital Writes: Feature Proposal

Open dtex opened this issue 8 years ago • 4 comments

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?

dtex avatar Oct 20 '17 21:10 dtex

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.

soundanalogous avatar Oct 21 '17 02:10 soundanalogous

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

dtex avatar Oct 21 '17 03:10 dtex

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
  ]);
}

dtex avatar May 06 '18 19:05 dtex

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.

dtex avatar May 20 '18 18:05 dtex