Skip to content

Commit

Permalink
Promised based bindings.
Browse files Browse the repository at this point in the history
- Base bindings class to extend
- Move docs to base binding
- Make all bindings classes
- Ditch push bindings because it doesn't make anything cleaner
  • Loading branch information
reconbot committed Jan 11, 2017
1 parent e588e88 commit 414057c
Show file tree
Hide file tree
Showing 19 changed files with 874 additions and 1,345 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"rules": {
"arrow-parens": [2, "as-needed", {"requireForBlockBody": true }],
"no-unused-vars": [2, { "vars": "all", "args": "after-used" }],
"no-var": 2,
"object-curly-spacing": [2, "always"],
"object-shorthand": 2,
Expand Down
209 changes: 86 additions & 123 deletions README.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions examples/open-event.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ port.write('main screen turn on', (err) => {

port.on('data', (data) => {
/* get a buffer of data from the serial port */
console.log(data.toString());
});
119 changes: 0 additions & 119 deletions lib/bindings/auto-detect.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,6 @@

const debug = require('debug')('serialport:binding:auto-detect');

/**
* @module serialport
*/

/**
* @name module:serialport.Binding
* @type {module:serialport~Binding}
* @since 5.0.0
* @description The Binding is how node SerialPort talks to the underlying system. By default we auto detect windows, Linux and OSX and load the appropriate module for your system. You can assign `SerialPort.Binding` to any backend you like. You can find more by searching on [npm](https://npmjs.org/).
You can also avoid auto loading the default backends by requiring SerialPort with
```js
var SerialPort = require('serialport/lib/serialport');
SerialPort.Binding = MyBindingClass;
```
*/

switch (process.platform) {
case 'win32':
debug('loading WindowsBinding');
Expand All @@ -31,106 +15,3 @@ switch (process.platform) {
debug('loading LinuxBinding');
module.exports = require('./linux');
}

/**
* You wont ever have to use Binding objects directly they'll be used by SerialPort to access the underlying hardware. This documentation is geared towards people making bindings for different platforms.
* @typedef {Class} Binding
* @class
* @param {object} options
* @param {function} options.disconnect - function to be called when the bindings have detected a disconnected port. This function should be called during any operation instead of that operations usual callback. The `SerialPort` class will attempt to call `close` after a disconnection and ignore any errors.
* @property {boolean} isOpen Required property. `true` if the port is open, `false` otherwise. Should be read only.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
* @since 5.0.0
*/

/**
* Retrieves a list of available serial ports with metadata. The `comName` must be guaranteed and all the other fields should be undefined if they are unavailable. The `comName` is either the path or an identifier (eg `COM1`) used to open the serialport.
* @method module:serialport~Binding#list
* @param {module:serialport~listCallback} callback
*/

/**
* Opens a connection to the serial port referenced by the path.
* @method module:serialport~Binding#open
* @param {string} path
* @param {module:serialport~openOptions} openOptions
* @param {module:serialport~errorCallback} openCallback - is called after the data has been passed to the operating system for writing. This will only be called when there isn't a pending write operation.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/

/**
* Closes an open connection
* @method module:serialport~Binding#close
* @param {module:serialport~errorCallback} callback Called once a connection is closed.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/

/**
* Request a number of bytes from the SerialPort. This function is similar to node's [`fs.read`](http://nodejs.org/api/fs.html#fs_fs_read_fd_buffer_offset_length_position_callback).
* @method module:serialport~Binding#read
* @param {buffer} data - Accepts a [`Buffer`](http://nodejs.org/api/buffer.html) object.
* @params {integer} offset - is the offset in the buffer to start writing at.
* @param {integer} length - specifying the maximum number of bytes to read.
* @param {module:serialport~readCallback} readCallback - is called after a read operation
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/

/**
* A callback called with an error or null.
* @typedef {function} module:serialport~readCallback
* @param {?error} error
* @param {integer} bytesRead - the number of bytes that have been written into the buffer
* @param {buffer} buffer - the buffer that data was written into, same object that was passed into `read`.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/

/**
* Write a number of bytes to the SerialPort
* @method module:serialport~Binding#write
* @param {buffer} data - Accepts a [`Buffer`](http://nodejs.org/api/buffer.html) object.
* @param {module:serialport~errorCallback} writeCallback - is called after the data has been passed to the operating system for writing. This will only be called when there isn't a pending write operation.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/

/**
* Changes connection settings on an open port. Currently only the baudRate is required.
* @method module:serialport~Binding#update
* @param {object=} options Only `baudRate` is currently supported
* @param {number=} [options.baudRate] If provided a baudRate that isn't supported by the bindings it should pass an error to the callback
* @param {module:serialport~errorCallback} [callback] Called once the port's baud rate has been changed.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/

/**
* Set control flags on an open port.
* @method module:serialport~Binding#set
* @param {object=} options All options are operating system default when the port is opened. Every flag is set on each call to the provided or default values. All options will always be provided.
* @param {Boolean} [options.brk=false]
* @param {Boolean} [options.cts=false]
* @param {Boolean} [options.dsr=false]
* @param {Boolean} [options.dtr=true]
* @param {Boolean} [options.rts=true]
* @param {module:serialport~errorCallback} callback Called once the port's flags have been set.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/

/**
* Get the control flags (CTS, DSR, DCD) on the open port.
* @method module:serialport~Binding#get
* @param {module:serialport~modemBitsCallback=} callback Called once the flags have been retrieved.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/

/**
* Flush (discard) data received but not read and written but not transmitted.
* @method module:serialport~Binding#flush
* @param {module:serialport~errorCallback} callback Called once the flush operation finishes.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/

/**
* Drain waits until all output data has been transmitted to the serial port.
* @method module:serialport~Binding#drain
* @param {module:serialport~errorCallback} callback Called once the drain operation finishes.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/
210 changes: 210 additions & 0 deletions lib/bindings/base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
'use strict';

/**
* @module serialport
*/

/**
* @name module:serialport.Binding
* @type {module:serialport~BaseBinding}
* @since 5.0.0
* @description The Binding is how node SerialPort talks to the underlying system. By default we auto detect windows, Linux and OSX and load the appropriate module for your system. You can assign `SerialPort.Binding` to any backend you like. You can find more by searching on [npm](https://npmjs.org/).
You can also avoid auto loading the default backends by requiring SerialPort with
```js
var SerialPort = require('serialport/lib/serialport');
SerialPort.Binding = MyBindingClass;
```
*/

/**
* You wont ever have to use Binding objects directly they'll be used by SerialPort to access the underlying hardware. This documentation is geared towards people making bindings for different platforms. This class can be inherited from to get type checking for each method.
* @class
* @param {object} options
* @param {function} options.disconnect - function to be called when the bindings have detected a disconnected port. This function should be called during any operation instead of that operations usual callback. The `SerialPort` class will attempt to call `close` after a disconnection and ignore any errors.
* @property {boolean} isOpen Required property. `true` if the port is open, `false` otherwise. Should be read only.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
* @since 5.0.0
*/
class BaseBinding {

/**
* Retrieves a list of available serial ports with metadata. The `comName` must be guaranteed and all the other fields should be undefined if they are unavailable. The `comName` is either the path or an identifier (eg `COM1`) used to open the serialport.
* @returns {Promise} resolves to an array of port [info objects](#module_serialport--SerialPort.list).
*/
static list() {
return Promise.resolve();
}

constructor(opt) {
if (typeof opt !== 'object') {
throw new TypeError('"options" is not an object');
}
if (typeof opt.disconnect !== 'function') {
throw new TypeError('"options.disconnect" is not a function');
}
}

/**
* Opens a connection to the serial port referenced by the path.
* @param {string} path
* @param {module:serialport~openOptions} openOptions
* @returns {Promise} Resolves after the port has been opened and configured.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/
open(path, options) {
if (!path) {
throw new TypeError('"path" is not a valid port');
}

if (typeof options !== 'object') {
throw new TypeError('"options" is not an object');
}

if (this.isOpen) {
return Promise.reject(new Error('Already open'));
}
return Promise.resolve();
}

/**
* Closes an open connection
* @returns {Promise} Resolves once the connection is closed.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/
close() {
if (!this.isOpen) {
return Promise.reject(new Error('Port is not open'));
}
return Promise.resolve();
}

/**
* Request a number of bytes from the SerialPort. This function is similar to node's [`fs.read`](http://nodejs.org/api/fs.html#fs_fs_read_fd_buffer_offset_length_position_callback).
* @param {buffer} data - Accepts a [`Buffer`](http://nodejs.org/api/buffer.html) object.
* @params {integer} offset - is the offset in the buffer to start writing at.
* @param {integer} length - specifying the maximum number of bytes to read.
* @returns {Promise} Resolves with the number of bytes read after a read operation.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/
read(buffer, offset, length) {
if (!Buffer.isBuffer(buffer)) {
throw new TypeError('"buffer" is not a Buffer');
}

if (typeof offset !== 'number') {
throw new TypeError('"offset" is not an integer');
}

if (typeof length !== 'number') {
throw new TypeError('"length" is not an integer');
}

if (buffer.length < offset + length) {
return Promise.reject(new Error('buffer is too small'));
}

if (!this.isOpen) {
return Promise.reject(new Error('Port is not open'));
}
return Promise.resolve();
}

/**
* Write a number of bytes to the SerialPort This will only be called when there isn't a pending write operation.
* @param {buffer} data - Accepts a [`Buffer`](http://nodejs.org/api/buffer.html) object.
* @returns {Promise} Resolves after the data has been passed to the operating system for writing.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/
write(buffer) {
if (!Buffer.isBuffer(buffer)) {
throw new TypeError('"buffer" is not a Buffer');
}

if (!this.isOpen) {
return Promise.reject(new Error('Port is not open'));
}
return Promise.resolve();
}

/**
* Changes connection settings on an open port. Currently only the baudRate is required.
* @param {object=} options Only `baudRate` is currently supported
* @param {number=} [options.baudRate] If provided a baudRate that isn't supported by the bindings it should pass an error to the callback
* @returns {Promise} Resolves once the port's baud rate has been changed.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/
update(options) {
if (typeof options !== 'object') {
throw TypeError('"options" is not an object');
}

if (typeof options.baudRate !== 'number') {
throw new TypeError('"options.baudRate" is not a number');
}

if (!this.isOpen) {
return Promise.reject(new Error('Port is not open'));
}
return Promise.resolve();
}

/**
* Set control flags on an open port.
* @param {object=} options All options are operating system default when the port is opened. Every flag is set on each call to the provided or default values. All options will always be provided.
* @param {Boolean} [options.brk=false]
* @param {Boolean} [options.cts=false]
* @param {Boolean} [options.dsr=false]
* @param {Boolean} [options.dtr=true]
* @param {Boolean} [options.rts=true]
* @returns {Promise} Resolves once the port's flags have been set.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/
set(options) {
if (typeof options !== 'object') {
throw new TypeError('"options" is not an object');
}

if (!this.isOpen) {
return Promise.reject(new Error('Port is not open'));
}
return Promise.resolve();
}

/**
* Get the control flags (CTS, DSR, DCD) on the open port.
* @returns {Promise} Resolves with the flags that have been retrieved.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/
get() {
if (!this.isOpen) {
return Promise.reject(new Error('Port is not open'));
}
return Promise.resolve();
}

/**
* Flush (discard) data received but not read and written but not transmitted.
* @returns {Promise} Resolves once the flush operation finishes.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/
flush() {
if (!this.isOpen) {
return Promise.reject(new Error('Port is not open'));
}
return Promise.resolve();
}

/**
* Drain waits until all output data has been transmitted to the serial port.
* @returns {Promise} Resolves once the drain operation finishes.
* @throws {TypeError} When given invalid arguments a TypeError will be thrown.
*/
drain() {
if (!this.isOpen) {
return Promise.reject(new Error('Port is not open'));
}
return Promise.resolve();
}
}

module.exports = BaseBinding;
Loading

0 comments on commit 414057c

Please sign in to comment.