Skip to content
Rick Waldron edited this page Jan 13, 2015 · 35 revisions

(This document is an incomplete draft)

An IO plugin is any class whose instances implement a Firmata compatible interface. For an in-depth case study of creating an IO plugin, read about the design and creation of the Galileo-IO Plugin here.

Available IO Plugins

The following platform IO Plugins are currently available:

Minimum Plugin Class Requirements

The plugin must...

  • Be a constructor function that defines a prototype object
  • Be a subclass of EventEmitter
  • Initialize instances that must...
    • asynchronously emit a "connected" event when the connection to a physical device has been made.
    • asynchronously emit a "ready" event when the handshake to the physical device is complete.
    • include a property named isReady whose initial value is false. isReady must be set to true in the same or previous execution turn as the the "ready" event is emitted.
      • The process of establishing a connection and becoming "ready" is irrelevant to this document's purposes.
    • include a readonly property named MODES whose value is a frozen object containing the following property/values: { INPUT: 0, OUTPUT: 1, ANALOG: 2, PWM: 3, SERVO: 4 }
    • include a readonly property named pins whose value is an array of pin configuration objects. The indices of the pins array must correspond to the pin address integer value, eg. on an Arduino UNO digital pin 0 is at index 0 and analog pin 0 is index 14. See mock-pins.js for a complete example.
      • each pin configuration object must contain the following properties and values:
        • supportedModes: an array of modes supported by this pin, eg.
          • [0, 1, 2] represents INPUT, OUTPUT, ANALOG. (Analog pin outs)
          • [0, 1, 4] represents INPUT, OUTPUT, SERVO. (Digital pin outs)
          • [0, 1, 3, 4] represents INPUT, OUTPUT, PWM, SERVO. (Digital PWM pin outs)
        • mode: the current mode this pin is set to.
        • value: the current value of this pin
          • INPUT mode: property updated via the read loop
          • OUTPUT mode: property updated via *Write methods
        • report: 1 if reporting, 0 if not reporting
        • analogChannel: corresponding analogPin index (127 if none), eg. analogChannel: 0 is A0 whose index is 14 in the pins array.
    • include a readonly property named analogPins whose value is an array of pin indices that correspond to the analog pin indices in the pins array.
  • If an essential IO feature is not implemented or cannot be implemented, the method must throw. For example, the Raspberry Pi does not support analog inputs, if user code calls through to an analogRead, the program must throw as an irrefutable means of indicating non-support.
  • If a non-essential IO feature is not implemented or cannot be implemented, the method must accept the expected arguments and indicate successful completion. For example, if it receives a callback, that callback must be called asynchronously.

Minimum API Requirements

pinMode(pin, mode)

  • Set the mode of a specified pin to one of:
INPUT: 0
OUTPUT: 1
ANALOG: 2
PWM: 3
SERVO: 4
  • Pins with "A" prefix that are set to INPUT should actually store ANALOG (2) on the pin's mode property
  • In firmata.js and Firmata protocol, ANALOG mode is used for reading (input) on analog pins because only a pin address integer is sent over the wire, which means that A0 is sent as 0, A1 as 1 and so on. This creates an ambiguity: which 0 and 1 are we sending, digital or analog? Then, for reporting, analog reads are separated: https://github.com/firmata/arduino/blob/master/examples/StandardFirmata/StandardFirmata.ino#L625-L632 This may not be relevant to all IO-Plugins, they may only need to provide the mode for compatibility and override it in pinMode. For Johnny-Five analog sensors to work with an IO Plugin, they need to support the conversion of 2 => 0 or 2 as it's used in firmata.

analogWrite(pin, value) pwmWrite(pin, value) (to supercede analogWrite)

  • Ensure pin mode is PWM (3)
  • Ensure PWM capability
  • Accept an 8 bit value (0-255) to write

digitalWrite(pin, value)

  • Ensure pin mode is OUTPUT (1)
  • Write HIGH/LOW (single bit: 1 or 0)

i2cWrite(address, inBytes)

  • Ensure pin mode is UNKNOWN (99)
    • Can be transformed
  • inBytes is an array of data bytes to write

i2cWrite(address, register, inBytes)

  • Ensure pin mode is UNKNOWN (99)
    • Can be transformed
  • register is a single byte
  • inBytes is an array of data bytes to write

i2cWriteReg(address, register, value)

  • Ensure pin mode is UNKNOWN (99)
    • Can be transformed
  • register is a single byte
  • value is a single byte value

servoWrite(pin, value)

  • Ensure pin mode is SERVO (4)
    • Can be transformed
  • Ensure PWM capability
  • Accept an 8 bit value (0-255) to write

analogRead(pin, handler)

  • Ensure pin mode is ANALOG (2)
    • Can be transformed
  • Create a data event stream, invoking handler at an implementation independent frequency, however it is recommended that handler is called no less than once every 19 milliseconds.
  • A corresponding "analog-read-${pin}" event is also emitted

digitalRead(pin, handler)

  • Ensure pin mode is INPUT (0)
    • Can be transformed
  • Create a data event stream, invoking handler at an implementation independent frequency, however it is recommended that handler is called no less than once every 19 milliseconds.
  • A corresponding "digital-read-${pin}" event is also emitted

i2cRead(address, register, bytesToRead, handler)

  • Ensure pin mode is UNKNOWN (99)
    • Can be transformed
  • register is set prior to, or as part of, the read request.
  • Create a single data event, invoking handler once per read, continuously and asynchronously reading.
  • A corresponding "I2C-reply-${address}-${register}" event is also emitted

i2cRead(address, bytesToRead, handler)

  • Ensure pin mode is UNKNOWN (99)
    • Can be transformed
  • Create a single data event, invoking handler once per read, continuously and asynchronously reading.
  • A corresponding "I2C-reply-${address}-0" event is also emitted

i2cReadOnce(address, register, bytesToRead, handler)

  • Ensure pin mode is UNKNOWN (99)
    • Can be transformed
  • register is set prior to, or as part of, the read request.
  • Create a single data event, invoking handler once after a single asynchronous read.
  • A corresponding "I2C-reply-${address}-0" event is also emitted

i2cReadOnce(address, bytesToRead, handler)

  • Ensure pin mode is UNKNOWN (99)
    • Can be transformed
  • Create a single data event, invoking handler once after a single asynchronous read.
  • A corresponding "I2C-reply-${address}-${register}" event is also emitted

Special Method Definitions

normalize(pin)

  • Define a special method that Johnny-Five will call when normalizing the pin value.
// Examples: 
var io = new IOPlugin();

// The board might want to map "A*" pins to their integer value, 
// eg. Arduino allows user code to write "A0" for pin 14:
io.normalize("A0"); // 14

Special Property Definitions

defaultLed

  • This is the pin address for the board's default, built-in led.

TODO

  • Define pluggable transports, for example: replacing node-serialport with socket.io-serialport and similar.
Clone this wiki locally