UNPKG

5.14 kBJavaScriptView Raw
1'use strict';
2
3var _ = require('lodash');
4var util = require('util');
5var when = require('when');
6var nodefn = require('when/node');
7var reemit = require('re-emitter');
8var EventEmitter = require('events').EventEmitter;
9
10var Transport = require('./transport');
11
12var TerminalStreamParser = require('./lib/terminal-stream-parser');
13var TransmitStreamParser = require('./lib/transmit-stream-parser');
14
15function Protocol(options){
16 EventEmitter.call(this);
17
18 this._terminal = new TerminalStreamParser();
19 this._transmit = new TransmitStreamParser();
20
21 var TransportCtor = options.transport || Transport;
22
23 this._options = {
24 echo: options.echo || false
25 };
26
27 this._transport = new TransportCtor(_.omit(options, 'transport'));
28
29 reemit(this._transport, this, ['open', 'close', 'data']);
30 this.on('data', this._emitTerminal.bind(this));
31 this._terminalEvents = true;
32}
33
34util.inherits(Protocol, EventEmitter);
35
36Protocol.prototype.isOpen = function isOpen(){
37 return this._transport.isOpen();
38};
39
40Protocol.prototype.open = function(cb){
41 var promise;
42 if(this.isOpen()){
43 promise = when.resolve();
44 }else{
45 promise = this._transport.open();
46 }
47 return nodefn.bindCallback(promise, cb);
48};
49
50Protocol.prototype.close = function(cb){
51 return nodefn.bindCallback(this._transport.close(), cb);
52};
53
54Protocol.prototype.enterProgramming = function(options, cb){
55 var self = this;
56 var transport = this._transport;
57
58 if(typeof options === 'function'){
59 cb = options;
60 options = {};
61 }else{
62 options = options || {};
63 }
64
65 this._terminalEvents = false;
66
67 var promise = transport.open()
68 .then(function(){
69 transport.autoRecover = false;
70 return transport.setBreak();
71 })
72 .then(function(){
73 return transport.flush();
74 })
75 .then(function(){
76 if(transport.isPaused()){
77 return transport.unpause();
78 }
79 })
80 .then(function(){
81 return transport.set({ dtr: false });
82 })
83 .then(function(){
84 return transport.set({ dtr: true }).delay(60);
85 })
86 .then(function(){
87 return transport.clearBreak();
88 })
89 .then(function(){
90 transport.autoRecover = true;
91 if(transport.isPaused()){
92 return transport.unpause();
93 }
94 })
95 .then(function(){
96 return transport.flush();
97 });
98
99 return nodefn.bindCallback(promise, cb);
100};
101
102Protocol.prototype.exitProgramming = function(options, cb){
103 var self = this;
104 var transport = this._transport;
105
106 if(typeof options === 'function'){
107 cb = options;
108 options = {};
109 }else{
110 options = options || {};
111 }
112
113 var promise = this.signoff()
114 .then(function(){
115 self._terminal.clearIgnore();
116 if(!options.keepOpen){
117 return transport.close();
118 }
119 })
120 .otherwise(function(err){
121 //close socket
122 return transport.close()
123 .then(function(){
124 throw err;
125 });
126 })
127 .ensure(function(){
128 if(options.listen){
129 self._terminalEvents = true;
130 }
131 });
132
133 return nodefn.bindCallback(promise, cb);
134};
135
136Protocol.prototype._emitTerminal = function _emitTerminal(chunk){
137 if(this._terminalEvents){
138 this.emit('terminal', this._terminal.parseStreamChunk(chunk));
139 }
140};
141
142Protocol.prototype.send = function send(data, cb){
143 var self = this;
144
145 var responseLength = data.length + 1;
146
147 var defer = when.defer();
148
149 var buffer = new Buffer(0);
150 function onChunk(chunk){
151 buffer = Buffer.concat([buffer, chunk]);
152
153 if(buffer.length < responseLength){
154 // keep buffering
155 return;
156 }
157 if (buffer.length > responseLength) {
158 // or ignore after
159 defer.reject(new Error('buffer overflow ' + buffer.length + ' > ' + responseLength));
160 return;
161 }
162 if (buffer.length === responseLength) {
163 defer.resolve(buffer[data.length]);
164 }
165 }
166
167 this.on('data', onChunk);
168
169 this._transport.send(data)
170 .catch(defer.reject);
171
172 var promise = defer.promise.finally(function(){
173 self.removeListener('data', onChunk);
174 });
175
176 return nodefn.bindCallback(promise, cb);
177};
178
179Protocol.prototype.write = function(data, cb){
180 var transmitEvents = this._transmit.parseStreamChunk(data);
181 this.emit('transmit', transmitEvents);
182
183 if(!this._options.echo){
184 this._terminal.ignore(data);
185 }
186 var promise = this._transport.send(data);
187
188 return nodefn.bindCallback(promise, cb);
189};
190
191Protocol.prototype.reset = function reset(cb){
192 var transport = this._transport;
193
194 var promise = transport.set({ dtr: true })
195 .delay(2)
196 .then(function(){
197 return transport.set({ dtr: false });
198 });
199
200 return nodefn.bindCallback(promise, cb);
201};
202
203Protocol.prototype.signoff = function signoff(cb){
204 var signoffBit = new Buffer([0]);
205
206 var promise = this._transport.send(signoffBit);
207
208 return nodefn.bindCallback(promise, cb);
209};
210
211Protocol.prototype.setEcho = function setEcho(echo){
212 this._options.echo = echo;
213 this._terminal.clearIgnore();
214};
215
216Protocol.listPorts = function(cb){
217 //TODO Refactor listPorts call in bs2-serial to break serial-protocol dependency chain
218 return nodefn.bindCallback(Transport.listPorts(), cb);
219};
220
221module.exports = Protocol;