function SerialPort(path, options, callback) {
if (typeof callback === 'boolean') {
throw new TypeError('`openImmediately` is now called `autoOpen` and is a property of options');
}
if (typeof options === 'function') {
callback = options;
options = {};
}
options = options || {};
stream.Stream.call(this);
if (!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) {
throw new TypeError('Invalid "databits": ' + settings.dataBits);
}
if (STOPBITS.indexOf(settings.stopBits) === -1) {
throw new TypeError('Invalid "stopbits": ' + settings.stopbits);
}
if (PARITY.indexOf(settings.parity) === -1) {
throw new TypeError('Invalid "parity": ' + settings.parity);
}
FLOWCONTROLS.forEach(function(control) {
if (typeof settings[control] !== 'boolean') {
throw new TypeError('Invalid "' + control + '" is not boolean');
}
});
settings.disconnectedCallback = this._disconnected.bind(this);
settings.dataCallback = settings.parser.bind(this, this);
this.fd = null;
this.paused = true;
this.opening = false;
this.closing = false;
if (process.platform !== 'win32') {
this.bufferSize = settings.bufferSize;
this.readable = true;
this.reading = false;
}
this.options = settings;
if (this.options.autoOpen) {
// is nextTick necessary?
process.nextTick(this.open.bind(this, callback));
}
}n/a
function listLinux(callback) {
callback = callback || function(err) {
if (err) { this.emit('error', err) }
}.bind(this);
return listUnix(callback);
}...
port.on('open', function() {
// open logic
});
```
### Listing Ports
`.list(callback)`
Retrieves a list of available serial ports with metadata.
* `callback` is a required function that looks should look like: `function (err, ports) { ... }`. `ports` will be an array of objects
with port info. Only the `comName` is guaranteed, all the other fields undefined if unavailable. The `comName` is either the path
or identifier (eg `COM1`) used to open the serialport.
```js
// example port information
...function Stream() {
EE.call(this);
}n/a
function SerialportPoller() { [native code] }n/a
function close() { [native code] }n/a
function drain() { [native code] }...
**Example**
Writes `data` and waits until it has finish transmitting to the target serial port before calling the callback.
```
function writeAndDrain (data, callback) {
sp.write(data, function () {
sp.drain(callback);
});
}
```
### .close (callback)
Closes an open connection.
...function flush() { [native code] }n/a
function listLinux(callback) {
callback = callback || function(err) {
if (err) { this.emit('error', err) }
}.bind(this);
return listUnix(callback);
}...
port.on('open', function() {
// open logic
});
```
### Listing Ports
`.list(callback)`
Retrieves a list of available serial ports with metadata.
* `callback` is a required function that looks should look like: `function (err, ports) { ... }`. `ports` will be an array of objects
with port info. Only the `comName` is guaranteed, all the other fields undefined if unavailable. The `comName` is either the path
or identifier (eg `COM1`) used to open the serialport.
```js
// example port information
...function open() { [native code] }...
1. Options - optional and described below.
### Opening a Port
Constructing a `SerialPort` object will open a port on `nextTick`. You can bind events while the port is opening but you must wait
until it is open to `write()` to it. (Most port functions require an open port.) You can call code when a port is opened in three
ways.
- The `open` event is always emitted when the port is opened
- The constructor's openCallback is passed to `.open()` when the `autoOpen` option
hasn't been disabled, if you have disabled it the callback is ignored.
- The `.open()` function takes a callback that is called after the port is opened. This can be used if you disabled the `autoOpen
` option or have previously closed an open port.
```js
var SerialPort = require('serialport');
var port = new SerialPort('/dev/tty-usbserial1');
...function set() { [native code] }n/a
function update() { [native code] }n/a
function write() { [native code] }...
```js
var SerialPort = require('serialport');
var port = new SerialPort('/dev/tty-usbserial1');
port.on('open', function() {
port.write('main screen turn on', function(err) {
if (err) {
return console.log('Error on write: ', err.message);
}
console.log('message written');
});
});
...byteDelimiter = function (delimiter) {
if (Object.prototype.toString.call(delimiter) !== '[object Array]') {
delimiter = [ delimiter ];
}
var buf = [];
var nextDelimIndex = 0;
return function(emitter, buffer) {
for (var i = 0; i < buffer.length; i++) {
buf[buf.length] = buffer[i];
if (buf[buf.length - 1] === delimiter[nextDelimIndex]) {
nextDelimIndex++;
}
if (nextDelimIndex === delimiter.length) {
emitter.emit('data', buf);
buf = [];
nextDelimIndex = 0;
}
}
};
}...
Note that the raw parser does not guarantee that all data it receives will come in a single event.
To use the byte sequence parser, you must provide a delimiter as an array of bytes:
```js
var SerialPort = require('serialport');
var port = new SerialPort('/dev/tty-usbserial1', {
parser: SerialPort.parsers.byteDelimiter([10,13])
});
```
To use the byte length parser, you must provide a delimiter as a length in bytes:
```js
var SerialPort = require('serialport');
...byteLength = function (length) {
var data = new Buffer(0);
return function(emitter, buffer) {
data = Buffer.concat([data, buffer]);
while (data.length >= length) {
var out = data.slice(0, length);
data = data.slice(length);
emitter.emit('data', out);
}
};
}...
```
To use the byte length parser, you must provide a delimiter as a length in bytes:
```js
var SerialPort = require('serialport');
var port = new SerialPort('/dev/tty-usbserial1', {
parser: SerialPort.parsers.byteLength(5)
});
```
You can get updates of new data from the Serial Port as follows:
```js
port.on('data', function (data) {
...raw = function (emitter, buffer) {
emitter.emit('data', buffer);
}n/a
readline = function (delimiter, encoding) {
if (typeof delimiter === 'undefined' || delimiter === null) { delimiter = '\r' }
if (typeof encoding === 'undefined' || encoding === null) { encoding = 'utf8' }
// Delimiter buffer saved in closure
var data = '';
return function(emitter, buffer) {
// Collect data
data += buffer.toString(encoding);
// Split collected data by delimiter
var parts = data.split(delimiter);
data = parts.pop();
parts.forEach(function(part) {
emitter.emit('data', part);
});
};
}...
To use the readline parser, you must provide a delimiter as such:
```js
var SerialPort = require('serialport');
var port = new SerialPort('/dev/tty-usbserial1', {
parser: SerialPort.parsers.readline('\n')
});
```
To use the raw parser don't specify any parser, however if you really want to you can:
```js
var SerialPort = require('serialport');
...function SerialPort(path, options, callback) {
if (typeof callback === 'boolean') {
throw new TypeError('`openImmediately` is now called `autoOpen` and is a property of options');
}
if (typeof options === 'function') {
callback = options;
options = {};
}
options = options || {};
stream.Stream.call(this);
if (!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) {
throw new TypeError('Invalid "databits": ' + settings.dataBits);
}
if (STOPBITS.indexOf(settings.stopBits) === -1) {
throw new TypeError('Invalid "stopbits": ' + settings.stopbits);
}
if (PARITY.indexOf(settings.parity) === -1) {
throw new TypeError('Invalid "parity": ' + settings.parity);
}
FLOWCONTROLS.forEach(function(control) {
if (typeof settings[control] !== 'boolean') {
throw new TypeError('Invalid "' + control + '" is not boolean');
}
});
settings.disconnectedCallback = this._disconnected.bind(this);
settings.dataCallback = settings.parser.bind(this, this);
this.fd = null;
this.paused = true;
this.opening = false;
this.closing = false;
if (process.platform !== 'win32') {
this.bufferSize = settings.bufferSize;
this.readable = true;
this.reading = false;
}
this.options = settings;
if (this.options.autoOpen) {
// is nextTick necessary?
process.nextTick(this.open.bind(this, callback));
}
}n/a
function listLinux(callback) {
callback = callback || function(err) {
if (err) { this.emit('error', err) }
}.bind(this);
return listUnix(callback);
}...
port.on('open', function() {
// open logic
});
```
### Listing Ports
`.list(callback)`
Retrieves a list of available serial ports with metadata.
* `callback` is a required function that looks should look like: `function (err, ports) { ... }`. `ports` will be an array of objects
with port info. Only the `comName` is guaranteed, all the other fields undefined if unavailable. The `comName` is either the path
or identifier (eg `COM1`) used to open the serialport.
```js
// example port information
...function Stream() {
EE.call(this);
}n/a
_disconnected = function (err) {
this.paused = true;
this.emit('disconnect', err);
if (this.closing) {
return;
}
if (this.fd === null) {
return;
}
this.closing = true;
if (process.platform !== 'win32') {
this.readable = false;
this.serialPoller.close();
}
SerialPortBinding.close(this.fd, function(err) {
this.closing = false;
if (err) {
debug('Disconnect close completed with error: ', err);
}
this.fd = null;
this.emit('close');
}.bind(this));
}n/a
_emitData = function (data) {
this.options.dataCallback(data);
}n/a
_error = function (error, callback) {
if (callback) {
callback.call(this, error);
} else {
this.emit('error', error);
}
}n/a
_read = function () {
if (!this.readable || this.paused || this.reading || this.closing) {
return;
}
this.reading = true;
if (!this.pool || this.pool.length - this.pool.used < kMinPoolSpace) {
// discard the old pool. Can't add to the free list because
// users might have references to slices on it.
this.pool = new Buffer(kPoolSize);
this.pool.used = 0;
}
// Grab another reference to the pool in the case that while we're in the
// thread pool another read() finishes up the pool, and allocates a new
// one.
var toRead = Math.min(this.pool.length - this.pool.used, ~~this.bufferSize);
var start = this.pool.used;
var _afterRead = function(err, bytesRead, readPool, bytesRequested) {
this.reading = false;
if (err) {
if (err.code && err.code === 'EAGAIN') {
if (this.isOpen()) {
this.serialPoller.start();
}
// handle edge case were mac/unix doesn't clearly know the error.
} else if (err.code && (err.code === 'EBADF' || err.code === 'ENXIO' || (err.errno === -1 || err.code === 'UNKNOWN'))) {
this._disconnected(err);
} else {
this.fd = null;
this.readable = false;
this.emit('error', err);
}
return;
}
// Since we will often not read the number of bytes requested,
// let's mark the ones we didn't need as available again.
this.pool.used -= bytesRequested - bytesRead;
if (bytesRead === 0) {
if (this.isOpen()) {
this.serialPoller.start();
}
} else {
var b = this.pool.slice(start, start + bytesRead);
// do not emit events if the stream is paused
if (this.paused) {
if (!this.buffer) {
this.buffer = new Buffer(0);
}
this.buffer = Buffer.concat([this.buffer, b]);
return;
}
this._emitData(b);
// do not emit events anymore after we declared the stream unreadable
if (!this.readable) {
return;
}
this._read();
}
}.bind(this);
fs.read(this.fd, this.pool, this.pool.used, toRead, null, function(err, bytesRead) {
var readPool = this.pool;
var bytesRequested = toRead;
_afterRead(err, bytesRead, readPool, bytesRequested);
}.bind(this));
this.pool.used += toRead;
}n/a
close = function (callback) {
this.paused = true;
if (this.closing) {
debug('close attempted, but port is already closing');
return this._error(new Error('Port is not open'), callback);
}
if (!this.isOpen()) {
debug('close attempted, but port is not open');
return this._error(new Error('Port is not open'), callback);
}
this.closing = true;
// Stop polling before closing the port.
if (process.platform !== 'win32') {
this.readable = false;
this.serialPoller.close();
}
SerialPortBinding.close(this.fd, function(err) {
this.closing = false;
if (err) {
debug('SerialPortBinding.close had an error', err);
return this._error(err, callback);
}
this.fd = null;
this.emit('close');
if (callback) { callback.call(this, null) }
}.bind(this));
}n/a
drain = function (callback) {
if (!this.isOpen()) {
debug('drain attempted, but port is not open');
return this._error(new Error('Port is not open'), callback);
}
SerialPortBinding.drain(this.fd, function(err) {
if (err) {
debug('SerialPortBinding.drain had an error', err);
return this._error(err, callback);
}
if (callback) { callback.call(this, null) }
}.bind(this));
}...
**Example**
Writes `data` and waits until it has finish transmitting to the target serial port before calling the callback.
```
function writeAndDrain (data, callback) {
sp.write(data, function () {
sp.drain(callback);
});
}
```
### .close (callback)
Closes an open connection.
...flush = function (callback) {
if (!this.isOpen()) {
debug('flush attempted, but port is not open');
return this._error(new Error('Port is not open'), callback);
}
SerialPortBinding.flush(this.fd, function(err, result) {
if (err) {
debug('SerialPortBinding.flush had an error', err);
return this._error(err, callback);
}
if (callback) { callback.call(this, null, result) }
}.bind(this));
}n/a
isOpen = function () {
return this.fd !== null && !this.closing;
}...
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) { ... }`
### .isOpen()
Returns `true` if the port is open.
### .write (buffer, callback)
Writes data to the given serial port.
...open = function (callback) {
if (this.isOpen()) {
return this._error(new Error('Port is already open'), callback);
}
if (this.opening) {
return this._error(new Error('Port is opening'), callback);
}
this.paused = true;
this.readable = true;
this.reading = false;
this.opening = true;
SerialPortBinding.open(this.path, this.options, function(err, fd) {
this.opening = false;
if (err) {
debug('SerialPortBinding.open had an error', err);
return this._error(err, callback);
}
this.fd = fd;
this.paused = false;
if (process.platform !== 'win32') {
this.serialPoller = new SerialPortBinding.SerialportPoller(this.fd, function(err) {
if (!err) {
this._read();
} else {
this._disconnected(err);
}
}.bind(this));
this.serialPoller.start();
}
this.emit('open');
if (callback) { callback.call(this, null) }
}.bind(this));
}...
1. Options - optional and described below.
### Opening a Port
Constructing a `SerialPort` object will open a port on `nextTick`. You can bind events while the port is opening but you must wait
until it is open to `write()` to it. (Most port functions require an open port.) You can call code when a port is opened in three
ways.
- The `open` event is always emitted when the port is opened
- The constructor's openCallback is passed to `.open()` when the `autoOpen` option
hasn't been disabled, if you have disabled it the callback is ignored.
- The `.open()` function takes a callback that is called after the port is opened. This can be used if you disabled the `autoOpen
` option or have previously closed an open port.
```js
var SerialPort = require('serialport');
var port = new SerialPort('/dev/tty-usbserial1');
...pause = function () {
this.paused = true;
}n/a
resume = function () {
this.paused = false;
if (this.buffer) {
var buffer = this.buffer;
this.buffer = null;
this._emitData(buffer);
}
// No longer open?
if (!this.isOpen()) {
return;
}
this._read();
}n/a
set = function (options, callback) {
if (!this.isOpen()) {
debug('set attempted, but port is not open');
return this._error(new Error('Port is not open'), callback);
}
options = options || {};
if (!callback && typeof options === 'function') {
callback = options;
options = {};
}
var settings = {};
for (var i = SET_OPTIONS.length - 1; i >= 0; i--) {
var flag = SET_OPTIONS[i];
if (options[flag] !== undefined) {
settings[flag] = options[flag];
} else {
settings[flag] = defaultSetFlags[flag];
}
}
SerialPortBinding.set(this.fd, settings, function(err) {
if (err) {
debug('SerialPortBinding.set had an error', err);
return this._error(err, callback);
}
if (callback) { callback.call(this, null) }
}.bind(this));
}n/a
update = function (options, callback) {
if (!this.isOpen()) {
debug('update attempted, but port is not open');
return this._error(new Error('Port is not open'), callback);
}
var correctedOptions = correctOptions(options);
var settings = assign({}, defaultSettings, correctedOptions);
this.options.baudRate = settings.baudRate;
SerialPortBinding.update(this.fd, this.options, function(err) {
if (err) {
return this._error(err, callback);
}
if (callback) { callback.call(this, null) }
}.bind(this));
}n/a
write = function (buffer, callback) {
if (!this.isOpen()) {
debug('write attempted, but port is not open');
return this._error(new Error('Port is not open'), callback);
}
if (!Buffer.isBuffer(buffer)) {
buffer = new Buffer(buffer);
}
debug('write ' + buffer.length + ' bytes of data');
SerialPortBinding.write(this.fd, buffer, function(err) {
if (err) {
debug('SerialPortBinding.write had an error', err);
return this._error(err, callback);
}
if (callback) { callback.call(this, null) }
}.bind(this));
}...
```js
var SerialPort = require('serialport');
var port = new SerialPort('/dev/tty-usbserial1');
port.on('open', function() {
port.write('main screen turn on', function(err) {
if (err) {
return console.log('Error on write: ', err.message);
}
console.log('message written');
});
});
...