diff --git a/README.md b/README.md index 9487a9f24..93fbee1a5 100644 --- a/README.md +++ b/README.md @@ -160,8 +160,8 @@ npm rebuild --build-from-source Opening a serial port: ```js -var SerialPort = require("serialport").SerialPort -var serialPort = new SerialPort("/dev/tty-usbserial1", { +var SerialPort = require("serialport"); +var port = new SerialPort("/dev/tty-usbserial1", { baudrate: 57600 }); ``` @@ -181,7 +181,7 @@ Constructing a `SerialPort` object will open a port, eventually. You can bind ev ```js -var SerialPort = require('serialport').SerialPort; +var SerialPort = require('serialport'); var port = new SerialPort('/dev/tty-usbserial1'); port.on('open', function () { @@ -196,7 +196,7 @@ port.on('open', function () { This could be moved to the constructor's callback. ```js -var SerialPort = require('serialport').SerialPort; +var SerialPort = require('serialport'); var port = new SerialPort('/dev/tty-usbserial1', function () { port.write('main screen turn on', function(err) { if (err) { @@ -210,7 +210,7 @@ var port = new SerialPort('/dev/tty-usbserial1', function () { When disabling the `openImmediately` flag you'll need to open the port on your own. Note, in order to disable the `openImmediately` flag, we have to pass an options object. ```js -var SerialPort = require('serialport').SerialPort; +var SerialPort = require('serialport'); var port = new SerialPort('/dev/tty-usbserial1', {}, false); port.open(function (err) { @@ -246,8 +246,8 @@ Retrieves a list of available serial ports with metadata. ``` ```js -var serialPort = require('serialport'); -serialPort.list(function (err, ports) { +var SerialPort = require('serialport'); +SerialPort.list(function (err, ports) { ports.forEach(function(port) { console.log(port.comName); console.log(port.pnpId); @@ -261,22 +261,20 @@ serialPort.list(function (err, ports) { 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; +var SerialPort = require('serialport'); var port = new SerialPort('/dev/tty-usbserial1', { - parser: serialport.parsers.readline('\n') + 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; +var SerialPort = require('serialport'); var port = new SerialPort('/dev/tty-usbserial1', { - parser: serialport.parsers.raw + parser: SerialPort.parsers.raw }); ``` @@ -300,9 +298,9 @@ Enjoy and do cool things with this code. ## Methods -### SerialPort (path, options, openImmediately, callback) +### SerialPort (path, options, openImmediately, openCallback) -Create a new serial port on `path`. +Create a new serial port on `path`. In the case of invalid arguments or invalid options constructing a new serialport will throw an error. If `openImmediately` is true (the default) the `openCallback` will be passed to `.open()` **_path_** @@ -333,7 +331,7 @@ These properties are ignored for windows. An object with the following propertie **_openImmediately (optional)_** -Attempts to open a connection to the serial port on `process.nextTick`. The default is `true`. Set to `false` to manually call `open()` at a later time, but note you'll need to use factory error listener in the case of constructor errors. +Attempts to open a connection to the serial port on `process.nextTick`. The default is `true`. If you've provided a `openCallback` it will be given to `open()`. Set to `false` to manually call `open()`. **_callback (optional)_** @@ -435,7 +433,7 @@ Called once the port's flags have been set. `results` are the return of the unde ### .update (options, callback) -Changes the baudrate for an open port. Doesn't yet work on windows. +Changes the baudrate for an open port. Throws if you provide a bad argument. Emits an error or calls the callback if the baud rate isn't supported. Doesn't yet work on windows. **_options_** diff --git a/bin/serialport-terminal.js b/bin/serialport-terminal.js index cde50b124..312b3b424 100755 --- a/bin/serialport-terminal.js +++ b/bin/serialport-terminal.js @@ -1,7 +1,7 @@ #!/usr/bin/env node 'use strict'; -var serialport = require('../'); +var SerialPort = require('../'); var version = require('../package.json').version; var args = require('commander'); @@ -21,7 +21,7 @@ args .parse(process.argv); function listPorts() { - serialport.list(function(err, ports) { + SerialPort.list(function(err, ports) { if (err) { console.error('Error listing ports', err); } else { @@ -49,7 +49,7 @@ var openOptions = { stopBits: args.stopbits }; -var port = new serialport.SerialPort(args.port, openOptions); +var port = new SerialPort(args.port, openOptions); process.stdin.resume(); process.stdin.setRawMode(true); diff --git a/examples/drain.js b/examples/drain.js index 2090ece28..c342774c2 100644 --- a/examples/drain.js +++ b/examples/drain.js @@ -1,6 +1,6 @@ 'use strict'; -var SerialPort = require('serialport').SerialPort; +var SerialPort = require('serialport'); var port = new SerialPort('/dev/cu.Cubelet-RGB'); port.on('open', function() { diff --git a/examples/opening.js b/examples/opening.js index 03c2b5fd3..063d905b1 100644 --- a/examples/opening.js +++ b/examples/opening.js @@ -2,7 +2,7 @@ // Open event example -// var SerialPort = require('serialport').SerialPort; +// var SerialPort = require('serialport'); // var port = new SerialPort('/dev/tty-usbserial1'); // port.on('open', function () { @@ -18,7 +18,7 @@ // Constructor callback example -// var SerialPort = require('serialport').SerialPort; +// var SerialPort = require('serialport'); // var port = new SerialPort('/dev/tty-usbserial1', function () { // port.write('main screen turn on', function(err) { // if (err) { @@ -30,7 +30,7 @@ // When disabling open immediately. -// var SerialPort = require('serialport').SerialPort; +// var SerialPort = require('serialport'); // var port = new SerialPort('/dev/tty-usbserial1', {}, false); // port.open(function (err) { diff --git a/lib/serialport.js b/lib/serialport.js index 12174f87e..198fcb272 100644 --- a/lib/serialport.js +++ b/lib/serialport.js @@ -17,16 +17,10 @@ var SerialPortBinding = require('./bindings'); var parsers = require('./parsers'); // Built-ins Dependencies -var EventEmitter = require('events').EventEmitter; var fs = require('fs'); var stream = require('stream'); var util = require('util'); -// Setup the factory -var factory = new EventEmitter(); -factory.parsers = parsers; -factory.list = SerialPortBinding.list; - // VALIDATION ARRAYS var DATABITS = [5, 6, 7, 8]; var STOPBITS = [1, 1.5, 2]; @@ -96,41 +90,37 @@ function SerialPort(path, options, openImmediately, callback) { } stream.Stream.call(this); - callback = callback || function(err) { - if (err) { - if (this._events.error) { - this.emit('error', err); - } else { - factory.emit('error', err); - } - } - }.bind(this); if (!path) { - return callback(new Error('Invalid port specified: ' + path)); + throw new TypeError('No path specified'); } + this.path = path; var correctedOptions = correctOptions(options); var settings = assign({}, defaultSettings, correctedOptions); + if (typeof settings.baudRate !== 'number') { + throw new TypeError('Invalid "baudRate" must be a number got: ' + settings.baudRate); + } + if (DATABITS.indexOf(settings.dataBits) === -1) { - return callback(new Error('Invalid "databits": ' + settings.dataBits)); + throw new TypeError('Invalid "databits": ' + settings.dataBits); } if (STOPBITS.indexOf(settings.stopBits) === -1) { - return callback(new Error('Invalid "stopbits": ' + settings.stopbits)); + throw new TypeError('Invalid "stopbits": ' + settings.stopbits); } if (PARITY.indexOf(settings.parity) === -1) { - return callback(new Error('Invalid "parity": ' + settings.parity)); + throw new TypeError('Invalid "parity": ' + settings.parity); } - for (var i = FLOWCONTROLS.length - 1; i >= 0; i--) { - if (typeof settings[FLOWCONTROLS[i]] !== 'boolean') { - return callback(new Error('Invalid "' + FLOWCONTROLS[i] + '" is not boolean')); + FLOWCONTROLS.forEach(function(control) { + if (typeof settings[control] !== 'boolean') { + throw new TypeError('Invalid "' + control + '" is not boolean'); } - } + }); // TODO remove this option settings.dataCallback = options.dataCallback || function(data) { @@ -162,13 +152,11 @@ function SerialPort(path, options, openImmediately, callback) { this.options = settings; if (openImmediately) { - process.nextTick(function() { - this.open(callback); - }.bind(this)); + // is nextTick necessary? + process.nextTick(this.open.bind(this, callback)); } } -factory.SerialPort = SerialPort; util.inherits(SerialPort, stream.Stream); SerialPort.prototype._error = function(error, callback) { @@ -218,9 +206,6 @@ SerialPort.prototype.open = function(callback) { }.bind(this)); }; -// underlying code is written to update all options, but for now -// only baud is respected as I don't want to duplicate all the option -// verification code above SerialPort.prototype.update = function(options, callback) { if (!this.isOpen()) { debug('update attempted, but port is not open'); @@ -493,4 +478,19 @@ SerialPort.prototype.drain = function(callback) { }.bind(this)); }; -module.exports = factory; +SerialPort.parsers = parsers; +SerialPort.list = SerialPortBinding.list; + +// Write a depreciation warning once +Object.defineProperty(SerialPort, 'SerialPort', { + get: function() { + console.warn('DEPRECATION: Please use `require(\'serialport\')` instead of `require(\'serialport\').SerialPort`'); + Object.defineProperty(SerialPort, 'SerialPort', { + value: SerialPort + }); + return SerialPort; + }, + configurable: true +}); + +module.exports = SerialPort; diff --git a/test/arduinoTest/integration.js b/test/arduinoTest/integration.js index 3b82e91cd..65d088d40 100644 --- a/test/arduinoTest/integration.js +++ b/test/arduinoTest/integration.js @@ -1,8 +1,7 @@ 'use strict'; var crypto = require('crypto'); var assert = require('chai').assert; -var serialPort = require('../../'); -var SerialPort = serialPort.SerialPort; +var SerialPort = require('../../'); var platform; switch (process.platform) { @@ -24,7 +23,7 @@ if (!testPort) { describe('SerialPort Integration tests', function() { it('.list', function(done) { - serialPort.list(function(err, ports) { + SerialPort.list(function(err, ports) { var foundPort = false; ports.forEach(function(port) { if (port.comName === testPort){ diff --git a/test/arduinoTest/serialDuplexTest.js b/test/arduinoTest/serialDuplexTest.js index d27419b88..8ea9d09a8 100755 --- a/test/arduinoTest/serialDuplexTest.js +++ b/test/arduinoTest/serialDuplexTest.js @@ -7,7 +7,7 @@ Tests the functionality of the serial port library. To be used in conjunction with the Arduino sketch ArduinoEcho.ino */ 'use strict'; -var SerialPort = require('../../').SerialPort; +var SerialPort = require('../../'); var args = require('commander'); args diff --git a/test/arduinoTest/stress.js b/test/arduinoTest/stress.js index bdaf5a6a4..f13b2529b 100644 --- a/test/arduinoTest/stress.js +++ b/test/arduinoTest/stress.js @@ -4,7 +4,7 @@ var assert = require('chai').assert; var util = require('util'); -var serialPort = require('../../'); +var SerialPort = require('../../'); require('colors'); // this modifies String.prototype // var fs = require('fs'); @@ -34,7 +34,7 @@ describe('the stress', function() { it("doesn't leak memory", function(done) { var data = new Buffer(1024); var hd = new memwatch.HeapDiff(); - var port = new serialPort.SerialPort(testPort, {}, false); + var port = new SerialPort(testPort, {}, false); port.on('close', done); var leaks = 0; @@ -87,7 +87,7 @@ describe('the stress', function() { // describe('of opening and closing ports', function() { // it("doesn't leak memory", function(done) { // var hd = new memwatch.HeapDiff(); - // var port = new serialPort.SerialPort(testPort, {}, false); + // var port = new SerialPort(testPort, {}, false); // memwatch.on('leak', function(info) { // // fs.appendFile('leak.log', util.inspect(info)); diff --git a/test/integration-lite.js b/test/integration-lite.js index 94b025b4b..a12ec4b75 100644 --- a/test/integration-lite.js +++ b/test/integration-lite.js @@ -3,8 +3,7 @@ // These tests require an empty serialport to exist. Nothing needs to respond on the other end. var assert = require('chai').assert; -var serialPort = require('../'); -var SerialPort = serialPort.SerialPort; +var SerialPort = require('../'); var platform; switch (process.platform) { @@ -39,7 +38,7 @@ describe('SerialPort light integration', function() { }); it('.list', function(done) { - serialPort.list(done); + SerialPort.list(done); }); // Be careful to close the ports when you're done with them diff --git a/test/serialport.js b/test/serialport.js index 0162cf6da..1efe83c18 100644 --- a/test/serialport.js +++ b/test/serialport.js @@ -6,9 +6,8 @@ chai.use(require('chai-subset')); var assert = chai.assert; var expect = chai.expect; -var MockedSerialPort = require('./mocks/darwin-hardware'); -var SerialPort = MockedSerialPort.SerialPort; -var hardware = MockedSerialPort.hardware; +var SerialPort = require('./mocks/darwin-hardware'); +var hardware = SerialPort.hardware; var bindings = hardware.mockBinding; describe('SerialPort', function() { @@ -26,6 +25,12 @@ describe('SerialPort', function() { sandbox.restore(); }); + describe('Legacy Constructor', function() { + it('still works', function(done){ + this.port = new SerialPort.SerialPort('/dev/exists', done); + }); + }); + describe('Constructor', function() { it('opens the port immediately', function(done) { this.port = new SerialPort('/dev/exists', function(err) { @@ -39,15 +44,14 @@ describe('SerialPort', function() { port.on('open', done); }); - it('emits an error on the factory when erroring without a callback', function(done) { - MockedSerialPort.once('error', function(err) { + it('passes the error to the callback when an bad port is provided', function(done) { + this.port = new SerialPort('/bad/port', function(err) { assert.instanceOf(err, Error); done(); }); - this.port = new SerialPort('/bad/port'); }); - it('emits an error when an invalid port is provided', function(done) { + it('emits an error when an bad port is provided', function(done) { var port = new SerialPort('/bad/port'); port.once('error', function(err) { assert.instanceOf(err, Error); @@ -55,32 +59,67 @@ describe('SerialPort', function() { }); }); + it('throws an error when no port is provided', function(done) { + try { + this.port = new SerialPort(''); + } catch(err){ + assert.instanceOf(err, Error); + done(); + } + }); + + it('throws an error when given bad options even with a callback', function(done) { + try { + this.port = new SerialPort('/dev/exists', { baudRate: 'whatever'}, function() {}); + } catch(err){ + assert.instanceOf(err, Error); + done(); + } + }); + + it('errors with a non number baudRate', function(done) { + try { + this.port = new SerialPort('/bad/port', { baudRate: 'whatever'}); + } catch(err){ + assert.instanceOf(err, Error); + done(); + } + }); + it('errors with invalid databits', function(done) { - this.port = new SerialPort('/dev/exists', { databits: 19 }, false, function(err) { + try { + this.port = new SerialPort('/dev/exists', { databits: 19 }); + } catch(err){ assert.instanceOf(err, Error); done(); - }); + } }); it('errors with invalid stopbits', function(done) { - this.port = new SerialPort('/dev/exists', { stopbits: 19 }, function(err) { + try { + this.port = new SerialPort('/dev/exists', { stopbits: 19 }); + } catch(err){ assert.instanceOf(err, Error); done(); - }); + } }); it('errors with invalid parity', function(done) { - this.port = new SerialPort('/dev/exists', { parity: 'pumpkins' }, false, function(err) { + try { + this.port = new SerialPort('/dev/exists', { parity: 'pumpkins' }); + } catch(err){ assert.instanceOf(err, Error); done(); - }); + } }); it('errors with invalid flow control', function(done) { - this.port = new SerialPort('/dev/exists', { xon: 'pumpkins' }, false, function(err) { + try { + this.port = new SerialPort('/dev/exists', { xon: 'pumpkins' }); + } catch(err){ assert.instanceOf(err, Error); done(); - }); + } }); it('sets valid flow control individually', function(done) {