Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / extensions / renderer / resources / serial_service.js
blobb8b0970db71ab70e1921064d4570c6ed204a6ae6
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 define('serial_service', [
6 'content/public/renderer/service_provider',
7 'device/serial/serial.mojom',
8 'mojo/public/js/bindings/core',
9 'mojo/public/js/bindings/router',
10 ], function(serviceProvider, serialMojom, core, routerModule) {
11 /**
12 * A Javascript client for the serial service and connection Mojo services.
14 * This provides a thick client around the Mojo services, exposing a JS-style
15 * interface to serial connections and information about serial devices. This
16 * converts parameters and result between the Apps serial API types and the
17 * Mojo types.
20 var service = new serialMojom.SerialServiceProxy(new routerModule.Router(
21 serviceProvider.connectToService(serialMojom.SerialServiceProxy.NAME_)));
23 function getDevices() {
24 return service.getDevices().then(function(response) {
25 return $Array.map(response.devices, function(device) {
26 var result = {path: device.path || ''};
27 if (device.has_vendor_id)
28 result.vendorId = device.vendor_id;
29 if (device.has_product_id)
30 result.productId = device.product_id;
31 if (device.display_name)
32 result.displayName = device.display_name;
33 return result;
34 });
35 });
38 var DEFAULT_CLIENT_OPTIONS = {
39 persistent: false,
40 name: '',
41 receiveTimeout: 0,
42 sendTimeout: 0,
43 bufferSize: 4096,
46 var DATA_BITS_TO_MOJO = {
47 undefined: serialMojom.DataBits.NONE,
48 'seven': serialMojom.DataBits.SEVEN,
49 'eight': serialMojom.DataBits.EIGHT,
51 var STOP_BITS_TO_MOJO = {
52 undefined: serialMojom.StopBits.NONE,
53 'one': serialMojom.StopBits.ONE,
54 'two': serialMojom.StopBits.TWO,
56 var PARITY_BIT_TO_MOJO = {
57 undefined: serialMojom.ParityBit.NONE,
58 'no': serialMojom.ParityBit.NO,
59 'odd': serialMojom.ParityBit.ODD,
60 'even': serialMojom.ParityBit.EVEN,
63 function invertMap(input) {
64 var output = {};
65 for (var key in input) {
66 if (key == 'undefined')
67 output[input[key]] = undefined;
68 else
69 output[input[key]] = key;
71 return output;
73 var DATA_BITS_FROM_MOJO = invertMap(DATA_BITS_TO_MOJO);
74 var STOP_BITS_FROM_MOJO = invertMap(STOP_BITS_TO_MOJO);
75 var PARITY_BIT_FROM_MOJO = invertMap(PARITY_BIT_TO_MOJO);
77 function getServiceOptions(options) {
78 var out = {};
79 if (options.dataBits)
80 out.data_bits = DATA_BITS_TO_MOJO[options.dataBits];
81 if (options.stopBits)
82 out.stop_bits = STOP_BITS_TO_MOJO[options.stopBits];
83 if (options.parityBit)
84 out.parity_bit = PARITY_BIT_TO_MOJO[options.parityBit];
85 if ('ctsFlowControl' in options) {
86 out.has_cts_flow_control = true;
87 out.cts_flow_control = options.ctsFlowControl;
89 if ('bitrate' in options)
90 out.bitrate = options.bitrate;
91 return out;
94 function convertServiceInfo(result) {
95 if (!result.info)
96 throw new Error('Failed to get ConnectionInfo.');
97 return {
98 ctsFlowControl: !!result.info.cts_flow_control,
99 bitrate: result.info.bitrate || undefined,
100 dataBits: DATA_BITS_FROM_MOJO[result.info.data_bits],
101 stopBits: STOP_BITS_FROM_MOJO[result.info.stop_bits],
102 parityBit: PARITY_BIT_FROM_MOJO[result.info.parity_bit],
106 function Connection(remoteConnection, router, id, options) {
107 this.remoteConnection_ = remoteConnection;
108 this.router_ = router;
109 this.id_ = id;
110 getConnections().then(function(connections) {
111 connections[this.id_] = this;
112 }.bind(this));
113 this.paused_ = false;
114 this.options_ = {};
115 for (var key in DEFAULT_CLIENT_OPTIONS) {
116 this.options_[key] = DEFAULT_CLIENT_OPTIONS[key];
118 this.setClientOptions_(options);
121 Connection.create = function(path, options) {
122 options = options || {};
123 var serviceOptions = getServiceOptions(options);
124 var pipe = core.createMessagePipe();
125 // Note: These two are created and closed because the service implementation
126 // requires that we provide valid message pipes for the data source and
127 // sink. Currently the client handles are immediately closed; the real
128 // implementation will come later.
129 var sendPipe = core.createMessagePipe();
130 var receivePipe = core.createMessagePipe();
131 service.connect(path,
132 serviceOptions,
133 pipe.handle0,
134 sendPipe.handle0,
135 receivePipe.handle0);
136 core.close(sendPipe.handle1);
137 core.close(receivePipe.handle1);
138 var router = new routerModule.Router(pipe.handle1);
139 var connection = new serialMojom.ConnectionProxy(router);
140 return connection.getInfo().then(convertServiceInfo).then(
141 function(info) {
142 return Promise.all([info, allocateConnectionId()]);
143 }).catch(function(e) {
144 router.close();
145 throw e;
146 }).then(function(results) {
147 var info = results[0];
148 var id = results[1];
149 var serialConnectionClient = new Connection(
150 connection, router, id, options);
151 var clientInfo = serialConnectionClient.getClientInfo_();
152 for (var key in clientInfo) {
153 info[key] = clientInfo[key];
155 return {
156 connection: serialConnectionClient,
157 info: info,
162 Connection.prototype.close = function() {
163 this.router_.close();
164 return getConnections().then(function(connections) {
165 delete connections[this.id_]
166 return true;
167 }.bind(this));
170 Connection.prototype.getClientInfo_ = function() {
171 var info = {
172 connectionId: this.id_,
173 paused: this.paused_,
175 for (var key in this.options_) {
176 info[key] = this.options_[key];
178 return info;
181 Connection.prototype.getInfo = function() {
182 var info = this.getClientInfo_();
183 return this.remoteConnection_.getInfo().then(convertServiceInfo).then(
184 function(result) {
185 for (var key in result) {
186 info[key] = result[key];
188 return info;
189 }).catch(function() {
190 return info;
194 Connection.prototype.setClientOptions_ = function(options) {
195 if ('name' in options)
196 this.options_.name = options.name;
197 if ('receiveTimeout' in options)
198 this.options_.receiveTimeout = options.receiveTimeout;
199 if ('sendTimeout' in options)
200 this.options_.sendTimeout = options.sendTimeout;
201 if ('bufferSize' in options)
202 this.options_.bufferSize = options.bufferSize;
205 Connection.prototype.setOptions = function(options) {
206 this.setClientOptions_(options);
207 var serviceOptions = getServiceOptions(options);
208 if ($Object.keys(serviceOptions).length == 0)
209 return true;
210 return this.remoteConnection_.setOptions(serviceOptions).then(
211 function(result) {
212 return !!result.success;
213 }).catch(function() {
214 return false;
218 Connection.prototype.getControlSignals = function() {
219 return this.remoteConnection_.getControlSignals().then(function(result) {
220 if (!result.signals)
221 throw new Error('Failed to get control signals.');
222 var signals = result.signals;
223 return {
224 dcd: !!signals.dcd,
225 cts: !!signals.cts,
226 ri: !!signals.ri,
227 dsr: !!signals.dsr,
232 Connection.prototype.setControlSignals = function(signals) {
233 var controlSignals = {};
234 if ('dtr' in signals) {
235 controlSignals.has_dtr = true;
236 controlSignals.dtr = signals.dtr;
238 if ('rts' in signals) {
239 controlSignals.has_rts = true;
240 controlSignals.rts = signals.rts;
242 return this.remoteConnection_.setControlSignals(controlSignals).then(
243 function(result) {
244 return !!result.success;
248 Connection.prototype.flush = function() {
249 return this.remoteConnection_.flush().then(function(result) {
250 return !!result.success;
254 Connection.prototype.setPaused = function(paused) {
255 this.paused_ = paused;
258 var connections_ = {};
259 var nextConnectionId_ = 0;
261 // Wrap all access to |connections_| through getConnections to avoid adding
262 // any synchronous dependencies on it. This will likely be important when
263 // supporting persistent connections by stashing them.
264 function getConnections() {
265 return Promise.resolve(connections_);
268 function getConnection(id) {
269 return getConnections().then(function(connections) {
270 if (!connections[id])
271 throw new Error ('Serial connection not found.');
272 return connections[id];
276 function allocateConnectionId() {
277 return Promise.resolve(nextConnectionId_++);
280 return {
281 getDevices: getDevices,
282 createConnection: Connection.create,
283 getConnection: getConnection,
284 getConnections: getConnections,