Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SerialPort Streams2 Implementation #431

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a035a24
Initial commit
joshperry Dec 31, 2014
dd9e638
Replace deprecated
joshperry Dec 31, 2014
26029d3
Opening and constructing
joshperry Jan 1, 2015
2504d3e
Merge remote-tracking branch 'upstream/master' into streams2
joshperry Jan 1, 2015
f5ef189
Fix dependency
joshperry Jan 1, 2015
040abe5
Test options, change from sandboxed to proxyquire
joshperry Jan 1, 2015
5d7649f
Get platform from the `os` module
joshperry Jan 1, 2015
87e103a
Goodbye parsers
joshperry Jan 3, 2015
addd918
Work on opening port
joshperry Jan 3, 2015
56c829b
Fix line endings
joshperry Jan 3, 2015
118b393
Initial read logic, need tests
joshperry Jan 6, 2015
9142964
Fix buffer math
joshperry Jan 6, 2015
153467b
Modify terminal bin to use new code
joshperry Jan 6, 2015
5bded04
Convert terminal to use piped streams
joshperry Jan 6, 2015
ee743a8
Initial read/write tests and impl
joshperry Jan 6, 2015
9bd2b65
Fix case insensitive options
joshperry Jan 6, 2015
59b4f38
Elide transform code in core
joshperry Jan 7, 2015
4f23328
Bump major rev
joshperry Jan 9, 2015
e9218ca
Windows fixes
joshperry Jan 14, 2015
23e1c56
private host v2 binaries for now
joshperry Jan 14, 2015
de6ceab
Begin updating readme
joshperry Feb 27, 2015
22a33ea
Multiple serial ports will now have their own write queue and thread.
giseburt Dec 15, 2014
1912fee
Minor tweaks to close handling of write queue.
giseburt Dec 15, 2014
30e72df
Temporarily removing cleanup on close.
giseburt Dec 16, 2014
db20b77
Fixed uninitialized pointer.
giseburt Dec 19, 2014
ddef966
Merge multi write buf patch
joshperry Feb 28, 2015
ca42d15
Add close() functionality
joshperry Jun 16, 2015
20141e3
Set hardware flowcontrol when rtscts is true
joshperry Jun 16, 2015
fc1dad0
Version bump
joshperry Jun 16, 2015
cd86856
Nan v2 and Node v4 support
joshperry Sep 26, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 4 additions & 35 deletions .jshintrc
Original file line number Diff line number Diff line change
@@ -1,43 +1,12 @@
{
// Whether the scan should stop on first error.
"passfail": false,
// Maximum errors before stopping.
"maxerr": 100,


// Predefined globals

// Whether the standard browser globals should be predefined.
"browser": false,
// Whether the Node.js environment globals should be predefined.
"node": true,
// Whether the Rhino environment globals should be predefined.
"rhino": false,
// Whether CouchDB globals should be predefined.
"couch": false,
// Whether the Windows Scripting Host environment globals should be predefined.
"wsh": false,

// Whether jQuery globals should be predefined.
"jquery": false,
// Whether Prototype and Scriptaculous globals should be predefined.
"prototypejs": false,
// Whether MooTools globals should be predefined.
"mootools": false,
// Whether Dojo Toolkit globals should be predefined.
"dojo": false,

// Custom predefined globals.
"predef": [],

// Development

// Whether debugger statements should be allowed.
"debug": false,
// Whether logging globals should be predefined (console, alert, etc.).
"devel": false,


// ECMAScript 5

// Whether the "use strict"; pragma should be required.
Expand All @@ -51,7 +20,7 @@
// Whether automatic semicolon insertion should be allowed.
"asi": false,
// Whether line breaks should not be checked, e.g. `return [\n] x`.
"laxbreak": false,
"laxbreak": true,
// Whether bitwise operators (&, |, ^, etc.) should be forbidden.
"bitwise": false,
// Whether assignments inside `if`, `for` and `while` should be allowed. Usually
Expand Down Expand Up @@ -113,13 +82,13 @@
// Whether only function scope should be used for scope tests.
"funcscope": false,
// Whether es.next specific syntax should be allowed.
"esnext": false,
"esnext": true,


// Style preferences

// Whether constructor names must be capitalized.
"newcap": false,
"newcap": true,
// Whether empty blocks should be forbidden.
"noempty": false,
// Whether using `new` for side-effects should be forbidden.
Expand Down Expand Up @@ -151,5 +120,5 @@
// Maximum number of statements per function.
"maxstatements": 25,
// Maximum cyclomatic complexity.
"maxcomplexity": 6
"maxcomplexity": 10
}
46 changes: 30 additions & 16 deletions Gruntfile.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,45 @@
'use strict';
module.exports = function(grunt) {

require('jit-grunt')(grunt, {});

grunt.initConfig({
mochaTest: {
test: {
options: { reporter: 'spec' },
options: {
reporter: 'spec',
clearRequireCache: true
},
src: ['test/**/*.js']
}
},
jshint: {
all: ['*.js', 'test/**/*.js', 'arduinoTest/**/*.js'],
all: ['*.js', 'transforms/*.js', 'test/**/*.js', 'arduinoTest/**/*.js'],
options: {
node: true,
'-W030': true, // to allow mocha expects syntax
globals: {
before: false,
after: false,
beforeEach: false,
afterEach: false,
describe: false,
it: false
}
jshintrc: true
}
},
watch: {
javascripts: {
options: {
spawn: false
},
files: [ '*.js', 'transforms/*.js', 'test/**/*.js' ],
tasks: ['jshint', 'mochaTest']
}
}
});

// On watch events, if the changed file is a test file then configure mochaTest to only
// run the tests from that file. Otherwise run all the tests
var defaultTestSrc = grunt.config('mochaTest.test.src');
grunt.event.on('watch', function(action, filepath) {
if (filepath.match('test/')) {
grunt.config('mochaTest.test.src', ['test/global.js', filepath]);
} else {
grunt.config('mochaTest.test.src', defaultTestSrc);
}
});

grunt.loadNpmTasks('grunt-mocha-test');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.registerTask('default', ['jshint', 'mochaTest']);

};
};
142 changes: 30 additions & 112 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,87 +144,74 @@ npm install serialport
npm install serialport
```


To Use
------

Opening a serial port:

```js
var SerialPort = require("serialport").SerialPort
var serialPort = new SerialPort("/dev/tty-usbserial1", {
baudrate: 57600
});
var serialPorts = require("serialport");
var serialPort = serialPorts.open({ comname: "/dev/tty-usbserial1", baudrate: 57600 });
```

When opening a serial port, you can specify (in this order).
If you happen to be using the default settings of 9600,8,N,1 then you can just put the comname as the only parameter:

1. Path to Serial Port - required.
1. Options - optional and described below.
```js
var serialPort = serialPorts.open('/dev/tty-usbserial1');
```

The options object allows you to pass named options to the serial port during initialization. The valid attributes for the options object are the following:
The options object allows you to pass named options to the serial port during initialization. The options are optional and have default values, except for `comName` which must always be specified. The valid attributes for the options object are the following:

* comname: *Required* The name of the serial port. On Mac/Linux it will be something like `/dev/tty-usbserial1`. On Windows it will be something like `COM3`.
* baudrate: Baud Rate, defaults to 9600. Should be one of: 115200, 57600, 38400, 19200, 9600, 4800, 2400, 1800, 1200, 600, 300, 200, 150, 134, 110, 75, or 50. Custom rates as allowed by hardware is supported.
* databits: Data Bits, defaults to 8. Must be one of: 8, 7, 6, or 5.
* stopbits: Stop Bits, defaults to 1. Must be one of: 1 or 2.
* parity: Parity, defaults to 'none'. Must be one of: 'none', 'even', 'mark', 'odd', 'space'
* buffersize: Size of read buffer, defaults to 255. Must be an integer value.
* parser: The parser engine to use with read data, defaults to rawPacket strategy which just emits the raw buffer as a "data" event. Can be any function that accepts EventEmitter as first parameter and the raw buffer as the second parameter.

**Note, we have added support for either all lowercase OR camelcase of the options (thanks @jagautier), use whichever style you prefer.**
**Note, the options are completely case-insensitive `baudrate == baudRate == BaUdraTe`.**


It's a Stream!
--------------

open event
The serial port object implements a Node `Duplex` (read/write) stream. This means that all the documentation and libraries for working with other streams in Node, like `Socket`, will also work with your minty-fresh `SerialPort`.

Take a look at the [Node Streams documentation](http://nodejs.org/api/stream.html) for an in-depth treatment.


Opening
----------
If you want to know when the port successfully opens, you can listen to the `open` event. Any reads or writes that happen before the `open` event fires will be buffered and carried out once the open successfully completes.

You MUST wait for the open event to be emitted before reading/writing to the serial port. The open happens asynchronously so installing 'data' listeners and writing
before the open event might result in... nothing at all.
A shortcut for listening for the `open` event is to pass a function as the second parameter to `open()`. This function will be called only once when the port has been openned successfully.

Assuming you are connected to a serial console, you would for example:

```js
serialPort.on("open", function () {
console.log('open');
serialPort.on('data', function(data) {
console.log('data received: ' + data);
});
serialPort.write("ls\n", function(err, results) {
console.log('err ' + err);
console.log('results ' + results);
});
var serialPort = serialPorts.open('/dev/tty-usbserial1', function() {
console.log('Hey everyone, my serial port is open!');
});
```

You can also call the open function, in this case instanciate the serialport with an additional flag.
For advanced use-cases (none of which I can think of right now) you can new up the `SerialPort` object and call `open()` on it yourself. Note that you will get errors if you attempt to `write()` before you have called `open()` on your instance; once you've called `open()`, it's fair game.

```js
var SerialPort = require("serialport").SerialPort
var serialPort = new SerialPort("/dev/tty-usbserial1", {
baudrate: 57600
}, false); // this is the openImmediately flag [default is true]

serialPort.open(function (error) {
if ( error ) {
console.log('failed to open: '+error);
} else {
console.log('open');
serialPort.on('data', function(data) {
console.log('data received: ' + data);
});
serialPort.write("ls\n", function(err, results) {
console.log('err ' + err);
console.log('results ' + results);
});
}
var serialPort = new SerialPort({ comname: '/dev/tty-usbserial1', baudrate: 57600 }, function() {
console.log('Hey everyone, I opened my own SerialPort instance!');
});
```


List Ports
----------

You can also list the ports along with some metadata as well.

```js
var serialPort = require("serialport");
serialPort.list(function (err, ports) {
var serialPorts = require("serialport");
serialPorts.list(function (err, ports) {
ports.forEach(function(port) {
console.log(port.comName);
console.log(port.pnpId);
Expand All @@ -233,47 +220,6 @@ serialPort.list(function (err, ports) {
});
```

Parsers
-------

Out of the box, node-serialport provides two parsers one that simply emits the raw buffer as a data event and the other which provides familiar "readline" style parsing. To use the readline parser, you must provide a delimiter as such:

```js
var serialport = require("serialport");
var SerialPort = serialport.SerialPort; // localize object constructor

var sp = new SerialPort("/dev/tty-usbserial1", {
parser: serialport.parsers.readline("\n")
});
```

To use the raw parser, you just provide the function definition (or leave undefined):

```js
var serialport = require("serialport");
var SerialPort = serialport.SerialPort; // localize object constructor

var sp = new SerialPort("/dev/tty-usbserial1", {
parser: serialport.parsers.raw
});
```


You can get updates of new data from the Serial Port as follows:

```js
serialPort.on("data", function (data) {
sys.puts("here: "+data);
});
```

You can write to the serial port by sending a string or buffer to the write method as follows:

```js
serialPort.write("OMG IT WORKS\r");
```

Enjoy and do cool things with this code.

Reference Guide
---------------
Expand Down Expand Up @@ -323,34 +269,6 @@ Attempts to open a connection to the serial port on `process.nextTick`. The defa

Called when a connection has been opened. The callback should be a function that looks like: `function (error) { ... }`

### .open (callback)

Opens a connection to the given serial port.

**_callback (optional)_**

Called when a connection has been opened. The callback should be a function that looks like: `function (error) { ... }`

### .write (buffer, callback)

Writes data to the given serial port.

**_buffer_**

The `buffer` parameter accepts a [`Buffer` ](http://nodejs.org/api/buffer.html) object, or a type that is accepted by the `Buffer` constructor (ex. an array of bytes or a string).

**_callback (optional)_**

Called once the write operation returns. The callback should be a function that looks like: `function (error) { ... }` _Note: The write operation is non-blocking. When it returns, data may still have not actually been written to the serial port. See `drain()`._

### .pause ()

Pauses an open connection.

### .resume ()

Resumes a paused connection.

### .flush (callback)

Flushes data received but not read. See [`tcflush()`](http://linux.die.net/man/3/tcflush) for Mac/Linux and [`FlushFileBuffers`](http://msdn.microsoft.com/en-us/library/windows/desktop/aa364439) for Windows.
Expand Down
13 changes: 13 additions & 0 deletions arduinoTest/.jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"extends": "../.jshintrc",

"globals": {
/* mocha defines */
"describe": true,
"it": true,
"before": true,
"beforeEach": true,
"after": true,
"afterEach": true
}
}
10 changes: 4 additions & 6 deletions arduinoTest/requiresComPort.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/*jslint node: true */
/*global describe, it */
"use strict";
'use strict';

var chai = require('chai');
var util = require('util');
Expand All @@ -16,7 +14,7 @@ describe ('requiresComPort', function() {
chai.assert.isDefined(ports, 'ports is not defined');
chai.assert.isTrue(ports.length > 0, 'no ports found');

var data = new Buffer("hello");
var data = new Buffer('hello');

var port = new serialPort.SerialPort(ports.slice(-1)[0].comName, null, false);
port.on('error', function(err) {
Expand Down Expand Up @@ -71,7 +69,7 @@ describe ('requiresComPort', function() {
chai.assert.isDefined(ports, 'ports is not defined');
chai.assert.isTrue(ports.length > 0, 'no ports found');

var data = new Buffer("hello");
var data = new Buffer('hello');

var port = new serialPort.SerialPort(ports.slice(-1)[0].comName, null, false);
port.on('error', function(err) {
Expand Down Expand Up @@ -117,4 +115,4 @@ describe ('requiresComPort', function() {
});
});

});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes are irrelevant.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Irrelevant unless you want the lint step in the build process to pass. It complains when there are mixed quotes, among other things.

Loading