Skip to content

Commit c2e1f2e

Browse files
committed
Transform parsers into streams
Parsers are now transform streams! I'm not 100% convinced this is easier to use but it is more clear about the mechanics. I think that might make it worthwhile. It also opens up a clear example to how to make your own parser.
1 parent 71f7fb3 commit c2e1f2e

File tree

11 files changed

+527
-240
lines changed

11 files changed

+527
-240
lines changed

README.md

Lines changed: 60 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ For getting started with node-serialport, we recommend you begin with the follow
6565
* [`Event: "disconnect"`](#module_serialport--SerialPort+event_disconnect)
6666
* [`Event: "close"`](#module_serialport--SerialPort+event_close)
6767
* _static_
68-
* [`.parsers`](#module_serialport--SerialPort.parsers) : <code>object</code>
6968
* [`.list`](#module_serialport--SerialPort.list) : <code>function</code>
69+
* [`.parsers`](#module_serialport--SerialPort.parsers) : <code>object</code>
7070
* _inner_
7171
* [`~errorCallback`](#module_serialport--SerialPort..errorCallback) : <code>function</code>
7272
* [`~openOptions`](#module_serialport--SerialPort..openOptions) : <code>Object</code>
@@ -504,64 +504,6 @@ The `close` event's callback is called with no arguments when the port is closed
504504

505505
-
506506

507-
<a name="module_serialport--SerialPort.parsers"></a>
508-
509-
#### `SerialPort.parsers` : <code>object</code>
510-
Parsers will process incoming data in a variety of ways and are meant to be passed to a port during construction.
511-
512-
**Kind**: static property of <code>[SerialPort](#exp_module_serialport--SerialPort)</code>
513-
**Properties**
514-
515-
| Name | Type | Description |
516-
| --- | --- | --- |
517-
| raw | <code>function</code> | emits a raw buffer as a data event as it's received. This is the default parser. |
518-
| readline | <code>function</code> | returns a function that emits a string as a data event after a newline delimiter is received. |
519-
| byteLength | <code>function</code> | returns a function that emits a data event as a buffer after a specific number of bytes are received. |
520-
| byteDelimiter | <code>function</code> | returns a function that emits a data event each time a byte sequence (an array of bytes) is received. |
521-
522-
**Example**
523-
To use the readline parser, you must provide a delimiter as such:
524-
525-
```js
526-
var SerialPort = require('serialport');
527-
528-
var port = new SerialPort('/dev/tty-usbserial1', {
529-
parser: SerialPort.parsers.readline('\n')
530-
});
531-
```
532-
533-
To use the raw parser don't specify any parser, however if you really want to you can:
534-
535-
```js
536-
var SerialPort = require('serialport');
537-
538-
var port = new SerialPort('/dev/tty-usbserial1', {
539-
parser: SerialPort.parsers.raw
540-
});
541-
```
542-
543-
Note that the raw parser does not guarantee that all data it receives will come in a single event.
544-
545-
To use the byte sequence parser, you must provide a delimiter as an array of bytes:
546-
```js
547-
var SerialPort = require('serialport');
548-
549-
var port = new SerialPort('/dev/tty-usbserial1', {
550-
parser: SerialPort.parsers.byteDelimiter([10,13])
551-
});
552-
```
553-
554-
To use the byte length parser, you must provide a delimiter as a length in bytes:
555-
```js
556-
var SerialPort = require('serialport');
557-
558-
var port = new SerialPort('/dev/tty-usbserial1', {
559-
parser: SerialPort.parsers.byteLength(5)
560-
});
561-
```
562-
563-
-
564-
565507
<a name="module_serialport--SerialPort.list"></a>
566508

567509
#### `SerialPort.list` : <code>function</code>
@@ -601,6 +543,65 @@ SerialPort.list(function (err, ports) {
601543

602544
-
603545

546+
<a name="module_serialport--SerialPort.parsers"></a>
547+
548+
#### `SerialPort.parsers` : <code>object</code>
549+
Parsers are [Transform streams](https://nodejs.org/api/stream.html#stream_class_stream_transform) that will parse data in a variety of ways and can be used to process incoming data.
550+
551+
**Kind**: static property of <code>[SerialPort](#exp_module_serialport--SerialPort)</code>
552+
**Properties**
553+
554+
| Name | Type | Description |
555+
| --- | --- | --- |
556+
| ByteLength | <code>function</code> | is a transform stream that emits data each time a byte sequence is received. |
557+
| Delimiter | <code>function</code> | is a transform stream that emits data as a buffer after a specific number of bytes are received. |
558+
| ReadLine | <code>function</code> | is a transform stream that emits data after a newline delimiter is received. |
559+
560+
**Example**
561+
To use any of the parsers you need to create them and then pipe the serialport to the parser. Be sure not to write to the parser.
562+
```js
563+
var SerialPort = require('serialport');
564+
var port = new SerialPort('/dev/tty-usbserial1');
565+
var parser = new SerialPort.parsers.ReadLine();
566+
port.pipe(parser);
567+
parser.on('data', console.log);
568+
port.write('ROBOT PLEASE RESPOND\n');
569+
570+
// this can be shortened to
571+
var SerialPort = require('serialport');
572+
var parser = port.pipe(new SerialPort.parsers.ReadLine());
573+
parser.on('data', console.log);
574+
port.write('ROBOT PLEASE RESPOND\n');
575+
```
576+
577+
To use the byte length parser, you must provide the length of the number of bytes:
578+
```js
579+
var SerialPort = require('serialport');
580+
var port = new SerialPort('/dev/tty-usbserial1');
581+
var parser = port.pipe(new SerialPort.parsers.ByteLength({length: 8}));
582+
port.pipe(parser);
583+
parser.on('data', console.log);
584+
```
585+
586+
To use the Delimiter parser you must specify, you must provide a delimiter as a string, buffer, or an array of bytes:
587+
```js
588+
var SerialPort = require('serialport');
589+
var port = new SerialPort('/dev/tty-usbserial1');
590+
var parser = new SerialPort.parsers.Delimiter({delimiter: new Buffer('EOL')});
591+
port.pipe(parser);
592+
parser.on('data', console.log);
593+
```
594+
595+
To use the ReadLine parser, you must provide a delimiter as such:
596+
```js
597+
var SerialPort = require('serialport');
598+
var SerialPort = require('serialport');
599+
var parser = port.pipe(new SerialPort.parsers.ReadLine({delimiter: '\r\n'}));
600+
parser.on('data', console.log);
601+
```
602+
603+
-
604+
604605
<a name="module_serialport--SerialPort..errorCallback"></a>
605606

606607
#### `SerialPort~errorCallback` : <code>function</code>
@@ -634,7 +635,6 @@ A callback called with an error or null.
634635
| xoff | <code>boolean</code> | <code>false</code> | flow control setting |
635636
| xany | <code>boolean</code> | <code>false</code> | flow control setting |
636637
| bufferSize | <code>number</code> | <code>65536</code> | Size of read buffer |
637-
| parser | <code>function</code> | <code>Parsers.raw</code> | The parser to transform read data, defaults to the `raw` parser that emits data as it's received. |
638638
| platformOptions | <code>object</code> | | sets platform specific options |
639639
| platformOptions.vmin | <code>number</code> | <code>1</code> | see [`man termios`](http://linux.die.net/man/3/termios) |
640640
| platformOptions.vtime | <code>number</code> | <code>0</code> | see [`man termios`](http://linux.die.net/man/3/termios) |

lib/parser-byte-length.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict';
2+
var Transform = require('readable-stream').Transform;
3+
var inherits = require('inherits');
4+
5+
function ByteLengthParser(options) {
6+
if (!(this instanceof ByteLengthParser)) {
7+
return new ByteLengthParser(options);
8+
}
9+
Transform.call(this, options);
10+
11+
options = options || {};
12+
13+
if (typeof options.length !== 'number') {
14+
throw new TypeError('length is not a number');
15+
}
16+
17+
if (options.length < 1) {
18+
throw new TypeError('length is not greater than 0');
19+
}
20+
21+
this.length = options.length;
22+
this.buffer = new Buffer(0);
23+
}
24+
25+
inherits(ByteLengthParser, Transform);
26+
27+
ByteLengthParser.prototype._transform = function(chunk, encoding, cb) {
28+
var data = Buffer.concat([this.buffer, chunk]);
29+
while (data.length >= this.length) {
30+
var out = data.slice(0, this.length);
31+
this.push(out);
32+
data = data.slice(this.length);
33+
}
34+
this.buffer = data;
35+
cb();
36+
};
37+
38+
ByteLengthParser.prototype._flush = function(cb) {
39+
this.push(this.buffer);
40+
this.buffer = new Buffer(0);
41+
cb();
42+
};
43+
44+
45+
module.exports = ByteLengthParser;

lib/parser-delimiter.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
'use strict';
2+
var Transform = require('readable-stream').Transform;
3+
var inherits = require('inherits');
4+
var bindexOf;
5+
6+
if (typeof Buffer.prototype.indexOf === 'function') {
7+
bindexOf = function(buff, search, offset, encoding) {
8+
return buff.indexOf(search, offset, encoding);
9+
};
10+
} else {
11+
bindexOf = require('buffer-indexof');
12+
}
13+
14+
function DelimiterParser(options) {
15+
if (!(this instanceof DelimiterParser)) {
16+
return new DelimiterParser(options);
17+
}
18+
Transform.call(this, options);
19+
20+
options = options || {};
21+
22+
if (options.delimiter === undefined) {
23+
throw new TypeError('delimiter is not a bufferable object');
24+
}
25+
26+
if (options.delimiter.length === 0) {
27+
throw new TypeError('delimiter has a 0 or undefined length');
28+
}
29+
30+
this.delimiter = new Buffer(options.delimiter);
31+
this.buffer = new Buffer(0);
32+
}
33+
34+
inherits(DelimiterParser, Transform);
35+
36+
DelimiterParser.prototype._transform = function(chunk, encoding, cb) {
37+
var data = Buffer.concat([this.buffer, chunk]);
38+
var position;
39+
while ((position = bindexOf(data, this.delimiter)) !== -1) {
40+
this.push(data.slice(0, position));
41+
data = data.slice(position + this.delimiter.length);
42+
}
43+
this.buffer = data;
44+
cb();
45+
};
46+
47+
DelimiterParser.prototype._flush = function(cb) {
48+
this.push(this.buffer);
49+
this.buffer = new Buffer(0);
50+
cb();
51+
};
52+
53+
module.exports = DelimiterParser;

lib/parser-read-line.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict';
2+
var DelimiterParser = require('./parser-delimiter');
3+
var inherits = require('inherits');
4+
5+
function ReadLineParser(options) {
6+
if (!(this instanceof ReadLineParser)) {
7+
return new ReadLineParser(options);
8+
}
9+
10+
options = options || {};
11+
12+
if (options.delimiter === undefined) {
13+
options.delimiter = new Buffer('\n', 'utf8');
14+
}
15+
16+
DelimiterParser.call(this, options);
17+
18+
var encoding = options.encoding || 'utf8';
19+
this.delimiter = new Buffer(options.delimiter, encoding);
20+
this.setEncoding(encoding);
21+
}
22+
23+
inherits(ReadLineParser, DelimiterParser);
24+
module.exports = ReadLineParser;

lib/parsers.js

Lines changed: 0 additions & 73 deletions
This file was deleted.

0 commit comments

Comments
 (0)