From 89db4e804a9546dfedae85e94a54aae0f19a3e0f Mon Sep 17 00:00:00 2001 From: Zoltan Kis Date: Wed, 26 Apr 2017 17:03:51 +0300 Subject: [PATCH 1/8] Board: make API synchronous Signed-off-by: Zoltan Kis --- board/README.md | 76 ++++++++++-------------- board/aio.md | 77 ++++++++++++------------ board/gpio.md | 154 +++++++++++++++++++++++------------------------- board/i2c.md | 88 +++++++++++++-------------- board/pwm.md | 66 +++++++++++---------- board/spi.md | 85 +++++++++++++------------- board/uart.md | 79 ++++++++++++------------- board/webidl.md | 49 ++++++++++----- 8 files changed, 335 insertions(+), 339 deletions(-) diff --git a/board/README.md b/board/README.md index 296f0ec..108a400 100644 --- a/board/README.md +++ b/board/README.md @@ -57,7 +57,7 @@ Represents a hardware board. | [`name`](#name) | String | no | `undefined` | board name | | [`version`](#version) | String | no | `versions.board` in [`package.json`](../package.json) | API version | -| Method signature | Description | +| Method | Description | | --- | --- | | [`aio()`](#aio) | request an AIO object | | [`gpio()`](#gpio) | request a GPIO object | @@ -85,57 +85,43 @@ Board errors are represented as augmented [`Error`](https://nodejs.org/api/error #### `Board` methods -##### The `aio(options)` method -Configures an AIO pin. The method runs the following steps: -- Return a [`Promise`](../README.md/#promise) object `promise` and continue [in parallel](https://html.spec.whatwg.org/#in-parallel). -- If the AIO functionality is not supported, reject `promise` with `"NotSupportedError"`. -- Run the internal [`AIO initialization`](./aio.md/#init) algorithm with `options` as argument and let `aio` be the returned result. -- If it throws an error, reject promise with that error. -- Resolve `promise` with the `aio` object. +##### The `aio()` method +Provides the AIO API object. The method runs the following steps: +- If the AIO functionality is not supported on the board, throw `"NotSupportedError"`. +- Initialize AIO functionality on the board. If it fails, throw `"SystemError"`. +- Let `aio` be the [AIO API object](./aio.md/#apiobject). Return `aio`. -##### The `gpio(options)` method -Configures a GPIO pin or GPIO port. The method runs the following steps: -- Return a [`Promise`](../README.md/#promise) object `promise` and continue [in parallel](https://html.spec.whatwg.org/#in-parallel). -- If the GPIO functionality is not supported, reject `promise` with `"NotSupportedError"`. -- Run the internal [`GPIO initialization`](./gpio.md/#init) algorithm with `options` as argument and let `gpio` be the returned result. -- If it throws an error, reject promise with that error. -- Resolve `promise` with the `gpio` object. +##### The `gpio()` method +Provides the GPIO API object. The method runs the following steps: +- If the GPIO functionality is not supported on the board, throw `"NotSupportedError"`. +- Initialize GPIO functionality on the board. If it fails, throw `"SystemError"`. +- Let `gpio` be the [GPIO API object](./gpio.md/#apiobject). Return `gpio`. -##### The `pwm(options)` method -Configures a PWM pin. The method runs the following steps: -- Return a [`Promise`](../README.md/#promise) object `promise` and continue [in parallel](https://html.spec.whatwg.org/#in-parallel). -- If the PWM functionality is not supported, reject `promise` with `"NotSupportedError"`. -- Run the internal [`PWM initialization`](./pwm.md/#init) algorithm with `options` as argument and let `pwm` be the returned result. -- If it throws an error, reject promise with that error. -- Resolve `promise` with the `pwm` object. +##### The `pwm()` method +Provides the PWM API object. The method runs the following steps: +- If the PWM functionality is not supported on the board, throw `"NotSupportedError"`. +- Initialize PWM functionality on the board. If it fails, throw `"SystemError"`. +- Let `pwm` be the [PWM API object`](./pwm.md/#apiobject). Return `pwm`. -##### The `i2c(options)` method -Configures I2C communication. The method runs the following steps: -- Return a [`Promise`](../README.md/#promise) object `promise` and continue [in parallel](https://html.spec.whatwg.org/#in-parallel). -- If the I2C functionality is not supported, reject `promise` with `"NotSupportedError"`. -- Run the internal [`I2C initialization`](./i2c.md/#init) algorithm with `options` as argument and let `i2c` be the returned result. -- If it throws an error, reject promise with that error. -- Resolve `promise` with the `i2c` object. +##### The `i2c()` method +Provides the I2C API object. The method runs the following steps: +- If the I2C functionality is not supported on the board, throw `"NotSupportedError"`. +- Initialize I2C functionality on the board. If it fails, throw `"SystemError"`. +- Let `i2c` be the [I2C API Object](./i2c.md/#apiobject). Return `pwm`. -##### The `spi(options)` method -Configures SPI communication. -The method runs the following steps: -- Return a [`Promise`](../README.md/#promise) object `promise` and continue [in parallel](https://html.spec.whatwg.org/#in-parallel). -- If the SPI functionality is not supported, reject `promise` with `"NotSupportedError"`. -- Run the [`SPI init`](./spi.md/#init) steps with `options` as argument and let `spi` be the returned result. -- If it throws an error, reject promise with that error. -- Resolve `promise` with the `spi` object. +##### The `spi()` method +Provides the SPI API object. The method runs the following steps: +- If the SPI functionality is not supported on the board, throw `"NotSupportedError"`. +- Initialize SPI functionality on the board. If it fails, throw `"SystemError"`. +- Let `spi` be the [SPI API object](./spi.md/#apiobject). Return `spi`. -##### The `uart(options)` method -Configures UART communication. It takes a dictionary object as argument. -The method runs the following steps: -- Return a [`Promise`](../README.md/#promise) object `promise` and continue [in parallel](https://html.spec.whatwg.org/#in-parallel). -- If the UART functionality is not supported, reject `promise` with `"NotSupportedError"`. -- Run the [`UART init`](./uart.md/#init) steps with `options` as argument and let `uart` be the returned result. -- If it throws an error, reject promise with that error. -- Resolve `promise` with the `uart` object. +##### The `uart()` method +Provides the UART API object. The method runs the following steps: +- If the UART functionality is not supported on the board, throw `"NotSupportedError"`. +- Initialize UART functionality on the board. If it fails, throw `"SystemError"`. +- Let `uart` be the [UART API object](./uart.md/#apiobject) object. Return `uart`. diff --git a/board/aio.md b/board/aio.md index e9b6de5..8e6f677 100644 --- a/board/aio.md +++ b/board/aio.md @@ -3,22 +3,42 @@ AIO API The AIO API supports reading analog input pins that measure the analog voltage signal between 0 and a maximum voltage (usually 3.3 or 5 Volts), then do Analog-to-Digital Conversion (ADC) with a resolution of 10 or 12 bits on most boards, so that the result (pin value) is 0 to 1023 or 0 to 4095, inclusively. -On some boards access to AIO may be asynchronous. This API uses synchronous read. +On some boards access to AIO may be asynchronous. This API uses synchronous methods. -The API object --------------- -AIO functionality is exposed by the [`AIO`](#aio) object that can be obtained by using the [`aio()`](./README.md/#aio) method of the [`Board` API](./README.md/#board). See also the [Web IDL](./webidl.md). + +### The AIO API object +AIO functionality is exposed by an object that can be obtained by using the [`aio()`](./README.md/#aio) method of the [`Board` API](./README.md/#board). See also the [Web IDL](./webidl.md). The API object exposes the following method: + +| Method | Description | +| --- | --- | +| [`open()`](#open) | synchronous open | + + +#### The `AIO open(options)` method +Configures an AIO pin using data provided by the `options` argument. It involves the following steps: +- If `options` is a string, create a dictionary 'init' and use the value of `options` to initialize the `init.pin` property. +- Otherwise if `options` is a number, create a dictionary 'init' and use the value of `options` to initialize the `init.pin` property. +- Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`AIO`](#aio) properties, where at least `pin` MUST be specified: + * `pin` for board pin name with the valid values defined by the board, or for the numeric index of the analog pin; + * `precision` for the bit width of a sample (if the board supports setting the sampling rate). +- If any property of `init` is specified and has an invalid value on the given board, as defined by the board documentation, throw `TypeError`. +- Request the underlying platform to initialize AIO on `init.pin` (if defined) or otherwise `init.channel`. +- In case of failure, throw `InvalidAccessError`. +- Let `aio` be the `AIOPin`](#aiopin) object that represents the hardware pin identified by `init.pin`, as defined by the board documentation. +- If `init.precision` is defined, request the board to set the precision and initialize the `aio.precision` property with the value supported by the board. If there is an error, throw `InvalidAccessError`. +- Initialize the `aio.value` property with `undefined`. +- Return the `aio` object. ### The `AIO` interface -Represents the properties and methods that expose AIO functionality. The `AIO` object implements the [`EventEmitter`](../README.md/#events) interface, and extends the [`Pin`](./README.md/#pin) object. It has the following properties and methods: +The `AIO` object extends the [`Pin`](./README.md/#pin) object. | Property | Type | Optional | Default value | Represents | | --- | --- | --- | --- | --- | | `pin` | String or Number | no | `undefined` | board name for the pin | | `precision` | unsigned long | yes | `undefined` | bit length of digital sample | -| Method signature | Description | +| Method | Description | | --- | --- | | [`read()`](#read) | synchronous read | | [`close()`](#close) | close the pin | @@ -27,52 +47,33 @@ The `pin` property inherited from [`Pin`](./README.md/#pin) can take values defi The `precision` property represents the bit length of the digital sample. It is usually 10 or 12 bits, depending on board. - -#### AIO initialization -This internal algorithm is used by the [`Board.aio()`](./README.md/#aio) method. Configures the AIO pin provided by the `options` argument. It involves the following steps: -- If `options` is a string, create a dictionary 'init' and use the value of `options` to initialize the `init.pin` property. -- Otherwise if `options` is a number, create a dictionary 'init' and use the value of `options` to initialize the `init.pin` property. -- Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`AIO`](#aio) properties, where at least `pin` MUST be specified: - * `pin` for board pin name with the valid values defined by the board, or for the numeric index of the analog pin; - * `precision` for the bit width of a sample (if the board supports setting the sampling rate). -- If any property of `init` is specified and has an invalid value on the given board, as defined by the board documentation, throw `TypeError`. -- Request the underlying platform to initialize AIO on `init.pin` (if defined) or otherwise `init.channel`. -- In case of failure, throw `InvalidAccessError`. -- Let `aio` be the `AIO`](#aio) object that represents the hardware pin identified by `init.pin`, as defined by the board documentation. -- If `init.precision` is defined, request the board to set the precision and initialize the `aio.precision` property with the value supported by the board. If there is an error, throw `InvalidAccessError`. -- Initialize the `aio.value` property with `undefined`. -- Return the `aio` object. - #### The `unsigned long read()` method Performs a synchronous read operation for the pin value. It returns the pin value representing the last sampling. #### The `close()` method -Called when the application is no longer interested in the pin. Until the next [initialization](#init), invoking the `read()` method SHOULD throw `InvalidAccessError`. +Called when the application is no longer interested in the pin. Until the next [open()](#open) is called, invoking the `read()` method throws `InvalidAccessError`. ### Examples ```javascript -var board = require("board"); +try { + var aio = require("board").aio(); // initialize AIO on the board -// Configure AIO using the board -board.aio("A1").then(function(aio){ - // Read pin values. - console.log(board.name + " AIO pin 1 value: " + aio.read()); + var a1 = aio.open("A1"); + console.log(board.name + " AIO pin 1 value: " + a1.read()); + a1.close(); - // Release the pin. - aio.close(); -}); + var a4 = aio.open({pin: "A4", precision: 12 }); -board.aio({pin: "A4", precision: 12 }) -.then(function(aio){ // read 10 samples, one every second setTimeout(function() { - aio.close(); + a4.close(); }, 10500); + setInterval(function() { - console.log("AIO pin 4 value: " + aio.read()); + console.log("AIO pin 4 value: " + a4.read()); }, 1000); -}).catch(function(err) { - console.log("AIO error."); -}); +} catch (err) { + console.log("AIO error: " + err.message); +}; ``` diff --git a/board/gpio.md b/board/gpio.md index 821f03d..b8db6d5 100644 --- a/board/gpio.md +++ b/board/gpio.md @@ -3,17 +3,42 @@ GPIO API The GPIO (General Purpose Input & Output) API supports digital pins. -The API object --------------- -GPIO pin functionality is exposed by the [`GPIO`](#gpio) object that can be obtained by using the [gpio() method of the `Board` API](./README.md/#gpio). See also the [Web IDL](./webidl.md). - On certain boards GPIO pins may be grouped into ports (e.g. 8, 16 or 32 pins), read and written as registers by the controller. On certain boards, analog pins can also be used as GPIO. + +### The GPIO API object +GPIO pin functionality is exposed by an object that can be obtained by using the [`gpio()`](./README.md/#gpio) method of the [`Board` API](./README.md/#board). See also the [Web IDL](./webidl.md). The API object exposes the following method: + +| Method | Description | +| --- | --- | +| [`open()`](#open) | synchronous open | + + +#### The `GPIO open(options)` method +Configures a GPIO pin or port using data provided by the `options` argument. It involves the following steps: +- If `options` is a number or string, create a dictionary `init` and use the value of `options` to initialize the `init.pin` property. +- Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`GPIO`](#gpio) properties: + * `pin` for the GPIO pin or port name defined by the board + * `port` for the array of GPIO pins that define the port + * `mode` with valid values `"input"` or `"output"`, by default `"input"` + * `activeLow`, by default `false` + * `edge`, by default `"any"` + * `state`, by default `undefined`. +- If any of the `init` properties has an invalid value, throw `TypeError`. +- If `init.port` is defined and matches a GPIO port name defined by the board, run the following sub-steps: + * request the underlying platform to initialize the GPIO port on the given board with the `init` properties. In case of failure, throw `InvalidAccessError`. + * Let `gpio` be the [`GPIO`](#gpio) object representing the requested port initialized by `init`. +- Otherwise, if `init.pin` is defined, run the following sub-steps: + * Let `gpio` be the [`GPIO`](#gpio) object representing the requested pin initialized by `init`. For the [`GPIO`](#gpio) properties missing from the `init` dictionary, use the default values of the `GPIO` object properties. + * Initialize the `gpio.pin` property with `init.pin`. +- Return the `gpio` object. + + ### The `GPIO` interface -Represents the properties and methods that expose GPIO functionality. The `GPIO` object implements the [`EventEmitter`](../README.md/#events) interface, and extends the [`Pin`](./README.md/#pin) object. +The `GPIO` interface extends the [`Pin`](./README.md/#pin) object and implements the [`EventEmitter`](../README.md/#events) interface. It exposes the following properties and methods. | Property | Type | Optional | Default value | Represents | | --- | --- | --- | --- | --- | @@ -24,7 +49,7 @@ Represents the properties and methods that expose GPIO functionality. The `GPIO` | `edge` | string | yes | `"any"` | Interrupt generation mode | | `state` | string | yes | `undefined` | "pulldown", "pullup" | -| Method signature | Description | +| Method | Description | | --- | --- | | [`read()`](#read) | synchronous read | | [`write()`](#write) | synchronous write | @@ -48,26 +73,6 @@ The `edge` property is used for input pins and tells whether the `data` event is The `state` property tells if the internal pulldown (string value `"pulldown"`) or pullup (string value `"pullup"`) resistor is used for input pins to provide a default value (0 or 1) when the input is floating. The default value is `undefined`. - -#### GPIO initialization -This internal algorithm is used by the [`Board.gpio()`](./README.md/#gpio) method. Configures the GPIO pin or GPIO port provided by the `options` argument. -- If `options` is a number or string, create a dictionary `init` and use the value of `options` to initialize the `init.pin` property. -- Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`GPIO`](#gpio) properties: - * `pin` for the GPIO pin or port name defined by the board - * `port` for the array of GPIO pins that define the port - * `mode` with valid values `"input"` or `"output"`, by default `"input"` - * `activeLow`, by default `false` - * `edge`, by default `"any"` - * `state`, by default `undefined`. -- If any of the `init` properties has an invalid value, throw `TypeError`. -- If `init.port` is defined and matches a GPIO port name defined by the board, run the following sub-steps: - * request the underlying platform to initialize the GPIO port on the given board with the `init` properties. In case of failure, throw `InvalidAccessError`. - * Let `gpio` be the [`GPIO`](#gpio) object representing the requested port initialized by `init`. -- Otherwise, if `init.pin` is defined, run the following sub-steps: - * Let `gpio` be the [`GPIO`](#gpio) object representing the requested pin initialized by `init`. For the [`GPIO`](#gpio) properties missing from the `init` dictionary, use the default values of the `GPIO` object properties. - * Initialize the `gpio.pin` property with `init.pin`. -- Return the `gpio` object. - #### The `unsigned long read()` method Returns the value of the GPIO pin or port. @@ -78,68 +83,59 @@ If `value` is `0`, `null` or `undefined`, let `value` be 0. Otherwise, if `port` #### The `close()` method -Called when the application is no longer interested in the pin. This also removes all listeners to the `data` event. Until the next invocation of `init()`, invoking the `write()` method or reading the `value` property SHOULD throw `InvalidAccessError`. +Called when the application is no longer interested in the pin. This also removes all listeners to the `data` event. Until the next invocation of [`open()`](#open), invoking the `write()` method or reading the `value` property SHOULD throw `InvalidAccessError`. ### Examples #### Working with GPIO pins ```javascript -var board = require("board"); - -var gpio3 = board.gpio(3) // GPIO input pin with default configuration. - .then(function(gpio){ - console.log(board.name + " GPIO pin 3 value: " + gpio3.read()); - gpio3.close(); - }); - -board.gpio({ pin: 5, mode: "output", activeLow: true }) - .then(function(gpio) { - gpio.write(0); // activate pin - gpio.close(); - }); - -board.gpio({pin: 6, edge: "any"}) - .then(function(gpio) { - gpio.on("data", function(value) { - console.log("GPIO pin 6 has changed; value: " + value); - }; - - setTimeout(function(){ - gpio.close(); - }, 2000); - - }).catch (function(err) { - console.log("GPIO error."); - }); +try { + var gpio = require("board").gpio(); + + var gpio3 = gpio.open(3); // GPIO input pin with default configuration. + console.log(board.name + " GPIO pin 3 value: " + gpio3.read()); + gpio3.close(); + + var gpio5 = gpio.open({ pin: 5, mode: "output", activeLow: true }); + gpio5.write(0); // activate pin + gpio5.close(); + + gpio6 = gpio.open({pin: 6, edge: "any"}); + gpio6.on("data", function(value) { + console.log("GPIO pin 6 has changed; value: " + value); + }; + setTimeout(function(){ + gpio6.close(); + }, 2000); + +} catch (err) { + console.log("GPIO error: " + error.message); +}; ``` #### Working with GPIO ports ```javascript -var board = require("board"); - -// Configure a GPIO port using default configuration -board.gpio({ port: [3,4,5,6,7,8]}) - .then(function(gpio){ - // Set up a change listener on the port value. - gpio.on("data", function(value) { - console.log("GPIO port value has changed; value: " + gpio.read()); - }); - - setTimeout(function(){ - gpio.close(); - }, 2000); - - }); - -// Initialize and write an output port -board.gpio({ port: [5,6,7,8], mode: "output", activeLow: true }) -.then(function(gpio){ - gpio.write(0x21); - gpio.close(); -}).catch(function(error){ - console.log("GPIO error: " + error.message); -}); - +try { + var gpio = require("board").gpio(); + // Configure a GPIO port using default configuration + var gport1 = gpio.open({ port: [3,4,5,6,7,8]}); + + // Set up a change listener on the port value. + gport1.on("data", function(value) { + console.log("GPIO port value has changed; value: " + gport1.read()); + }); + + setTimeout(function(){ + gport1.close(); + }, 2000); + + // Initialize and write an output port + var gport2 = gpio.open({ port: [5,6,7,8], mode: "output", activeLow: true }); + gport2.write(0x21); + gport2.close(); +} catch (err) { + console.log("GPIO port error: " + error.message); +}; ``` diff --git a/board/i2c.md b/board/i2c.md index 23331b8..7d25400 100644 --- a/board/i2c.md +++ b/board/i2c.md @@ -11,9 +11,23 @@ If write was requested, the master puts the bit on SDA and sends a clock signal Therefore it is important to select the right speed supported by the master and slave devices. This API uses a [`Buffer`](../README.md/#buffer) object for both read and write. -The API object --------------- -I2C functionality is exposed by the [`I2C`](#i2c) object that can be obtained by using the [i2c() method of the `Board` API](./README.md/#i2c). See also the [Web IDL](./webidl.md). + +### The I2C API object +I2C functionality is exposed by an object that can be obtained by using the [`i2c()`](./README.md/#i2c) method of the [`Board` API](./README.md/#board). See also the [Web IDL](./webidl.md). The API object exposes the following method: + +| Method | Description | +| --- | --- | +| [`open()`](#open) | synchronous open | + + +#### The `I2C open(options)` method +Configures an I2C bus using data provided by the `options` argument. It runs the following steps: +- Let `i2c` be an `I2C`](#i2c) object. +- If `options` is a dictionary and the `options.bus` property is a number between 0 and 127, let `i2c.bus` be `options.bus`, otherwise select the platform default value, and if that is not available, set the value to 0. +- If `options.speed` is not a number, let `i2c.speed` be 10. Otherwise, if it is in the { 10, 100, 400, 1000, 3400 } set, let `i2c.speed` take that value, otherwise set `i2c.speed` to the closest matching value. +- Request the underlying platform to initialize the I2C `bus` with `i2c.speed` on `board`. +- In case of failure, throw `InvalidAccessError`. +- Return `i2c`. ### The `I2C` interface @@ -24,68 +38,48 @@ Represents the properties and methods that expose I2C functionality. | `bus` | octet | yes | platform selected | I2C bus | | `speed` | long | yes | platform selected | I2C bus speed | -| Method signature | Description | -| --- | --- | -| [`write(device, buffer)`](#write) | write data to a device | -| [`read(device, size)`](#read) | read data from a device | -| [`close()`](#close) | close the I2C bus | +| Method | Description | +| --- | --- | +| [`write()`](#write) | write data to a device | +| [`read()`](#read) | read data from a device | +| [`close()`](#close) | close the I2C bus | The `bus` property denotes the I2C bus number between 0 and 127. The `speed` property can take the following numeric values denoting kilobits per second: 10, 100, 400, 1000, 3400. - -#### I2C initialization -This internal algorithm is used by the [`Board.i2c()`](./README.md/#i2c) method. Configures the I2C bus and bus speed provided by the `options` (first) dictionary argument on the [`board`](./README.md/#board) specified by the `board` (second) argument. -- Let `i2c` be an `I2C`](#i2c) object. -- If `options` is a dictionary and the `options.bus` property is a number between 0 and 127, let `i2c.bus` be `options.bus`, otherwise select the platform default value, and if that is not available, set the value to 0. -- If `options.speed` is not a number, let `i2c.speed` be 10. Otherwise, if it is in the { 10, 100, 400, 1000, 3400 } set, let `i2c.speed` take that value, otherwise set `i2c.speed` to the closest matching value. -- Request the underlying platform to initialize the I2C `bus` with `i2c.speed` on `board`. -- In case of failure, return `null`. -- Return `i2c`. - #### The `write(device, buffer)` method Writes a [`Buffer`](../README.md/#buffer) using I2C to slave `device`. The method runs the following steps: -- Return a [`Promise`](../README.md/#promise) object `promise` and continue [in parallel](https://html.spec.whatwg.org/#in-parallel). -- If `device` is not a number between 0 and 127, reject `promise` with `TypeError` and terminate these steps. -- Create a [`Buffer`](../README.md/#buffer) from `buffer`. If that fails, reject `promise` with `TypeError` and terminate these steps. -- Request the underlying platform to write the specified bytes to the specified device. -If the operation fails, reject `promise`. -- Otherwise, resolve `promise`. +- If `device` is not a number between 0 and 127, throw `TypeError` and terminate these steps. +- Request the underlying platform to write the bytes specified by `buffer` argument to the specified device. If the operation fails, throw `SystemError`. #### The `read(device, size)` method -Reads maximum `size` number of bytes from I2C device `device` and resolves with a [`Buffer`](../README.md/#buffer). The method runs the following steps: -- Return a [`Promise`](../README.md/#promise) object `promise` and continue [in parallel](https://html.spec.whatwg.org/#in-parallel). -- If `device` is not a number between 0 and 127, reject `promise` with `TypeError` and terminate these steps. -- Create a [`Buffer`](../README.md/#buffer) from `buffer`. -- Request the underlying platform to read `size` number of bytes from the specified `device` into `buffer`. -If the operation fails, reject `promise`. -- Otherwise, resolve `promise` with `buffer`. +Reads maximum `size` number of bytes from I2C device `device` and returs a [`Buffer`](../README.md/#buffer). The method runs the following steps: +- If `device` is not a number between 0 and 127, throw `TypeError` and terminate these steps. +- Allocate a [`Buffer`](../README.md/#buffer). +- Request the underlying platform to read `size` number of bytes from the specified `device` into `buffer`. If the operation fails, throw `SystemError`. +- Return `buffer`. #### The `close()` method -Closes the current [`I2C`](#i2c) bus and interrupts all pending operations. +Closes the current [`I2C`](#i2c) bus and cancels all pending operations. ### Examples ```javascript try { - var board = require("board"); - var i2c = null; - - board.i2c().then(function(iic) { - i2c = iic; - console.log("I2C bus " + i2c.bus + " opened with bus speed " + i2c.speed); - return i2c.write(0x02, [1, 2, 3]); - }).then(function() { - return i2c.read(0x03, 3); - }).then(function(buffer) { - console.log("From I2C device 0x03: " + buffer.toString()); - i2c.close(); - }).catch(function(err) { - console.log("I2C error: " + err.message); - }); + var i2c = require("board").i2c().open(); + console.log("I2C bus " + i2c.bus + " opened with bus speed " + i2c.speed); + + i2c.write(0x02, [1, 2, 3]); + + var buffer = i2c.read(0x03, 3); + console.log("From I2C device 0x03: " + buffer.toString()); + + i2c.close(); +} catch (err) { + console.log("I2C error: " + err.message); } ``` diff --git a/board/pwm.md b/board/pwm.md index 26b7052..f271ad3 100644 --- a/board/pwm.md +++ b/board/pwm.md @@ -8,9 +8,26 @@ For instance, a LED that is driven with a PWM signal with 50% duty cycle will be The term "channel" is used as the numeric index of a PWM pin relative to the PWM controller, as described in the board documentation. -The API object --------------- -PWM functionality is exposed by the [`PWM`](#pwm) object that can be obtained by using the [pwm() method of the `Board` API](./README.md/#pwm). See also the [Web IDL](./webidl.md). + +### The PWM API object +PWM functionality is exposed by an object that can be obtained by using the [`pwm()`](./README.md/#pwm) method of the [`Board` API](./README.md/#board). See also the [Web IDL](./webidl.md). The API object exposes the following method: + +| Method | Description | +| --- | --- | +| [`open()`](#open) | synchronous open | + + +#### The `PWM open(options)` method +Configures a PWM pin using data provided by the `options` argument. It runs the following steps: +- If `options` is a string or number, create a dictionary `init` and use the value of `options` to initialize the `init.pin` property. +- Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`PWM`](#pwm) properties, but at least `pin` + * `pin` for board pin name, or PWM channel number, as defined by the board documentation + * `reversePolarity`, with a default value `false`. +- If any of the `init` properties is specified, but has invalid value on the board, throw `InvalidAccessError`. +- Let `pwm` be the [`PWM`](#pwm) object representing the pin identified by the `init.pin` and request the underlying platform to initialize PWM for the given pin. In case of failure, throw `InvalidAccessError`. +- Initialize the `pwm.pin` property with `init.pin`. +- Initialize the `pwm.reversePolarity` property with `init.reversePolarity`. +- Return the `pwm` object. ### The `PWM` interface @@ -24,9 +41,9 @@ Represents the properties and methods that expose PWM functionality. The `PWM` o | `stop()` | function | no | defined by implementation | stop the PWM signal | | `close()` | function | no | defined by implementation | release the pin | -| Method signature | Description | +| Method | Description | | --- | --- | -| [`write(value)`](#write) | set and start a PWM signal | +| [`write()`](#write) | set and start a PWM signal | | [`stop()`](#stop) | stop the PWM signal | | [`close()`](#close) | close the pin | @@ -34,19 +51,6 @@ The `pin` property inherited from [`Pin`](./README.md/#pin) can take values defi The `reversePolarity` property tells whether the PWM signal is active on 0. The default value is `false`. - -#### PWM initialization -This internal algorithm is used by the [`Board.pwm()`](./README.md/#pwm) method. Configures the PWM pin provided by the `options` argument. It runs the following steps: -- If `options` is a string or number, create a dictionary `init` and use the value of `options` to initialize the `init.pin` property. -- Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`PWM`](#pwm) properties, but at least `pin` - * `pin` for board pin name, or PWM channel number, as defined by the board documentation - * `reversePolarity`, with a default value `false`. -- If any of the `init` properties is specified, but has invalid value on the board, throw `InvalidAccessError`. -- Let `pwm` be the [`PWM`](#pwm) object representing the pin identified by the `init.pin` and request the underlying platform to initialize PWM for the given pin. In case of failure, throw `InvalidAccessError`. -- Initialize the `pwm.pin` property with `init.pin`. -- Initialize the `pwm.reversePolarity` property with `init.reversePolarity`. -- Return the `pwm` object. - #### The `write(value)` method Performs a synchronous write operation to define and enable the PWM signal. The argument `value` MUST be a dictionary defined here. @@ -78,18 +82,18 @@ Called when the application is no longer interested in the pin. It invokes the ` ### Examples ```javascript -var board = require("board"); - -board.pwm(6) // configure pin 6 as PWM - .then(function(pwm){ - pwm.write({ period: 2.5, pulseWidth: 1.5 }); // duty cycle is 60% - console.log("PWM duty cycle: " + pwm.dutyCycle); - setTimeout(function(){ - pwm.stop(); // stop the PWM signal - pwm.close(); - }, 2000); - }).catch(function(error) { - console.log("PWM error: " + error.message); - }); +try { + var pwm = require("board").pwm(); + + var pwm6 = pwm.open(6); // configure pin 6 as PWM + pwm6.write({ period: 2.5, pulseWidth: 1.5 }); // duty cycle is 60% + console.log("PWM duty cycle: " + pwm6.dutyCycle); + setTimeout(function(){ + pwm6.stop(); // stop the PWM signal + pwm6.close(); + }, 2000); +}.catch (error) { + console.log("PWM error: " + error.message); +}; ``` diff --git a/board/spi.md b/board/spi.md index f99a868..ee16d4a 100644 --- a/board/spi.md +++ b/board/spi.md @@ -11,9 +11,29 @@ Since the SS pins may be connected to slave chip select through a demultiplexer This API uses a [`Buffer`](../README.md/#buffer) object for both read and write data. -The API object --------------- -SPI functionality is exposed by the [`SPI`](#spi) object that can be obtained by using the [spi() method of the `Board` API](./README.md/#spi). See also the [Web IDL](./webidl.md). + +### The SPI API object +SPI functionality is exposed by an object that can be obtained by using the [`spi()`](./README.md/#spi) method of the [`Board` API](./README.md/#board). See also the [Web IDL](./webidl.md). The API object exposes the following method: + +| Method | Description | +| --- | --- | +| [`open()`](#open) | synchronous open | + + +#### The `SPI open(options)` method +Configures an SPI bus using data provided by the `options` argument. It runs the following steps: +- Let `spi` be an [`SPI`](#spi) object. +- If `options` is a dictionary and the `options.bus` property is a number between 0 and 127, let `spi.bus` be `options.bus`, otherwise select the platform default value, and if that is not available, set the value to 0. +- If `options.speed` is not a number, let `spi.speed` be 10. Otherwise, set `spi.speed` to the closest matching value that is lower than `options.speed` and is supported by the platform. +- If `options.msbFirst` is `false`, set `spi.msbFirst` to `false`, otherwise set it to `true`. +- If `options.bits` is in the set {1, 2, 4, 8, 16 }, then set `spi.bits` to `option.bits`, otherwise set it to the value 4. +- If `options.polarity` is 0, then set `spi.polarity` to 0, otherwise set `spi.polarity` to 2. +- If `options.phase` is 0, then set `spi.phase` to 0, otherwise set `spi.phase` to 1. +- Request the underlying platform to initialize the SPI `spi.bus` with `spi.speed` on the board. The implementation will use the board mapping from the value of `bus` to the set of physical pins used for the bus. +- In case of failure in any of the steps above, return `null`. +- Set `spi.frameGap` to 0. Request the underlying platform to provide the SPI inter-frame delay value expressed in nanoseconds and if the request successfully completes, then set `spi.frameGap` to that value. +- Set `spi.topology` to `"full-duplex"`. Request the underlying platform to provide the SPI transfer mode and if the request successfully completes, then set `spi.topology` to the corresponding value. +- Return `spi`. ### The `SPI` interface @@ -64,58 +84,35 @@ The `topology` property describes the SPI master-slave connection type. This val - `"multiplexed"`: 4 SS lines are connected to a decoder that can activate up to 15 slave devices. This works as full-duplex. - `"daisy-chain"`: the master uses one SS and one SCLK (clock) line for all slaves. The MOSI line from the master goes to the first slave's MOSI pin, the MISO line of that slave goes to the MOSI pin of the next slave, and so forth. The last slave's MISO line is connected to the master's MISO pin. - -#### SPI initialization -This internal algorithm is used by the [`Board.spi()`](./README.md/#spi) method. It configures the SPI bus and bus speed provided by the `options` dictionary argument. -- Let `spi` be an [`SPI`](#spi) object. -- If `options` is a dictionary and the `options.bus` property is a number between 0 and 127, let `spi.bus` be `options.bus`, otherwise select the platform default value, and if that is not available, set the value to 0. -- If `options.speed` is not a number, let `spi.speed` be 10. Otherwise, set `spi.speed` to the closest matching value that is lower than `options.speed` and is supported by the platform. -- If `options.msbFirst` is `false`, set `spi.msbFirst` to `false`, otherwise set it to `true`. -- If `options.bits` is in the set {1, 2, 4, 8, 16 }, then set `spi.bits` to `option.bits`, otherwise set it to the value 4. -- If `options.polarity` is 0, then set `spi.polarity` to 0, otherwise set `spi.polarity` to 2. -- If `options.phase` is 0, then set `spi.phase` to 0, otherwise set `spi.phase` to 1. -- Request the underlying platform to initialize the SPI `spi.bus` with `spi.speed` on the board. The implementation will use the board mapping from the value of `bus` to the set of physical pins used for the bus. -- In case of failure in any of the steps above, return `null`. -- Set `spi.frameGap` to 0. Request the underlying platform to provide the SPI inter-frame delay value expressed in nanoseconds and if the request successfully completes, then set `spi.frameGap` to that value. -- Set `spi.topology` to `"full-duplex"`. Request the underlying platform to provide the SPI transfer mode and if the request successfully completes, then set `spi.topology` to the corresponding value. -- Return `spi`. - #### The `transceive(device, buffer)` method Writes a [`Buffer`](../README.md/#buffer) `buffer` using SPI to the slave identified by the `device` argument, and reads another [`Buffer`](../README.md/#buffer) from the slave device that is returned. The method runs the following steps: -- Return a [`Promise`](../README.md/#promise) object `promise` and continue [in parallel](https://html.spec.whatwg.org/#in-parallel). -- If `device` is not a number between 0 and 127, reject `promise` with `TypeError` and terminate these steps. -- Create a [`Buffer`](../README.md/#buffer) from `buffer` (may be empty). If that fails, reject `promise` with `TypeError` and terminate these steps. -- Request the underlying platform to write the specified `buffer` to the specified device and read another [`Buffer`](../README.md/#buffer) `readBuffer`. The implementation maps the value of `device` to the physical SS (slave select) pins on the board. -If the operation fails, reject `promise`. -- Otherwise, resolve `promise` with `readBuffer`. +- If `device` is not a number between 0 and 127, Throw `TypeError` and terminate these steps. +- Request the underlying platform to write the bytes specified in `buffer` to the specified device and read another [`Buffer`](../README.md/#buffer) `readBuffer`. The implementation maps the value of `device` to the physical SS (slave select) pins on the board. If the operation fails, throw `SystemError` and abort these steps. +- Return `readBuffer`. #### The `close()` method -Closes the current [`SPI`](#spi) bus and interrupts all pending operations. +Closes the current [`SPI`](#spi) bus and cancels all pending operations. ### Examples ```javascript try { - var board = require("board"); - - board.spi().then(function(spi) { - console.log("SPI bus " + spi.bus + " opened with bus speed " + spi.speed); - console.log("SPI mode: " + spi.mode); - console.log("Data bits: " + spi.bits); - console.log("Speed [MHz]: " + spi.speed); - console.log("MSB first: " + (spi.msbFirst ? "true" : "false")); - - spi.transceive(0, [1, 2, 3]).then(function(buffer) { - // Buffer object - console.log("From SPI device 0: " + buffer.toString()); - spi.close(); - }); - }); - }).catch(function(err) { - console.log("SPI error: " + err.message); - }); + var spi = require("board").spi().open(); + + console.log("SPI bus " + spi.bus + " opened with bus speed " + spi.speed); + console.log("SPI mode: " + spi.mode); + console.log("Data bits: " + spi.bits); + console.log("Speed [MHz]: " + spi.speed); + console.log("MSB first: " + (spi.msbFirst ? "true" : "false")); + + var buffer = spi.transceive(0, [1, 2, 3]); + console.log("From SPI device 0: " + buffer.toString()); + + spi.close(); +} catch (err) { + console.log("SPI error: " + err.message); } ``` diff --git a/board/uart.md b/board/uart.md index 20fb8f4..982eb92 100644 --- a/board/uart.md +++ b/board/uart.md @@ -4,17 +4,31 @@ UART API The UART API supports the Universal Asynchronous Receiver/Transmitter that allows the board to communicate with other external devices. It uses 2 pins, RX for receiving and TX for transmitting. UART ports are usually referred by string names, but numbers may also be accepted, as defined in the board documentation. This API uses a [`Buffer`](../README.md/#buffer) object for both read and write. -The API object --------------- -UART functionality is exposed by the [`UART`](#uart) object that can be obtained by using the [uart() method of the `Board` API](./README.md/#uart). See also the [Web IDL](./webidl.md). + +### The UART API object +UART functionality is exposed by an object that can be obtained by using the [`uart()`](./README.md/#uart) method of the [`Board` API](./README.md/#board). See also the [Web IDL](./webidl.md). The API object exposes the following method: + +| Method | Description | +| --- | --- | +| [`open()`](#open) | synchronous open | + + +#### The `UART open(options)` method +Configures an UART port using data provided by the `options` argument. It runs the following steps: +- Let `uart` be an [`UART`](#uart) object. +- For all `uart` properties, if the `options` dictionary defines the same property with a valid value, let the `uart` property take that value, otherwise the default value. +- Request the underlying platform to initialize the UART with the parameters provided by `uart`. +- In case of failure, throw `SystemError` and abort these steps. +- Invoke the `uart.setReadRange(min, max)` method with `min` = 1, and `max` taking a value determined by the platform that is greater than or equal to 1. +- Return `uart`. ### The `UART` interface -Represents the properties and methods that expose UART functionality. The `UART` interface implements the [`EventEmitter`](../README.md/#events) interface and exposes one event. +Represents the properties, methods and event that expose UART functionality. The `UART` interface implements the [`EventEmitter`](../README.md/#events) interface. | Event name | Event callback argument | | -------------- | ----------------------- | -| `data` | [`Buffer`](../README.md/#buffer) | +| `read` | [`Buffer`](../README.md/#buffer) | | Property | Type | Optional | Default value | Represents | | --- | --- | --- | --- | --- | @@ -25,10 +39,10 @@ Represents the properties and methods that expose UART functionality. The `UART` | `parity` | enum | yes | `'none'` | `'none'`, `'even'`, `'odd'` | | `flowControl` | boolean | yes | `false` | if flow control is on | -| Method signature | Description | +| Method | Description | | --- | --- | -| [`write(buffer)`](#write) | write a buffer | -| [`setReadRange(min, max)`](#readrange) | set buffer sizes for read notifications | +| [`write()`](#write) | write a buffer | +| [`setReadRange()`](#readrange) | set buffer sizes for read notifications | | [`close()`](#close) | close the UART port | The `port` property denotes the UART port as a string defined by the board documentation, such as `"tty0"`, `"serialUSB0"`, etc. @@ -43,29 +57,14 @@ The `parity` property can take the following values: `"none"` (by default), `"ev The `flowControl` boolean property denotes if flow control is used. By default it is `false`. - -#### UART initialization -This internal algorithm is used by the [`Board.uart()`](./README.md/#uart) method. Configures UART with the `options` dictionary argument. -- If `options.port` is not a string, return `null`. -- Let `uart` be an [`UART`](#uart) object. -- For all `uart` properties, if the `options` dictionary defines the same property with a valid value, let the `uart` property take that value, otherwise the default value. -- Request the underlying platform to initialize the UART with the parameters provided by `uart`. -- In case of failure, return `null`. -- Invoke the `uart.setReadRange(min, max)` method with `min` = 1, and `max` taking a value determined by the platform that is greater than or equal to 1. -- Return `uart`. - #### The `write(buffer)` method Transmits a [`Buffer`](../README.md/#buffer) using UART. The method runs the following steps: -- Return a [`Promise`](../README.md/#promise) object `promise` and continue [in parallel](https://html.spec.whatwg.org/#in-parallel). -- Create a [`Buffer`](../README.md/#buffer) from `buffer`. If that fails, reject `promise` with `TypeError` and terminate these steps. -- Request the underlying platform to send the specified bytes. -If the operation fails, reject `promise`. -- Otherwise, resolve `promise`. +- Request the underlying platform to send the bytes specified in `buffer`. If the operation fails, throw `SystemError` and abort these steps. #### The `setReadRange(min, max)` method -Sets the minimum and maximum number of bytes for triggering the `onread` event. Whenever at least `min` number of bytes is available, a [`Buffer`](../README.md/#buffer) object containing a `max` number of bytes is sent with the `onread` event. +Sets the minimum and maximum number of bytes for triggering the `onread` event. Whenever at least `min` number of bytes is available, the `read` event is fired with a [`Buffer`](../README.md/#buffer) containing at maximum `max` number of bytes. #### The `close()` method @@ -75,26 +74,24 @@ Closes the current [`UART`](#uart) port and interrupts all pending operations. ```javascript try { - var board = require("board"); + var uart = require("board").uart("serialUSB0"); - board.uart("serialUSB0").then(function(uart) { - console.log("UART port " + uart.port); - console.log("Speed [bps]: " + uart.speed); - console.log("Data bits: " + uart.dataBits); - console.log("Stop bits: " + uart.stopBits); - console.log("Parity: " + uart.parity); - console.log("Flow control " + (uart.flowControl ? "on." : "off."); + console.log("UART port " + uart.port); + console.log("Speed [bps]: " + uart.speed); + console.log("Data bits: " + uart.dataBits); + console.log("Stop bits: " + uart.stopBits); + console.log("Parity: " + uart.parity); + console.log("Flow control " + (uart.flowControl ? "on." : "off."); - uart.setReadRange(8, 16); // min 8 byes, max 16 bytes in one read event + uart.setReadRange(8, 16); // min 8 byes, max 16 bytes in one read event - uart.on("read", function(buffer) { - console.log("UART received: " + buffer.toString()); - }); + uart.on("read", function(buffer) { + console.log("UART received: " + buffer.toString()); + }); - uart.write([1, 2, 3]); + uart.write([1, 2, 3]); - }).catch(function(err) { - console.log("UART error: " + err.message); - }); +} catch(err) { + console.log("UART error: " + err.message); } ``` diff --git a/board/webidl.md b/board/webidl.md index 682e133..e591f00 100644 --- a/board/webidl.md +++ b/board/webidl.md @@ -6,12 +6,12 @@ interface Board { readonly attribute String name; // board name, e.g. "arduino101" attribute EventHandler onerror; - Promise aio(PinName pin); - Promise gpio(PinName or GPIOOptions options); - Promise pwm( (PinName or PWMOptions) options); - Promise i2c(I2COptions options); - Promise spi(SPIOptions options); - Promise uart(UARTOptions options); + AIO aio(); + GPIO gpio(); + PWM pwm(); + I2C i2c(); + SPI spi(); + UART uart(); }; Board implements EventEmitter; @@ -25,6 +25,9 @@ interface Pin { }; // AIO +interface AIOObject { + AIO open((PinName or AIOOptions) options); +}; dictionary AIOOptions { PinName pin; @@ -39,9 +42,11 @@ interface AIO: Pin { void close(); }; -AIO implements EventEmitter; - // GPIO +interface GPIOObject { + GPIO open((PinName or GPIOOptions) options); +}; + enum GPIOMode { "input", "output" }; enum GPIOEdge { "none", "rising", "falling", "any" }; enum GPIOState { "pull-up", "pull-down", "high-impedance" }; @@ -56,16 +61,21 @@ dictionary GPIOOptions { }; [NoInterfaceObject] -interface GPIO: Pin { +interface GPIO { + PinName pin; unsigned long read(); void write(long value); void close(); attribute EventHandler ondata; }; -GPIO implements EventEmitter; +GPIOAccess implements EventEmitter; // PWM +interface PWMObject { + PWM open((PinName or PWMOptions) options); +}; + dictionary PWMOptions { PinName pin; boolean reversePolarity = false; @@ -83,6 +93,10 @@ interface PWM: Pin { }; // I2C +interface I2CObject { + I2C open(I2COptions options); +}; + dictionary I2COptions { octet bus; unsigned long speed; // 10, 100, 400, 1000, 3400 kbps @@ -93,12 +107,15 @@ interface I2C { readonly attribute octet bus; readonly attribute unsigned long speed; - Promise read(octet device, unsigned long size); - Promise write(octet device, Buffer data); + Buffer read(octet device, unsigned long size); + void write(octet device, Buffer data); void close(); }; // SPI +interface SPIObject { + SPI open(SPIOptions options); +}; enum SPITopology { "full-duplex", "single-write", "single-read", "daisy-chain" }; @@ -116,11 +133,15 @@ dictionary SPIOptions { [NoInterfaceObject] interface SPI { // has all the properties of SPIOptions as read-only attributes - Promise transfer(octet device, Buffer txData); + Buffer transfer(octet device, Buffer txData); void close(); }; // UART +interface UARTObject { + UART open(UARTOptions options); +}; + enum UARTParity { "none", "even", "odd" }; dictionary UARTOptions { @@ -135,7 +156,7 @@ dictionary UARTOptions { [NoInterfaceObject] interface UART { // has all the properties of UARTInit as read-only attributes - Promise write(Buffer data); + void write(Buffer data); void setReadRange(long minBytes, long maxBytes); attribute EventHandler ondata; void close(); From 2f089ab5b230f61ed5bf0933f9d29e6a634377fc Mon Sep 17 00:00:00 2001 From: Geoff Gustafson Date: Tue, 2 May 2017 07:03:12 -0700 Subject: [PATCH 2/8] [gpio] Fix bugs in GPIO sample code Signed-off-by: Geoff Gustafson --- board/gpio.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/board/gpio.md b/board/gpio.md index b8db6d5..4d06f88 100644 --- a/board/gpio.md +++ b/board/gpio.md @@ -104,13 +104,13 @@ try { gpio6 = gpio.open({pin: 6, edge: "any"}); gpio6.on("data", function(value) { console.log("GPIO pin 6 has changed; value: " + value); - }; + }); setTimeout(function(){ gpio6.close(); }, 2000); } catch (err) { - console.log("GPIO error: " + error.message); + console.log("GPIO error: " + err.message); }; ``` From 703b8771a1221ca1f3117851e1f7546c3988ae35 Mon Sep 17 00:00:00 2001 From: Zoltan Kis Date: Wed, 3 May 2017 17:40:12 +0300 Subject: [PATCH 3/8] Board: split into smaller modules, support pin namespaces for OS and board Signed-off-by: Zoltan Kis --- board/README.md | 106 +++++++++----------------------------------- board/aio.md | 38 +++++++++------- board/arduino101.md | 2 +- board/frdm_k64f.md | 2 + board/gpio.md | 71 ++++++++++++++++++++--------- board/i2c.md | 9 +++- board/pwm.md | 33 +++++++++----- board/spi.md | 9 +++- board/uart.md | 9 +++- board/webidl.md | 90 ++++++++++++++++++++----------------- 10 files changed, 187 insertions(+), 182 deletions(-) diff --git a/board/README.md b/board/README.md index 108a400..f775426 100644 --- a/board/README.md +++ b/board/README.md @@ -9,119 +9,57 @@ The [Board](#board) API provides low level interfaces for I/O operations: - [SPI - Serial Peripheral Interface](./spi.md) - [UART - Universal Asynchronous Receiver/Transmitter](./uart.md). -This API uses board pin names as defined in the corresponding board documentation. -The names, values and semantics related to hardware pins are owned and encapsulated by the implementation. This API uses opaque values (strings and numbers) for [`Pin`](#pin) names. +Hardware pin names are usually marked on the circuit boards. However, operating systems, such as [Zephyr](https://www.zephyrproject.org/doc/) define a pin name mapping that is consistent across the boards supported by the OS. This API supports both board and OS defined namespaces. In this API, [`Pin`](#pin) names are opaque to the application. Applications can open a given pin with a pin name that is either a string or a number, in either board or OS namespace. Implementations encapsulate the pin mapping. Also, the API exposes board name, OS name (including OS version) and API version for all board APIs. -The supported board documentations are listed in [this directory](./): +The supported board namespaces are listed in [this directory](./): - [arduino101.md](./arduino101.md) - [frdm_k64f.md](./frdm_k64f.md). -The full Web IDL definition for Board and IO APIs can be found [here](./webidl.md). +For the supported OS pin namespace, consult the documentation of the implementation and its underlying OS documentation. + +The full Web IDL definition for Board and IO APIs can be found in [webidl.md](./webidl.md). The `Board` API object ---------------------- -The API entry point is a [`Board`](./#board) object that is exposed in a platform-specific manner. As an example, on Node.js it can be obtained by requiring the package that implements this API. +The API entry point is a [`Board`](#board) object provided by an implementation (module). +When requiring `"board"`, the following steps are run: +- If there is no permission for using the functionality, throw `SecurityError`. +- If the [Board](#board) functionality is not supported on the board, throw `"NotSupportedError"`. +- Let `board` be the Board API object, and initialize it by fetching board name and OS name. Return `board`. -In the following example, the application requires an implementation that exposed Arduino 101 values and semantics for pins. ```javascript var board = require("board"); -console.log("Connected to board: " + board.name); +console.log("Connected to board: " + board.name + " running " + board.os); ``` -On other platforms, e.g. in browsers, the API entry point can be exposed on another object, or constructed. -```javascript -var board = new Board(); // provides an instance of the default board -``` - -If the functionality is not supported by the platform, `require` should throw `NotSupportedError`. If there is no permission for using the functionality, `require` should throw `SecurityError`. - - -### The `Pin` interface -Represents a hardware pin on the board. - -| Property | Type | Optional | Default value | Represents | -| --- | --- | --- | --- | --- | -| `pin` | String or Number | no | `undefined` | board name for the pin | - -The read-only `pin` property is the board-specific name or numeric value of a pin, as defined in the board documentation. - -In future versions of the API the `Pin` object may be extended. +If the functionality is not supported by the platform, `require` should throw `NotSupportedError`. ### The `Board` interface -Represents a hardware board. +Represents a hardware circuit board such as Arduino 101. | Property | Type | Optional | Default value | Represents | | --- | --- | --- | --- | --- | -| [`name`](#name) | String | no | `undefined` | board name | -| [`version`](#version) | String | no | `versions.board` in [`package.json`](../package.json) | API version | - -| Method | Description | -| --- | --- | -| [`aio()`](#aio) | request an AIO object | -| [`gpio()`](#gpio) | request a GPIO object | -| [`pwm()`](#pwm) | request a PWM object | -| [`i2c()`](#i2c) | request an I2C object | -| [`spi()`](#spi) | request an SPI object | -| [`uart()`](#uart) | request an UART object | +| [`name`](#boardname) | String | no | `undefined` | board name | +| [`os`](#osname) | String | no | `undefined` | OS name | +| [`apiVersion`](#apiversion) | String | no | `versions.board` in [`package.json`](../package.json) | API version | | Event name | Event callback argument | | -------------- | ----------------------- | | `error` | [`Error`](#error) object | - + The `name` property is read-only, and provides the board name. - -The `version` property is read-only, and provides the provides the Board API version, as specified in the `versions.board` property of [`package.json`](../package.json). + +The `os` property is read-only, and provides the underlying operating system name. + + +The `apiVersion` property is read-only, and provides the provides the Board API version, as specified in the `versions.board` property of [`package.json`](../package.json). Board errors are represented as augmented [`Error`](https://nodejs.org/api/errors.html#errors_class_error) objects. The following [`Error` names](https://nodejs.org/api/errors.html) are used for signaling issues: - `BoardDisconnectError` - `BoardTimeoutError` - `BoardIOError`. - -#### `Board` methods - - -##### The `aio()` method -Provides the AIO API object. The method runs the following steps: -- If the AIO functionality is not supported on the board, throw `"NotSupportedError"`. -- Initialize AIO functionality on the board. If it fails, throw `"SystemError"`. -- Let `aio` be the [AIO API object](./aio.md/#apiobject). Return `aio`. - - -##### The `gpio()` method -Provides the GPIO API object. The method runs the following steps: -- If the GPIO functionality is not supported on the board, throw `"NotSupportedError"`. -- Initialize GPIO functionality on the board. If it fails, throw `"SystemError"`. -- Let `gpio` be the [GPIO API object](./gpio.md/#apiobject). Return `gpio`. - - -##### The `pwm()` method -Provides the PWM API object. The method runs the following steps: -- If the PWM functionality is not supported on the board, throw `"NotSupportedError"`. -- Initialize PWM functionality on the board. If it fails, throw `"SystemError"`. -- Let `pwm` be the [PWM API object`](./pwm.md/#apiobject). Return `pwm`. - - -##### The `i2c()` method -Provides the I2C API object. The method runs the following steps: -- If the I2C functionality is not supported on the board, throw `"NotSupportedError"`. -- Initialize I2C functionality on the board. If it fails, throw `"SystemError"`. -- Let `i2c` be the [I2C API Object](./i2c.md/#apiobject). Return `pwm`. - - -##### The `spi()` method -Provides the SPI API object. The method runs the following steps: -- If the SPI functionality is not supported on the board, throw `"NotSupportedError"`. -- Initialize SPI functionality on the board. If it fails, throw `"SystemError"`. -- Let `spi` be the [SPI API object](./spi.md/#apiobject). Return `spi`. - - -##### The `uart()` method -Provides the UART API object. The method runs the following steps: -- If the UART functionality is not supported on the board, throw `"NotSupportedError"`. -- Initialize UART functionality on the board. If it fails, throw `"SystemError"`. -- Let `uart` be the [UART API object](./uart.md/#apiobject) object. Return `uart`. diff --git a/board/aio.md b/board/aio.md index 8e6f677..afa08b7 100644 --- a/board/aio.md +++ b/board/aio.md @@ -3,39 +3,44 @@ AIO API The AIO API supports reading analog input pins that measure the analog voltage signal between 0 and a maximum voltage (usually 3.3 or 5 Volts), then do Analog-to-Digital Conversion (ADC) with a resolution of 10 or 12 bits on most boards, so that the result (pin value) is 0 to 1023 or 0 to 4095, inclusively. -On some boards access to AIO may be asynchronous. This API uses synchronous methods. +On some boards access to AIO may be asynchronous. This API uses synchronous methods for allowing lean implementations. ### The AIO API object -AIO functionality is exposed by an object that can be obtained by using the [`aio()`](./README.md/#aio) method of the [`Board` API](./README.md/#board). See also the [Web IDL](./webidl.md). The API object exposes the following method: +When requiring `"aio"`, the following steps are run: +- If there is no permission for using the functionality, throw `SecurityError`. +- If the AIO functionality is not supported on the board, throw `"NotSupportedError"`. +- Return an object that implements the following method. | Method | Description | | --- | --- | -| [`open()`](#open) | synchronous open | +| [`open()`](#open) | open an AIO pin | + +See also the [Web IDL](./webidl.md) definition. #### The `AIO open(options)` method Configures an AIO pin using data provided by the `options` argument. It involves the following steps: - If `options` is a string, create a dictionary 'init' and use the value of `options` to initialize the `init.pin` property. -- Otherwise if `options` is a number, create a dictionary 'init' and use the value of `options` to initialize the `init.pin` property. -- Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`AIO`](#aio) properties, where at least `pin` MUST be specified: - * `pin` for board pin name with the valid values defined by the board, or for the numeric index of the analog pin; +- Otherwise if `options` is a number, create a dictionary 'init' and let `init.name` be `options`. +- Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`AIO`](#aio) properties, where at least `name` MUST be specified: + * `name` for board pin name with the valid values defined by the board, or for the numeric index of the analog pin; + * `mapping` to specify if OS or board namespace is to be used with the pin (by default `"os"`). * `precision` for the bit width of a sample (if the board supports setting the sampling rate). -- If any property of `init` is specified and has an invalid value on the given board, as defined by the board documentation, throw `TypeError`. -- Request the underlying platform to initialize AIO on `init.pin` (if defined) or otherwise `init.channel`. -- In case of failure, throw `InvalidAccessError`. -- Let `aio` be the `AIOPin`](#aiopin) object that represents the hardware pin identified by `init.pin`, as defined by the board documentation. -- If `init.precision` is defined, request the board to set the precision and initialize the `aio.precision` property with the value supported by the board. If there is an error, throw `InvalidAccessError`. +- If any property of `init` is specified and has an invalid value, throw `TypeError`. +- Request the underlying platform to initialize AIO on the pin identified by `init.name` in the namespace specified by `init.mapping`, or if not found, then in the other namespace. In case of failure, throw `InvalidAccessError`. +- Let `aio` be the `AIOPin`](#aiopin) object that represents the hardware pin identified by `init.name`. +- If `init.precision` is defined, request the board to set the precision and initialize the `aio.precision` property with the value supported by the underlying platform. If there is an error, throw `InvalidAccessError`. - Initialize the `aio.value` property with `undefined`. - Return the `aio` object. ### The `AIO` interface -The `AIO` object extends the [`Pin`](./README.md/#pin) object. | Property | Type | Optional | Default value | Represents | | --- | --- | --- | --- | --- | -| `pin` | String or Number | no | `undefined` | board name for the pin | +| `name` | String or Number | no | `undefined` | pin name | +| `mapping` | enum | no | `"os"` | pin mapping, `"os"` or `"board"` | | `precision` | unsigned long | yes | `undefined` | bit length of digital sample | | Method | Description | @@ -58,13 +63,14 @@ Called when the application is no longer interested in the pin. Until the next [ ### Examples ```javascript try { - var aio = require("board").aio(); // initialize AIO on the board + var aio = require("aio"); // initialize AIO on the board - var a1 = aio.open("A1"); + var a1 = aio.open(1); // pin 1 in OS namespace console.log(board.name + " AIO pin 1 value: " + a1.read()); a1.close(); - var a4 = aio.open({pin: "A4", precision: 12 }); + // Open pin A4 in board namespace, i.e. the value printed on the board + var a4 = aio.open({pin: "A4", mapping: "board", precision: 12 }); setTimeout(function() { a4.close(); diff --git a/board/arduino101.md b/board/arduino101.md index 271ce5f..e7e6ea4 100644 --- a/board/arduino101.md +++ b/board/arduino101.md @@ -1,7 +1,7 @@ Board Support for Arduino 101 ============================= -This document defines the pin values that are accepted by implementations. +This document defines the pin values that are accepted by implementations on board namespace. The board labels are described in the [Arduino 101](https://www.arduino.cc/en/Main/ArduinoBoard101) board documentation. Also, for each board pin, the supported modes of each pin is described. diff --git a/board/frdm_k64f.md b/board/frdm_k64f.md index a2d60bc..7f8aa14 100644 --- a/board/frdm_k64f.md +++ b/board/frdm_k64f.md @@ -1,6 +1,8 @@ Board Support for FRDM-K64F =========================== +This document defines the pin values that are accepted by implementations on board namespace. + The FRDM-K64F board pin names and locations are shown [here](https://developer.mbed.org/platforms/FRDM-K64F/). There are 16 general purpose I/O pins, `D0` - `D15`. `D14` and `D15` can currently be used as GPIO_INs but not as outputs. diff --git a/board/gpio.md b/board/gpio.md index b8db6d5..08f99fe 100644 --- a/board/gpio.md +++ b/board/gpio.md @@ -9,32 +9,51 @@ On certain boards, analog pins can also be used as GPIO. ### The GPIO API object -GPIO pin functionality is exposed by an object that can be obtained by using the [`gpio()`](./README.md/#gpio) method of the [`Board` API](./README.md/#board). See also the [Web IDL](./webidl.md). The API object exposes the following method: +When requiring `"gpio"`, the following steps are run: +- If there is no permission for using the functionality, throw `SecurityError`. +- If the AIO functionality is not supported on the board, throw `"NotSupportedError"`. +- Return an object that implements the following methods. | Method | Description | | --- | --- | -| [`open()`](#open) | synchronous open | +| [`open()`](#open) | open GPIO pin | +| [`port()`](#port) | open GPIO port | + +See also the [Web IDL](./webidl.md) definition. #### The `GPIO open(options)` method -Configures a GPIO pin or port using data provided by the `options` argument. It involves the following steps: -- If `options` is a number or string, create a dictionary `init` and use the value of `options` to initialize the `init.pin` property. -- Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`GPIO`](#gpio) properties: - * `pin` for the GPIO pin or port name defined by the board - * `port` for the array of GPIO pins that define the port +Configures a GPIO pin using data provided by the `options` argument, that may contain the following properties: + + * `name` for pin name, either a number or string, by default `undefined` + * `mapping` for either `"board"` or `"os"` pin mapping, by default `"os"` * `mode` with valid values `"input"` or `"output"`, by default `"input"` * `activeLow`, by default `false` * `edge`, by default `"any"` * `state`, by default `undefined`. -- If any of the `init` properties has an invalid value, throw `TypeError`. -- If `init.port` is defined and matches a GPIO port name defined by the board, run the following sub-steps: - * request the underlying platform to initialize the GPIO port on the given board with the `init` properties. In case of failure, throw `InvalidAccessError`. - * Let `gpio` be the [`GPIO`](#gpio) object representing the requested port initialized by `init`. -- Otherwise, if `init.pin` is defined, run the following sub-steps: - * Let `gpio` be the [`GPIO`](#gpio) object representing the requested pin initialized by `init`. For the [`GPIO`](#gpio) properties missing from the `init` dictionary, use the default values of the `GPIO` object properties. - * Initialize the `gpio.pin` property with `init.pin`. -- Return the `gpio` object. +The method runs the following steps: +- If `options` is a number or string, let `init` be a [GPIOOptions](#gpiooptions) object, let `init.name` be `options` and let the other [GPIOOptions](#gpiooptions) properties take the default values. +- If `options` is a dictionary and if `options.name` is not defined, throw `TypeError`. If any of the `options` properties has an invalid value, throw `TypeError`. Let the the missing [GPIOOptions](#gpiooptions) properties take the default values. Let `init` be `options`. +- Let `gpio` be the [`GPIO`](#gpio) object that represents the requested pin corresponding to `init.name`, by matching `init.name` in the pin namespace specified by `mapping`, then in the other pin namespace. If there is no match in either namespaces, throw `InvalidAccessError`. +- Initialize `gpio` with the properties of `init` and return `gpio`. + + +#### The `GPIO port(port, options)` method +Configures a GPIO pin or port using data provided by the `options` argument that can take the same properties as in the [`open()`](#open) method. +A GPIO port can be identified either by a symbolic name defined by the OS or the board, or a sequence of pin names the implementation binds together and are written and read together. +The `port()` method runs the following steps: +- If `port` is not a string or an array with at least one element, throw `TypeError`. +- Let `init` be a [GPIOOptions](#gpiooptions) object with all properties not defined in `options` take default values. If any of the `init` properties has an invalid value, throw `TypeError`. +- If `port` is a string, match it to the supported GPIO port names in the pin namespace specified by `mapping`, or then in the other pin namespace. If there is no match in either namespaces, throw `InvalidAccessError`. Otherwise let `gpio` be the [`GPIO`](#gpio) object representing the requested port and initialize it with `init`. Let `gpio.name` be `port` and let `gpio.port` be `undefined`. +- Otherwise if `port` is an array, run the following sub-steps for aggregating pins in the implementation: + * Let `gpio.name` take the string value `"port"` and `gpio.port` be the sequence of pin names that form the GPIO port. + * For each pin name in the `port` sequence, run the [`open()`](#open) method with `init` as argument, associate the returned [`GPIO`](#gpio) object with the `gpio` object and make it represent a bit in the value returned by `gpio.read()`, with the first element in the sequence representing the most significant bit. If any of the opens fail, close the other pins and throw `InvalidAccessError`. + * Initialize [`gpio.write()`](#write) with a function that obtains the corresponding bit values for each pin participating in the port and writes the pin values. Re-throw any errors. + * Initialize [`gpio.read()`](#read) with a function that reads the corresponding bit values from each pin participating in the port and returns the assembled value. Re-throw any errors. + * Initialize [`gpio.close()`](#close) with a function that closes each participating pin. Re-throw any errors. + * For any listener on the `data` event, on notification from the underlying platform on a value change on any participating pin, implementations SHOULD wait a platform-dependent short time and then fire the `data` event with the value assembled from the participating pins. + * Return the `gpio` object. ### The `GPIO` interface @@ -42,7 +61,8 @@ The `GPIO` interface extends the [`Pin`](./README.md/#pin) object and implements | Property | Type | Optional | Default value | Represents | | --- | --- | --- | --- | --- | -| `pin` | String or Number | no | `undefined` | board name for the pin | +| `name` | String or Number | no | `undefined` | pin name | +| `mapping` | String | no | `"os"` | pin mapping | | `mode` | String | no | `undefined` | I/O mode | | `port` | array | yes | `undefined` | array of pin names representing the ports | `activeLow` | boolean | yes | `false` | whether the pin is active on logical low | @@ -59,7 +79,7 @@ The `GPIO` interface extends the [`Pin`](./README.md/#pin) object and implements | -----------| ----------------------- | | `data` | unsigned long (the pin value) | -The `data` event listener callback receives the current value of the pin (0 or 1 for single pins, and positive integer for GPIO ports). +The `data` event listener callback receives the current value of the pin (0 or 1 for single pins, and positive integer for GPIO ports). Implementations SHOULD use a platform-dependent minimum time interval between firing two consecutive events. The `pin` property inherited from [`Pin`](./README.md/#pin) can take values defined by the board documentation, usually positive integers. @@ -91,17 +111,18 @@ Called when the application is no longer interested in the pin. This also remove ```javascript try { - var gpio = require("board").gpio(); + var board = require("board"); + var gpio = require("gpio"); var gpio3 = gpio.open(3); // GPIO input pin with default configuration. console.log(board.name + " GPIO pin 3 value: " + gpio3.read()); gpio3.close(); - var gpio5 = gpio.open({ pin: 5, mode: "output", activeLow: true }); + var gpio5 = gpio.open({ name: 5, mode: "output", activeLow: true }); gpio5.write(0); // activate pin gpio5.close(); - gpio6 = gpio.open({pin: 6, edge: "any"}); + gpio6 = gpio.open({ pin: 6, edge: "any"}); gpio6.on("data", function(value) { console.log("GPIO pin 6 has changed; value: " + value); }; @@ -120,7 +141,7 @@ try { try { var gpio = require("board").gpio(); // Configure a GPIO port using default configuration - var gport1 = gpio.open({ port: [3,4,5,6,7,8]}); + var gport1 = gpio.port([3,4,5,6,7,8]); // Set up a change listener on the port value. gport1.on("data", function(value) { @@ -132,9 +153,15 @@ try { }, 2000); // Initialize and write an output port - var gport2 = gpio.open({ port: [5,6,7,8], mode: "output", activeLow: true }); + var gport2 = gpio.port([5,6,7,8], { mode: "output", activeLow: true }); gport2.write(0x21); gport2.close(); + + // Configure a GPIO port supported in the platform under a symbolic name + var gport3 = gpio.port("gpio-port-1", { mode: "output", activeLow: true }); + gport3.write(0x21); + gport3.close(); + } catch (err) { console.log("GPIO port error: " + error.message); }; diff --git a/board/i2c.md b/board/i2c.md index 7d25400..17250c7 100644 --- a/board/i2c.md +++ b/board/i2c.md @@ -13,12 +13,17 @@ This API uses a [`Buffer`](../README.md/#buffer) object for both read and write. ### The I2C API object -I2C functionality is exposed by an object that can be obtained by using the [`i2c()`](./README.md/#i2c) method of the [`Board` API](./README.md/#board). See also the [Web IDL](./webidl.md). The API object exposes the following method: +When requiring `"i2c"`, the following steps are run: +- If there is no permission for using the functionality, throw `SecurityError`. +- If the AIO functionality is not supported on the board, throw `"NotSupportedError"`. +- Return an object that implements the following method. | Method | Description | | --- | --- | | [`open()`](#open) | synchronous open | +See also the [Web IDL](./webidl.md) definition. + #### The `I2C open(options)` method Configures an I2C bus using data provided by the `options` argument. It runs the following steps: @@ -70,7 +75,7 @@ Closes the current [`I2C`](#i2c) bus and cancels all pending operations. ```javascript try { - var i2c = require("board").i2c().open(); + var i2c = require("i2c").open(); // open the default I2C bus console.log("I2C bus " + i2c.bus + " opened with bus speed " + i2c.speed); i2c.write(0x02, [1, 2, 3]); diff --git a/board/pwm.md b/board/pwm.md index f271ad3..3038418 100644 --- a/board/pwm.md +++ b/board/pwm.md @@ -6,36 +6,43 @@ The PWM API supports writing analog values to pins using Pulse Width Modulation. PWM is characterized by a repeating digital signal of given pulse width (duration for value 1 in normal polarity and for value 0 in reverse polarity) and a total duration of the signal (period). Also, PWM is characterized by a duty cycle that is the ratio between the pulse width and the total signal period. For instance, a LED that is driven with a PWM signal with 50% duty cycle will be approximately half-bright. -The term "channel" is used as the numeric index of a PWM pin relative to the PWM controller, as described in the board documentation. +The term "channel" is used as the numeric index of a PWM pin relative to the PWM controller starting with 1. ### The PWM API object -PWM functionality is exposed by an object that can be obtained by using the [`pwm()`](./README.md/#pwm) method of the [`Board` API](./README.md/#board). See also the [Web IDL](./webidl.md). The API object exposes the following method: +When requiring `"pwm"`, the following steps are run: +- If there is no permission for using the functionality, throw `SecurityError`. +- If the AIO functionality is not supported on the board, throw `"NotSupportedError"`. +- Return an object that implements the following method. | Method | Description | | --- | --- | -| [`open()`](#open) | synchronous open | +| [`open()`](#open) | open a PWM pin | + +See also the [Web IDL](./webidl.md) definition. #### The `PWM open(options)` method Configures a PWM pin using data provided by the `options` argument. It runs the following steps: - If `options` is a string or number, create a dictionary `init` and use the value of `options` to initialize the `init.pin` property. -- Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`PWM`](#pwm) properties, but at least `pin` - * `pin` for board pin name, or PWM channel number, as defined by the board documentation - * `reversePolarity`, with a default value `false`. +- Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`PWM`](#pwm) properties, but at least `name` + * `name` for pin name + * `mapping` for pin mapping, by default `"os"` + * `reversePolarity`, by default `false`. - If any of the `init` properties is specified, but has invalid value on the board, throw `InvalidAccessError`. -- Let `pwm` be the [`PWM`](#pwm) object representing the pin identified by the `init.pin` and request the underlying platform to initialize PWM for the given pin. In case of failure, throw `InvalidAccessError`. -- Initialize the `pwm.pin` property with `init.pin`. +- Let `pwm` be the [`PWM`](#pwm) object representing the pin identified by the `init.name` in the `mapping` pin namespace and request the underlying platform to initialize PWM for the given pin. In case of failure, throw `InvalidAccessError`. +- Initialize the `pwm.name` property with `init.name`. - Initialize the `pwm.reversePolarity` property with `init.reversePolarity`. - Return the `pwm` object. ### The `PWM` interface -Represents the properties and methods that expose PWM functionality. The `PWM` object extends the [`Pin`](./README.md/#pin) object. +Represents the properties and methods that expose PWM functionality. | Property | Type | Optional | Default value | Represents | | --- | --- | --- | --- | --- | -| `pin` | String or Number | no | `undefined` | board name for the pin, or channel number | +| `name` | String or Number | no | `undefined` | pin name | +| `mapping` | String | no | `"os"` | pin mapping | | `reversePolarity` | boolean | yes | `false` | PWM polarity | | `write()` | function | no | defined by implementation | set and enable PWM signal | | `stop()` | function | no | defined by implementation | stop the PWM signal | @@ -47,7 +54,9 @@ Represents the properties and methods that expose PWM functionality. The `PWM` o | [`stop()`](#stop) | stop the PWM signal | | [`close()`](#close) | close the pin | -The `pin` property inherited from [`Pin`](./README.md/#pin) can take values defined by the board documentation, either a pin name, or a channel number. +The `name` property is an opaque number or string, representing a pin name. + +The `mapping` property represents the pin namespace, either `"board"` or `"os"`. The `reversePolarity` property tells whether the PWM signal is active on 0. The default value is `false`. @@ -83,7 +92,7 @@ Called when the application is no longer interested in the pin. It invokes the ` ```javascript try { - var pwm = require("board").pwm(); + var pwm = require("pwm"); var pwm6 = pwm.open(6); // configure pin 6 as PWM pwm6.write({ period: 2.5, pulseWidth: 1.5 }); // duty cycle is 60% diff --git a/board/spi.md b/board/spi.md index ee16d4a..35ab338 100644 --- a/board/spi.md +++ b/board/spi.md @@ -13,12 +13,17 @@ This API uses a [`Buffer`](../README.md/#buffer) object for both read and write ### The SPI API object -SPI functionality is exposed by an object that can be obtained by using the [`spi()`](./README.md/#spi) method of the [`Board` API](./README.md/#board). See also the [Web IDL](./webidl.md). The API object exposes the following method: +When requiring `"spi"`, the following steps are run: +- If there is no permission for using the functionality, throw `SecurityError`. +- If the AIO functionality is not supported on the board, throw `"NotSupportedError"`. +- Return an object that implements the following method. | Method | Description | | --- | --- | | [`open()`](#open) | synchronous open | +See also the [Web IDL](./webidl.md) definition. + #### The `SPI open(options)` method Configures an SPI bus using data provided by the `options` argument. It runs the following steps: @@ -99,7 +104,7 @@ Closes the current [`SPI`](#spi) bus and cancels all pending operations. ```javascript try { - var spi = require("board").spi().open(); + var spi = require("spi").open(); // open the default SPI bus console.log("SPI bus " + spi.bus + " opened with bus speed " + spi.speed); console.log("SPI mode: " + spi.mode); diff --git a/board/uart.md b/board/uart.md index 982eb92..85a3c78 100644 --- a/board/uart.md +++ b/board/uart.md @@ -6,12 +6,17 @@ This API uses a [`Buffer`](../README.md/#buffer) object for both read and write. ### The UART API object -UART functionality is exposed by an object that can be obtained by using the [`uart()`](./README.md/#uart) method of the [`Board` API](./README.md/#board). See also the [Web IDL](./webidl.md). The API object exposes the following method: +When requiring `"uart"`, the following steps are run: +- If there is no permission for using the functionality, throw `SecurityError`. +- If the AIO functionality is not supported on the board, throw `"NotSupportedError"`. +- Return an object that implements the following method. | Method | Description | | --- | --- | | [`open()`](#open) | synchronous open | +See also the [Web IDL](./webidl.md) definition. + #### The `UART open(options)` method Configures an UART port using data provided by the `options` argument. It runs the following steps: @@ -74,7 +79,7 @@ Closes the current [`UART`](#uart) port and interrupts all pending operations. ```javascript try { - var uart = require("board").uart("serialUSB0"); + var uart = require("uart").open("serialUSB0"); console.log("UART port " + uart.port); console.log("Speed [bps]: " + uart.speed); diff --git a/board/webidl.md b/board/webidl.md index e591f00..2b215b1 100644 --- a/board/webidl.md +++ b/board/webidl.md @@ -4,38 +4,33 @@ Web IDL for Board and IO APIs interface Board { readonly attribute String name; // board name, e.g. "arduino101" - attribute EventHandler onerror; + readonly attribute String os; // OS name, e.g. "Zephyr-1.0" - AIO aio(); - GPIO gpio(); - PWM pwm(); - I2C i2c(); - SPI spi(); - UART uart(); + readonly attribute EventHandler onerror; }; Board implements EventEmitter; typedef (long or unsigned long or double or unrestricted double) Number; typedef (DOMString or USVString) String; -typedef (Number or String) PinName; // implementation uses board specific mapping +typedef (Number or String) PinName; -interface Pin { - readonly attribute PinName pin; // board number/name of the pin -}; +enum PinMapping { "board", "os" }; // AIO interface AIOObject { - AIO open((PinName or AIOOptions) options); + AIO open((PinName or AIOOptions) init); }; dictionary AIOOptions { - PinName pin; - unsigned long precision; + PinName name; + PinMapping mapping = "os"; + unsigned long precision = 10; }; [NoInterfaceObject] -interface AIO: Pin { +interface AIO { + readonly attribute PinName name; readonly attribute unsigned long precision; // 10 or 12 bits unsigned long read(); @@ -44,40 +39,45 @@ interface AIO: Pin { // GPIO interface GPIOObject { - GPIO open((PinName or GPIOOptions) options); + GPIO open((PinName or GPIOOptions) init); + GPIO port((PinName or sequence) port, optional GPIOOptions options); }; -enum GPIOMode { "input", "output" }; -enum GPIOEdge { "none", "rising", "falling", "any" }; -enum GPIOState { "pull-up", "pull-down", "high-impedance" }; +[NoInterfaceObject] +interface GPIO: { + // has all the properties of GPIOOptions as readonly attributes + + unsigned long read(); + void write(long value); + void close(); + + attribute EventHandler ondata; -dictionary GPIOOptions { - PinName pin; - sequence port; // GPIO Ports (8, 16 or 32 pins) - GPIOMode mode = "input"; - boolean activeLow = false; - GPIOEdge edge = "any"; - GPIOState state = "high-impedance"; }; -[NoInterfaceObject] -interface GPIO { - PinName pin; - unsigned long read(); - void write(long value); - void close(); - attribute EventHandler ondata; +GPIO implements EventEmitter; + +dictionary GPIOOptions { + PinName name; + PinMapping mapping = "os"; + GPIOMode mode = "input"; + boolean activeLow = false; + GPIOEdge edge = "any"; + GPIOState state = "high-impedance"; }; -GPIOAccess implements EventEmitter; +enum GPIOMode { "input", "output" }; +enum GPIOEdge { "none", "rising", "falling", "any" }; +enum GPIOState { "pull-up", "pull-down", "high-impedance" }; // PWM interface PWMObject { - PWM open((PinName or PWMOptions) options); + PWM open((PinName or PWMOptions) init); }; dictionary PWMOptions { - PinName pin; + PinName name; + PinMapping mapping = "os"; boolean reversePolarity = false; double period; double pulseWidth; @@ -85,11 +85,19 @@ dictionary PWMOptions { }; [NoInterfaceObject] -interface PWM: Pin { - readonly attribute boolean reversePolarity; - void write(PWMOptions value); - void stop(); - void close(); +interface PWM { + readonly attribute PinName name; + readonly attribute boolean reversePolarity; + + void write(PWMValue value); + void stop(); + void close(); +}; + +dictionary PWMValue { + double period; + double pulseWidth; + double dutyCycle; }; // I2C From c17862cf5cd0703e1443721e9d4ba01defeb407c Mon Sep 17 00:00:00 2001 From: Zoltan Kis Date: Thu, 4 May 2017 21:01:01 +0300 Subject: [PATCH 4/8] GPIO: change default values Signed-off-by: Zoltan Kis --- board/gpio.md | 18 +++++++++--------- board/webidl.md | 8 +++----- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/board/gpio.md b/board/gpio.md index c8ef0cf..93f5299 100644 --- a/board/gpio.md +++ b/board/gpio.md @@ -27,10 +27,10 @@ Configures a GPIO pin using data provided by the `options` argument, that may co * `name` for pin name, either a number or string, by default `undefined` * `mapping` for either `"board"` or `"os"` pin mapping, by default `"os"` - * `mode` with valid values `"input"` or `"output"`, by default `"input"` + * `mode` with valid values `"in"` or `"out"`, by default `"out"` * `activeLow`, by default `false` - * `edge`, by default `"any"` - * `state`, by default `undefined`. + * `edge`, with valid values: `"rising"`, `"falling"`, `"any"`, `"none"`, by default `"none"` + * `state`, by default `undefined`, supported values: `"pull-up"`, `"pull-down"`, `"high-impedance"`. The method runs the following steps: - If `options` is a number or string, let `init` be a [GPIOOptions](#gpiooptions) object, let `init.name` be `options` and let the other [GPIOOptions](#gpiooptions) properties take the default values. @@ -115,14 +115,14 @@ try { var gpio = require("gpio"); var gpio3 = gpio.open(3); // GPIO input pin with default configuration. - console.log(board.name + " GPIO pin 3 value: " + gpio3.read()); + gpio3.write(1); // activate pin gpio3.close(); - var gpio5 = gpio.open({ name: 5, mode: "output", activeLow: true }); + var gpio5 = gpio.open({ name: 5, mode: "out", activeLow: true }); gpio5.write(0); // activate pin gpio5.close(); - gpio6 = gpio.open({ pin: 6, edge: "any"}); + gpio6 = gpio.open({ pin: 6, mode: "in", edge: "any"}); gpio6.on("data", function(value) { console.log("GPIO pin 6 has changed; value: " + value); }); @@ -141,7 +141,7 @@ try { try { var gpio = require("board").gpio(); // Configure a GPIO port using default configuration - var gport1 = gpio.port([3,4,5,6,7,8]); + var gport1 = gpio.port([3,4,5,6,7,8], { mode: "in"}); // Set up a change listener on the port value. gport1.on("data", function(value) { @@ -153,12 +153,12 @@ try { }, 2000); // Initialize and write an output port - var gport2 = gpio.port([5,6,7,8], { mode: "output", activeLow: true }); + var gport2 = gpio.port([5,6,7,8], { activeLow: true }); gport2.write(0x21); gport2.close(); // Configure a GPIO port supported in the platform under a symbolic name - var gport3 = gpio.port("gpio-port-1", { mode: "output", activeLow: true }); + var gport3 = gpio.port("gpio-port-1", { activeLow: true }); gport3.write(0x21); gport3.close(); diff --git a/board/webidl.md b/board/webidl.md index 2b215b1..4642ca6 100644 --- a/board/webidl.md +++ b/board/webidl.md @@ -45,8 +45,6 @@ interface GPIOObject { [NoInterfaceObject] interface GPIO: { - // has all the properties of GPIOOptions as readonly attributes - unsigned long read(); void write(long value); void close(); @@ -60,13 +58,13 @@ GPIO implements EventEmitter; dictionary GPIOOptions { PinName name; PinMapping mapping = "os"; - GPIOMode mode = "input"; + GPIOMode mode = "out"; boolean activeLow = false; - GPIOEdge edge = "any"; + GPIOEdge edge = "none"; GPIOState state = "high-impedance"; }; -enum GPIOMode { "input", "output" }; +enum GPIOMode { "in", "out" }; enum GPIOEdge { "none", "rising", "falling", "any" }; enum GPIOState { "pull-up", "pull-down", "high-impedance" }; From f8d12530a749a20d521fcf07d9819fc8413903ba Mon Sep 17 00:00:00 2001 From: Zoltan Kis Date: Sat, 6 May 2017 11:28:22 +0300 Subject: [PATCH 5/8] Make pin and pin mapping spec consistent Signed-off-by: Zoltan Kis --- board/aio.md | 14 ++++----- board/gpio.md | 84 +++++++++++++++++++++++++------------------------ board/pwm.md | 19 +++++------ board/webidl.md | 21 ++++++------- 4 files changed, 70 insertions(+), 68 deletions(-) diff --git a/board/aio.md b/board/aio.md index afa08b7..a0d1901 100644 --- a/board/aio.md +++ b/board/aio.md @@ -22,13 +22,13 @@ See also the [Web IDL](./webidl.md) definition. #### The `AIO open(options)` method Configures an AIO pin using data provided by the `options` argument. It involves the following steps: - If `options` is a string, create a dictionary 'init' and use the value of `options` to initialize the `init.pin` property. -- Otherwise if `options` is a number, create a dictionary 'init' and let `init.name` be `options`. -- Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`AIO`](#aio) properties, where at least `name` MUST be specified: - * `name` for board pin name with the valid values defined by the board, or for the numeric index of the analog pin; - * `mapping` to specify if OS or board namespace is to be used with the pin (by default `"os"`). +- Otherwise if `options` is a number, create a dictionary 'init' and let `init.pin` be `options`. +- Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`AIO`](#aio) properties, where at least `pin` MUST be specified: + * `pin` for board pin name with the valid values defined by the board, or for the numeric index of the analog pin; + * `mapping` to specify if OS or board namespace is to be used with the pin (by default `"system"`). * `precision` for the bit width of a sample (if the board supports setting the sampling rate). - If any property of `init` is specified and has an invalid value, throw `TypeError`. -- Request the underlying platform to initialize AIO on the pin identified by `init.name` in the namespace specified by `init.mapping`, or if not found, then in the other namespace. In case of failure, throw `InvalidAccessError`. +- Request the underlying platform to initialize AIO on the pin identified by `init.pin` in the namespace specified by `init.mapping` if that is defined. If not found, throw `InvalidAccessError`. If `init.mapping is not defined, then search `init.pin` first in the OS namespace, then in board namespace. In case of failure, throw `InvalidAccessError`. - Let `aio` be the `AIOPin`](#aiopin) object that represents the hardware pin identified by `init.name`. - If `init.precision` is defined, request the board to set the precision and initialize the `aio.precision` property with the value supported by the underlying platform. If there is an error, throw `InvalidAccessError`. - Initialize the `aio.value` property with `undefined`. @@ -39,8 +39,8 @@ Configures an AIO pin using data provided by the `options` argument. It involves | Property | Type | Optional | Default value | Represents | | --- | --- | --- | --- | --- | -| `name` | String or Number | no | `undefined` | pin name | -| `mapping` | enum | no | `"os"` | pin mapping, `"os"` or `"board"` | +| `pin` | String or Number | no | `undefined` | pin name | +| `mapping` | enum | no | `"system"` | pin mapping, `"system"` or `"board"` | | `precision` | unsigned long | yes | `undefined` | bit length of digital sample | | Method | Description | diff --git a/board/gpio.md b/board/gpio.md index 93f5299..f075e8a 100644 --- a/board/gpio.md +++ b/board/gpio.md @@ -21,33 +21,57 @@ When requiring `"gpio"`, the following steps are run: See also the [Web IDL](./webidl.md) definition. +The following dictionary is used for initializing GPIO pins and ports. + + +| Property | Type | Optional | Default value | Represents | +| --- | --- | --- | --- | --- | +| `pin ` | String or Number | no | `undefined` | pin name | +| `mapping` | String | no | `"system"` | pin mapping | +| `mode` | String | no | `undefined` | I/O mode | +| `activeLow` | boolean | yes | `false` | whether the pin is active on logical low | +| `edge` | string | yes | `"any"` | Interrupt generation mode | +| `state` | string | yes | `undefined` | "pulldown", "pullup" | + +The `pin` property is either a number or string, with values defined by the OS or board documentation. The default valus is `undefined`. + +The `mapping` property represents the pin namespace, either `"system"` or `"board"`, by default `"system"`. + +The `mode` property MUST take the value `"in"` or `"out"`. The default value is `"out"`. + +The `activeLow` property tells whether the pin value 0 means active. If `activeLow` is `true`, with `value` 0 the pin is active, otherwise inactive. For instance, if an actuator is attached to the (output) pin active on low, client code should write the value 0 to the pin in order to activate the actuator. The default value is `false`. + +The `edge` property is used for input pins and tells whether the `data` event is emitted on the rising edge of the signal (string value `"rising"`) when `value` changes from 0 to 1, or on falling edge (string value `"falling"`) when `value` changes from 1 to 0, or both edges (string value `"any"`), or never (string value `"none`"). The default value is `"none"`. + +The `state` property tells if the internal pulldown (string value `"pulldown"`) or pullup (string value `"pullup"`) resistor is used for input pins to provide a default value (0 or 1) when the input is floating. The default value is `undefined`. + + #### The `GPIO open(options)` method Configures a GPIO pin using data provided by the `options` argument, that may contain the following properties: - - * `name` for pin name, either a number or string, by default `undefined` - * `mapping` for either `"board"` or `"os"` pin mapping, by default `"os"` - * `mode` with valid values `"in"` or `"out"`, by default `"out"` - * `activeLow`, by default `false` - * `edge`, with valid values: `"rising"`, `"falling"`, `"any"`, `"none"`, by default `"none"` - * `state`, by default `undefined`, supported values: `"pull-up"`, `"pull-down"`, `"high-impedance"`. The method runs the following steps: -- If `options` is a number or string, let `init` be a [GPIOOptions](#gpiooptions) object, let `init.name` be `options` and let the other [GPIOOptions](#gpiooptions) properties take the default values. -- If `options` is a dictionary and if `options.name` is not defined, throw `TypeError`. If any of the `options` properties has an invalid value, throw `TypeError`. Let the the missing [GPIOOptions](#gpiooptions) properties take the default values. Let `init` be `options`. -- Let `gpio` be the [`GPIO`](#gpio) object that represents the requested pin corresponding to `init.name`, by matching `init.name` in the pin namespace specified by `mapping`, then in the other pin namespace. If there is no match in either namespaces, throw `InvalidAccessError`. -- Initialize `gpio` with the properties of `init` and return `gpio`. +- If `options` is a number or string, let `init` be a [GPIOOptions](#gpiooptions) object, let `init.pin` be `options` and let the other [GPIOOptions](#gpiooptions) properties take the default values. +- If `options` is a dictionary and if `options.pin` is not defined, throw `TypeError`. If any of the `options` properties has an invalid value, throw `TypeError`. Let the the missing [GPIOOptions](#gpiooptions) properties take the default values. Let `init` be `options`. +- Request the underlying platform to initialize GPIO on the pin identified by `init.pin` in the namespace specified by `init.mapping` if that is defined. If not found, throw `InvalidAccessError`. If `init.mapping is not defined, then search `init.pin` first in the OS namespace, then in board namespace. In case of failure, throw `InvalidAccessError`. +- Let `gpio` be the [`GPIO`](#gpio) object that represents the requested pin corresponding to `init.pin` and return `gpio`. #### The `GPIO port(port, options)` method Configures a GPIO pin or port using data provided by the `options` argument that can take the same properties as in the [`open()`](#open) method. A GPIO port can be identified either by a symbolic name defined by the OS or the board, or a sequence of pin names the implementation binds together and are written and read together. +The `port` argument is either a number or string representing a symbolic port name defined in the OS or board documentation, or an array of strings representing the pin names participating in the port in MSB order, i.e. the first element in the array represents the MSB. + The `port()` method runs the following steps: -- If `port` is not a string or an array with at least one element, throw `TypeError`. -- Let `init` be a [GPIOOptions](#gpiooptions) object with all properties not defined in `options` take default values. If any of the `init` properties has an invalid value, throw `TypeError`. -- If `port` is a string, match it to the supported GPIO port names in the pin namespace specified by `mapping`, or then in the other pin namespace. If there is no match in either namespaces, throw `InvalidAccessError`. Otherwise let `gpio` be the [`GPIO`](#gpio) object representing the requested port and initialize it with `init`. Let `gpio.name` be `port` and let `gpio.port` be `undefined`. -- Otherwise if `port` is an array, run the following sub-steps for aggregating pins in the implementation: - * Let `gpio.name` take the string value `"port"` and `gpio.port` be the sequence of pin names that form the GPIO port. +- If `options` is a defined, let `mapping` be `init.mapping`. Let `init` be `options` and let the the missing [GPIOOptions](#gpiooptions) properties take the default values. +- Otherwise if `options` is not defined, let `init` be a [GPIOOptions](#gpiooptions) dictionary with all properties taking the default value. +- If `port` is a number or string, run the following sub-steps: + * If `mapping` is defined, match `port` to the supported GPIO port names in the pin namespace specified by `mapping`. If not found, throw `InvalidAccessError`. + * Otherwise if `mapping` is not defined, search `port` first in the OS namespace, then in board namespace. If both fail, throw `InvalidAccessError`. + * Request the underlying platform to initialize the GPIO port identified by `port` and initialize it using `init`. + * Let `gpio` be the [`GPIO`](#gpio) object representing the requested port and return `gpio`. +- Otherwise if `init.port` is an array, run the following sub-steps for aggregating pins in the implementation: + * Let `gpio` be a [`GPIO`](#gpio) object. * For each pin name in the `port` sequence, run the [`open()`](#open) method with `init` as argument, associate the returned [`GPIO`](#gpio) object with the `gpio` object and make it represent a bit in the value returned by `gpio.read()`, with the first element in the sequence representing the most significant bit. If any of the opens fail, close the other pins and throw `InvalidAccessError`. * Initialize [`gpio.write()`](#write) with a function that obtains the corresponding bit values for each pin participating in the port and writes the pin values. Re-throw any errors. * Initialize [`gpio.read()`](#read) with a function that reads the corresponding bit values from each pin participating in the port and returns the assembled value. Re-throw any errors. @@ -57,17 +81,7 @@ The `port()` method runs the following steps: ### The `GPIO` interface -The `GPIO` interface extends the [`Pin`](./README.md/#pin) object and implements the [`EventEmitter`](../README.md/#events) interface. It exposes the following properties and methods. - -| Property | Type | Optional | Default value | Represents | -| --- | --- | --- | --- | --- | -| `name` | String or Number | no | `undefined` | pin name | -| `mapping` | String | no | `"os"` | pin mapping | -| `mode` | String | no | `undefined` | I/O mode | -| `port` | array | yes | `undefined` | array of pin names representing the ports -| `activeLow` | boolean | yes | `false` | whether the pin is active on logical low | -| `edge` | string | yes | `"any"` | Interrupt generation mode | -| `state` | string | yes | `undefined` | "pulldown", "pullup" | +The `GPIO` interface implements the [`EventEmitter`](../README.md/#events) interface. It exposes the following methods and event. | Method | Description | | --- | --- | @@ -81,18 +95,6 @@ The `GPIO` interface extends the [`Pin`](./README.md/#pin) object and implements The `data` event listener callback receives the current value of the pin (0 or 1 for single pins, and positive integer for GPIO ports). Implementations SHOULD use a platform-dependent minimum time interval between firing two consecutive events. -The `pin` property inherited from [`Pin`](./README.md/#pin) can take values defined by the board documentation, usually positive integers. - -The `mode` property MUST take the value `"input"` or `"output"`. The default value is `"input"`. - -The `port` property, if defined, is an array of strings that represents the ordered list of pin names that form a GPIO port, where the first element in the array represents the MSB. - -The `activeLow` property tells whether the pin value 0 means active. If `activeLow` is `true`, with `value` 0 the pin is active, otherwise inactive. For instance, if an actuator is attached to the (output) pin active on low, client code should write the value 0 to the pin in order to activate the actuator. - -The `edge` property is used for input pins and tells whether the `data` event is emitted on the rising edge of the signal (string value `"rising"`) when `value` changes from 0 to 1, or on falling edge (string value `"falling"`) when `value` changes from 1 to 0, or both edges (string value `"any"`), or never (string value `"none`"). The default value is `"any"`, which means the event will fire on any change. - -The `state` property tells if the internal pulldown (string value `"pulldown"`) or pullup (string value `"pullup"`) resistor is used for input pins to provide a default value (0 or 1) when the input is floating. The default value is `undefined`. - #### The `unsigned long read()` method Returns the value of the GPIO pin or port. @@ -118,7 +120,7 @@ try { gpio3.write(1); // activate pin gpio3.close(); - var gpio5 = gpio.open({ name: 5, mode: "out", activeLow: true }); + var gpio5 = gpio.open({ pin: 5, mode: "out", activeLow: true }); gpio5.write(0); // activate pin gpio5.close(); @@ -139,7 +141,7 @@ try { ```javascript try { - var gpio = require("board").gpio(); + var gpio = require("gpio"); // Configure a GPIO port using default configuration var gport1 = gpio.port([3,4,5,6,7,8], { mode: "in"}); diff --git a/board/pwm.md b/board/pwm.md index 3038418..5e0c379 100644 --- a/board/pwm.md +++ b/board/pwm.md @@ -26,13 +26,14 @@ See also the [Web IDL](./webidl.md) definition. Configures a PWM pin using data provided by the `options` argument. It runs the following steps: - If `options` is a string or number, create a dictionary `init` and use the value of `options` to initialize the `init.pin` property. - Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`PWM`](#pwm) properties, but at least `name` - * `name` for pin name - * `mapping` for pin mapping, by default `"os"` + * `pin` for pin name + * `mapping` for pin mapping, either `"system"` or `"board"`, by default `"system"` * `reversePolarity`, by default `false`. - If any of the `init` properties is specified, but has invalid value on the board, throw `InvalidAccessError`. -- Let `pwm` be the [`PWM`](#pwm) object representing the pin identified by the `init.name` in the `mapping` pin namespace and request the underlying platform to initialize PWM for the given pin. In case of failure, throw `InvalidAccessError`. -- Initialize the `pwm.name` property with `init.name`. -- Initialize the `pwm.reversePolarity` property with `init.reversePolarity`. +- Let `mapping` be `init.mapping`. +- Let the missing `init` properties take the default value. +- Request the underlying platform to initialize PWM on the pin identified by `init.pin` in the namespace specified by `mapping` if that is defined. If not found, throw `InvalidAccessError`. If `mapping is not defined, then search `init.pin` first in the OS namespace, then in board namespace. In case of failure, throw `InvalidAccessError`. +- Let `pwm` be the [`PWM`](#pwm) object representing the pin identified by the `init.pin` initialized by `init`. - Return the `pwm` object. @@ -41,8 +42,8 @@ Represents the properties and methods that expose PWM functionality. | Property | Type | Optional | Default value | Represents | | --- | --- | --- | --- | --- | -| `name` | String or Number | no | `undefined` | pin name | -| `mapping` | String | no | `"os"` | pin mapping | +| `pin` | String or Number | no | `undefined` | pin name | +| `mapping` | String | no | `"system"` | pin mapping | | `reversePolarity` | boolean | yes | `false` | PWM polarity | | `write()` | function | no | defined by implementation | set and enable PWM signal | | `stop()` | function | no | defined by implementation | stop the PWM signal | @@ -54,9 +55,9 @@ Represents the properties and methods that expose PWM functionality. | [`stop()`](#stop) | stop the PWM signal | | [`close()`](#close) | close the pin | -The `name` property is an opaque number or string, representing a pin name. +The `pin` property is an opaque number or string, representing a pin name. -The `mapping` property represents the pin namespace, either `"board"` or `"os"`. +The `mapping` property represents the pin namespace, either `"board"` or `"system"`. The `reversePolarity` property tells whether the PWM signal is active on 0. The default value is `false`. diff --git a/board/webidl.md b/board/webidl.md index 4642ca6..243f5f1 100644 --- a/board/webidl.md +++ b/board/webidl.md @@ -15,7 +15,7 @@ typedef (long or unsigned long or double or unrestricted double) Number; typedef (DOMString or USVString) String; typedef (Number or String) PinName; -enum PinMapping { "board", "os" }; +enum PinMapping { "board", "system" }; // AIO interface AIOObject { @@ -23,14 +23,14 @@ interface AIOObject { }; dictionary AIOOptions { - PinName name; - PinMapping mapping = "os"; + PinName pin; + PinMapping mapping = "system"; unsigned long precision = 10; }; [NoInterfaceObject] interface AIO { - readonly attribute PinName name; + readonly attribute PinName pin; readonly attribute unsigned long precision; // 10 or 12 bits unsigned long read(); @@ -40,7 +40,7 @@ interface AIO { // GPIO interface GPIOObject { GPIO open((PinName or GPIOOptions) init); - GPIO port((PinName or sequence) port, optional GPIOOptions options); + GPIO port((PinName or sequence) port, optional GPIOOptions init); }; [NoInterfaceObject] @@ -50,14 +50,13 @@ interface GPIO: { void close(); attribute EventHandler ondata; - }; GPIO implements EventEmitter; dictionary GPIOOptions { - PinName name; - PinMapping mapping = "os"; + PinName pin; + PinMapping mapping = "system"; GPIOMode mode = "out"; boolean activeLow = false; GPIOEdge edge = "none"; @@ -74,8 +73,8 @@ interface PWMObject { }; dictionary PWMOptions { - PinName name; - PinMapping mapping = "os"; + PinName pin; + PinMapping mapping = "system"; boolean reversePolarity = false; double period; double pulseWidth; @@ -84,7 +83,7 @@ dictionary PWMOptions { [NoInterfaceObject] interface PWM { - readonly attribute PinName name; + readonly attribute PinName pin; readonly attribute boolean reversePolarity; void write(PWMValue value); From 55cb7e6038a235b983873a0b94dcfc0e5ee6fec4 Mon Sep 17 00:00:00 2001 From: Zoltan Kis Date: Tue, 9 May 2017 22:50:24 +0300 Subject: [PATCH 6/8] BLE: remove some Promises Signed-off-by: Zoltan Kis --- ble/README.md | 12 +++--------- ble/webidl.md | 6 +++--- board/README.md | 2 +- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/ble/README.md b/ble/README.md index 5ce496c..ee996a9 100644 --- a/ble/README.md +++ b/ble/README.md @@ -154,10 +154,8 @@ The `startadvertising()` method runs the following steps: ##### The `stopAdvertising()` method Requests the platform to stop sending advertisement packets. It runs the following steps: -- Return a [`Promise`](../README.md/#promise) object `promise` and continue [in parallel](https://html.spec.whatwg.org/#in-parallel). - Request from the underlying platform to stop the current advertisement. -- If the request is unsuccessful, reject `promise` with an [`Error`](../README.md/#error) object `error` with `error.message` set to `"BluetoothStopAdvertisement"`. -- Otherwise, if the request was successful, resolve `promise`. +- If the request is unsuccessful, throw an [`Error`](../README.md/#error) object `error` with `error.message` set to `"BluetoothStopAdvertisement"`. ##### The `addService(service)` method @@ -288,17 +286,13 @@ The `needsResponse` property is a boolean that is by default `true`. ##### The `respond(data)` method Sends a response to the request. It executes the following steps: -- Return a [`Promise`](../README.md/#promise) object `promise` and continue [in parallel](https://html.spec.whatwg.org/#in-parallel). - Create a response to the request, and include `data` in the response. - Request from the underlying platform to send the response to the client. -- If the request is unsuccessful, reject `promise` with an [`Error`](../README.md/#error) object `error` with `error.message` set to `"BluetoothSendResponse"`. -- Otherwise, if the request was successful, resolve `promise`. +- If the request is unsuccessful, throw an [`Error`](../README.md/#error) object `error` with `error.message` set to `"BluetoothSendResponse"`. ##### The `error(error)` method Sends an error response to the request. It executes the following steps: -- Return a [`Promise`](../README.md/#promise) object `promise` and continue [in parallel](https://html.spec.whatwg.org/#in-parallel). - Create an error response to the request, and include `error` in the response. - Request from the underlying platform to send the response to the client. -- If the request is unsuccessful, reject `promise` with an [`Error`](../README.md/#error) object `error` with `error.message` set to `"BluetoothSendErrorResponse"`. -- Otherwise, if the request was successful, resolve `promise`. +- If the request is unsuccessful, throw an [`Error`](../README.md/#error) object `error` with `error.message` set to `"BluetoothSendErrorResponse"`. diff --git a/ble/webidl.md b/ble/webidl.md index 5c97f42..d9ba04b 100644 --- a/ble/webidl.md +++ b/ble/webidl.md @@ -19,7 +19,7 @@ interface BluetoothPeripheralDevice { Promise startAdvertising(Advertisement advertisement, optional AdvertisingOptions options); - Promise stopAdvertising(); + void stopAdvertising(); // Promise? readonly attribute boolean enabled; attribute EventHandler onenabledchange; @@ -125,8 +125,8 @@ interface Request { readonly attribute Buffer? data = null; readonly attribute boolean needsResponse; - Promise respond(optional Buffer data); - Promise respondWithError(Error error); + void respond(optional Buffer data); // Promise? + void respondWithError(Error error); // Promise? }; enum RequestType { "read", "write", "notify", "subscribe", "unsubscribe"}; diff --git a/board/README.md b/board/README.md index f775426..b4ab0fb 100644 --- a/board/README.md +++ b/board/README.md @@ -37,7 +37,7 @@ If the functionality is not supported by the platform, `require` should throw `N ### The `Board` interface -Represents a hardware circuit board such as Arduino 101. +Represents a hardware circuit board such as Arduino 101. | Property | Type | Optional | Default value | Represents | | --- | --- | --- | --- | --- | From b7a8879e860875c40c3bdf44f1e12ba9c06d2b17 Mon Sep 17 00:00:00 2001 From: Zoltan Kis Date: Tue, 9 May 2017 23:06:25 +0300 Subject: [PATCH 7/8] Board: editorial corrections Signed-off-by: Zoltan Kis --- board/gpio.md | 4 ++-- board/i2c.md | 2 +- board/pwm.md | 2 +- board/spi.md | 2 +- board/uart.md | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/board/gpio.md b/board/gpio.md index f075e8a..0a3d9d1 100644 --- a/board/gpio.md +++ b/board/gpio.md @@ -11,7 +11,7 @@ On certain boards, analog pins can also be used as GPIO. ### The GPIO API object When requiring `"gpio"`, the following steps are run: - If there is no permission for using the functionality, throw `SecurityError`. -- If the AIO functionality is not supported on the board, throw `"NotSupportedError"`. +- If the GPIO functionality is not supported on the board, throw `"NotSupportedError"`. - Return an object that implements the following methods. | Method | Description | @@ -33,7 +33,7 @@ The following dictionary is used for initializing GPIO pins and ports. | `edge` | string | yes | `"any"` | Interrupt generation mode | | `state` | string | yes | `undefined` | "pulldown", "pullup" | -The `pin` property is either a number or string, with values defined by the OS or board documentation. The default valus is `undefined`. +The `pin` property is either a number or string, with values defined by the OS or board documentation. The default value is `undefined`. The `mapping` property represents the pin namespace, either `"system"` or `"board"`, by default `"system"`. diff --git a/board/i2c.md b/board/i2c.md index 17250c7..bfbdfdb 100644 --- a/board/i2c.md +++ b/board/i2c.md @@ -15,7 +15,7 @@ This API uses a [`Buffer`](../README.md/#buffer) object for both read and write. ### The I2C API object When requiring `"i2c"`, the following steps are run: - If there is no permission for using the functionality, throw `SecurityError`. -- If the AIO functionality is not supported on the board, throw `"NotSupportedError"`. +- If the I2C functionality is not supported on the board, throw `"NotSupportedError"`. - Return an object that implements the following method. | Method | Description | diff --git a/board/pwm.md b/board/pwm.md index 5e0c379..9ad7de5 100644 --- a/board/pwm.md +++ b/board/pwm.md @@ -12,7 +12,7 @@ The term "channel" is used as the numeric index of a PWM pin relative to the PWM ### The PWM API object When requiring `"pwm"`, the following steps are run: - If there is no permission for using the functionality, throw `SecurityError`. -- If the AIO functionality is not supported on the board, throw `"NotSupportedError"`. +- If the PWM functionality is not supported on the board, throw `"NotSupportedError"`. - Return an object that implements the following method. | Method | Description | diff --git a/board/spi.md b/board/spi.md index 35ab338..494dbec 100644 --- a/board/spi.md +++ b/board/spi.md @@ -15,7 +15,7 @@ This API uses a [`Buffer`](../README.md/#buffer) object for both read and write ### The SPI API object When requiring `"spi"`, the following steps are run: - If there is no permission for using the functionality, throw `SecurityError`. -- If the AIO functionality is not supported on the board, throw `"NotSupportedError"`. +- If the SPI functionality is not supported on the board, throw `"NotSupportedError"`. - Return an object that implements the following method. | Method | Description | diff --git a/board/uart.md b/board/uart.md index 85a3c78..de5f36f 100644 --- a/board/uart.md +++ b/board/uart.md @@ -8,7 +8,7 @@ This API uses a [`Buffer`](../README.md/#buffer) object for both read and write. ### The UART API object When requiring `"uart"`, the following steps are run: - If there is no permission for using the functionality, throw `SecurityError`. -- If the AIO functionality is not supported on the board, throw `"NotSupportedError"`. +- If the UART functionality is not supported on the board, throw `"NotSupportedError"`. - Return an object that implements the following method. | Method | Description | From 40c3b89e93d5c7aea4822516d608f3bc9c449295 Mon Sep 17 00:00:00 2001 From: Zoltan Kis Date: Thu, 11 May 2017 11:47:30 +0300 Subject: [PATCH 8/8] Board: change default pin namespace to board Signed-off-by: Zoltan Kis --- board/README.md | 6 ++++-- board/aio.md | 10 +++++----- board/gpio.md | 4 ++-- board/pwm.md | 4 ++-- board/webidl.md | 6 +++--- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/board/README.md b/board/README.md index b4ab0fb..f670b30 100644 --- a/board/README.md +++ b/board/README.md @@ -9,9 +9,11 @@ The [Board](#board) API provides low level interfaces for I/O operations: - [SPI - Serial Peripheral Interface](./spi.md) - [UART - Universal Asynchronous Receiver/Transmitter](./uart.md). -Hardware pin names are usually marked on the circuit boards. However, operating systems, such as [Zephyr](https://www.zephyrproject.org/doc/) define a pin name mapping that is consistent across the boards supported by the OS. This API supports both board and OS defined namespaces. In this API, [`Pin`](#pin) names are opaque to the application. Applications can open a given pin with a pin name that is either a string or a number, in either board or OS namespace. Implementations encapsulate the pin mapping. Also, the API exposes board name, OS name (including OS version) and API version for all board APIs. +Hardware pin names are usually marked on the circuit boards, that defines a board namespace for pins. However, operating systems, such as Linux, or [Zephyr](https://www.zephyrproject.org/doc/) define a pin name mapping that is consistent across the boards supported by the OS. This API supports both board and OS (system) defined namespaces. Pin names are opaque to the application, either strings or numbers that gain meaning in either the board or OS namespace. Also, the API exposes board name, OS name (including OS version) and API version for all board APIs. -The supported board namespaces are listed in [this directory](./): +Since it is generally easier for developers to just look at a given board and use the names printed there in the API, by default the board namespace is used, but developers can specify to use the system namespace as well. If a given pin value is not found in the default (or provided) namespace, an error is thrown: there is no fallback search in the other namespace. + +Examples for the supported board namespaces are listed in [this directory](./): - [arduino101.md](./arduino101.md) - [frdm_k64f.md](./frdm_k64f.md). diff --git a/board/aio.md b/board/aio.md index a0d1901..d3900e7 100644 --- a/board/aio.md +++ b/board/aio.md @@ -25,7 +25,7 @@ Configures an AIO pin using data provided by the `options` argument. It involves - Otherwise if `options` is a number, create a dictionary 'init' and let `init.pin` be `options`. - Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`AIO`](#aio) properties, where at least `pin` MUST be specified: * `pin` for board pin name with the valid values defined by the board, or for the numeric index of the analog pin; - * `mapping` to specify if OS or board namespace is to be used with the pin (by default `"system"`). + * `mapping` to specify if OS or board namespace is to be used with the pin (by default `"board"`). * `precision` for the bit width of a sample (if the board supports setting the sampling rate). - If any property of `init` is specified and has an invalid value, throw `TypeError`. - Request the underlying platform to initialize AIO on the pin identified by `init.pin` in the namespace specified by `init.mapping` if that is defined. If not found, throw `InvalidAccessError`. If `init.mapping is not defined, then search `init.pin` first in the OS namespace, then in board namespace. In case of failure, throw `InvalidAccessError`. @@ -40,7 +40,7 @@ Configures an AIO pin using data provided by the `options` argument. It involves | Property | Type | Optional | Default value | Represents | | --- | --- | --- | --- | --- | | `pin` | String or Number | no | `undefined` | pin name | -| `mapping` | enum | no | `"system"` | pin mapping, `"system"` or `"board"` | +| `mapping` | enum | no | `"board"` | pin mapping, `"system"` or `"board"` | | `precision` | unsigned long | yes | `undefined` | bit length of digital sample | | Method | Description | @@ -65,12 +65,12 @@ Called when the application is no longer interested in the pin. Until the next [ try { var aio = require("aio"); // initialize AIO on the board - var a1 = aio.open(1); // pin 1 in OS namespace + var a1 = aio.open("A1"); // pin 1 in board namespace console.log(board.name + " AIO pin 1 value: " + a1.read()); a1.close(); - // Open pin A4 in board namespace, i.e. the value printed on the board - var a4 = aio.open({pin: "A4", mapping: "board", precision: 12 }); + // Open pin A4 in system namespace + var a4 = aio.open({pin: "ADC4", mapping: "system", precision: 12 }); setTimeout(function() { a4.close(); diff --git a/board/gpio.md b/board/gpio.md index 0a3d9d1..ab33728 100644 --- a/board/gpio.md +++ b/board/gpio.md @@ -27,7 +27,7 @@ The following dictionary is used for initializing GPIO pins and ports. | Property | Type | Optional | Default value | Represents | | --- | --- | --- | --- | --- | | `pin ` | String or Number | no | `undefined` | pin name | -| `mapping` | String | no | `"system"` | pin mapping | +| `mapping` | String | no | `"board"` | pin mapping | | `mode` | String | no | `undefined` | I/O mode | | `activeLow` | boolean | yes | `false` | whether the pin is active on logical low | | `edge` | string | yes | `"any"` | Interrupt generation mode | @@ -35,7 +35,7 @@ The following dictionary is used for initializing GPIO pins and ports. The `pin` property is either a number or string, with values defined by the OS or board documentation. The default value is `undefined`. -The `mapping` property represents the pin namespace, either `"system"` or `"board"`, by default `"system"`. +The `mapping` property represents the pin namespace, either `"system"` or `"board"`, by default `"board"`. The `mode` property MUST take the value `"in"` or `"out"`. The default value is `"out"`. diff --git a/board/pwm.md b/board/pwm.md index 9ad7de5..e1c4c1d 100644 --- a/board/pwm.md +++ b/board/pwm.md @@ -27,7 +27,7 @@ Configures a PWM pin using data provided by the `options` argument. It runs the - If `options` is a string or number, create a dictionary `init` and use the value of `options` to initialize the `init.pin` property. - Otherwise if `options` is a dictionary, let `init` be `options`. It may contain the following [`PWM`](#pwm) properties, but at least `name` * `pin` for pin name - * `mapping` for pin mapping, either `"system"` or `"board"`, by default `"system"` + * `mapping` for pin mapping, either `"system"` or `"board"`, by default `"board"` * `reversePolarity`, by default `false`. - If any of the `init` properties is specified, but has invalid value on the board, throw `InvalidAccessError`. - Let `mapping` be `init.mapping`. @@ -43,7 +43,7 @@ Represents the properties and methods that expose PWM functionality. | Property | Type | Optional | Default value | Represents | | --- | --- | --- | --- | --- | | `pin` | String or Number | no | `undefined` | pin name | -| `mapping` | String | no | `"system"` | pin mapping | +| `mapping` | String | no | `"board"` | pin mapping | | `reversePolarity` | boolean | yes | `false` | PWM polarity | | `write()` | function | no | defined by implementation | set and enable PWM signal | | `stop()` | function | no | defined by implementation | stop the PWM signal | diff --git a/board/webidl.md b/board/webidl.md index 243f5f1..f6b882a 100644 --- a/board/webidl.md +++ b/board/webidl.md @@ -24,7 +24,7 @@ interface AIOObject { dictionary AIOOptions { PinName pin; - PinMapping mapping = "system"; + PinMapping mapping = "board"; unsigned long precision = 10; }; @@ -56,7 +56,7 @@ GPIO implements EventEmitter; dictionary GPIOOptions { PinName pin; - PinMapping mapping = "system"; + PinMapping mapping = "board"; GPIOMode mode = "out"; boolean activeLow = false; GPIOEdge edge = "none"; @@ -74,7 +74,7 @@ interface PWMObject { dictionary PWMOptions { PinName pin; - PinMapping mapping = "system"; + PinMapping mapping = "board"; boolean reversePolarity = false; double period; double pulseWidth;