UNPKG

4.99 kBJavaScriptView Raw
1'use strict';
2
3var _ = require('lodash');
4var util = require('util');
5var bs2 = require('bs2-programmer');
6var nodefn = require('when/node');
7var bluebird = require('bluebird');
8var Bs2Programmer = bs2.Programmer;
9var reemit = require('re-emitter');
10var bs2tokenizer = require('pbasic-tokenizer');
11var EventEmitter = require('events').EventEmitter;
12var Bs2SerialProtocol = require('bs2-serial-protocol');
13
14function internalCompile(source){
15 var TModuleRec = bs2tokenizer.compile(source, false);
16
17 var program = {
18 data: TModuleRec.PacketBuffer.slice(0, TModuleRec.PacketCount * 18),
19 name: TModuleRec.TargetModuleName,
20 error: !TModuleRec.Succeeded ? TModuleRec.Error : null,
21 raw: TModuleRec
22 };
23
24 return program;
25}
26
27function generateEmptyPort(port, err){
28 return {
29 name: null,
30 path: port,
31 type: 'bs2',
32 match: false,
33 program: null,
34 displayError: err,
35 board: {
36 path: port
37 }
38 };
39}
40
41function listPorts(options){
42 var reject = _.get(options, 'reject') || [];
43 var predicate = reject;
44 if(Array.isArray(reject)){
45 predicate = function(port){
46 return _.some(reject, function(entry){
47 if(typeof entry === 'string'){
48 return port === entry;
49 }
50 return entry.test(port);
51 });
52 };
53 }
54 return Bs2SerialProtocol.listPorts()
55 .then(function(portList){
56 return _.reject(portList, predicate);
57 });
58}
59
60function Board(options){
61 if(!options){
62 throw new Error('Options error: no options');
63 }
64
65 if(!options.path){
66 throw new Error('Options error: no path');
67 }
68
69 EventEmitter.call(this);
70
71 this._revision = options.revision || 'bs2';
72 this._protocol = new Bs2SerialProtocol(options);
73 this._programmer = new Bs2Programmer({
74 protocol: this._protocol,
75 revision: this._revision
76 });
77
78 reemit(this._protocol, this, ['terminal', 'transmit', 'open', 'close']);
79
80 var self = this;
81 this._programmer.on('bootloadProgress', function(progress){
82 self.emit('progress', progress);
83 });
84}
85
86util.inherits(Board, EventEmitter);
87
88Board.search = function(options, cb){
89 var revisions = _.keys(bs2.revisions);
90 var result = listPorts(options)
91 .then(function(portList){
92 return bluebird.reduce(portList, function(boardList, path){
93
94 var protocol = new Bs2SerialProtocol({ path: path });
95 return bluebird.reduce(revisions, function(current, rev){
96 if(current.revision){
97 return current;
98 }
99
100 var boardOpts = {
101 protocol: protocol,
102 revision: rev
103 };
104
105 return bs2.identify(boardOpts)
106 .then(function(result){
107 return _.assign({ path: path, revision: rev }, result);
108 })
109 .otherwise(function(err){
110 if(err.message === 'Serialport not open.'){
111 //workaround for generic browser-serialport errors
112 //TODO improve error messages in browser-serialport
113 err = new Error('Port could not be opened.');
114 }
115 return {
116 displayError: err.message
117 };
118 });
119
120 }, {})
121 .then(function(board){
122 if(board.revision != null){
123 var details = {
124 name: board.name,
125 path: board.path,
126 version: board.version,
127 board: _.cloneDeep(board),
128 match: false,
129 program: null
130 };
131 if(options.source){
132 details.program = internalCompile(options.source);
133 details.match = details.program.name === board.name;
134 }
135 boardList.push(details);
136 }else{
137 boardList.push(generateEmptyPort(path, board.displayError));
138 }
139 return boardList;
140 });
141 }, [])
142 .then(function(boards){
143 return _.sortBy(boards, 'name');
144 });
145 });
146
147 return nodefn.bindCallback(result, cb);
148};
149
150Board.prototype.bootload = function(program, cb){
151 if(typeof program === 'string'){
152 program = internalCompile(program);
153 }
154 if(program && program.error){
155 return bluebird.reject(program.error).nodeify(cb);
156 }
157 if(!program || !program.data){
158 return bluebird.reject(new Error('Options error: no program data')).nodeify(cb);
159 }
160
161 return this._programmer.bootload(program.data, cb);
162};
163
164Board.compile = function(source){
165 return internalCompile(source);
166};
167
168Board.prototype.isOpen = function(){
169 return this._protocol.isOpen();
170};
171
172Board.prototype.write = function(data, cb){
173 if(typeof data === 'number'){
174 data = new Buffer([data]);
175 }else if(Array.isArray(data) || typeof data === 'string'){
176 data = new Buffer(data);
177 }
178 return this._protocol.write(data, cb);
179};
180
181Board.prototype.open = function(cb){
182 return this._protocol.open(cb);
183};
184
185Board.prototype.close = function(cb){
186 return this._protocol.close(cb);
187};
188
189Board.getRevisions = function(){
190 return bs2.revisions;
191};
192
193module.exports = Board;