| Index: extensions/renderer/resources/serial_service.js
|
| diff --git a/extensions/renderer/resources/serial_service.js b/extensions/renderer/resources/serial_service.js
|
| index 92e17d06ec2b8dfb8936021ec29f1fbf6ddf7abb..00d137b1ea1cac14226803db8fd829650b2c83c7 100644
|
| --- a/extensions/renderer/resources/serial_service.js
|
| +++ b/extensions/renderer/resources/serial_service.js
|
| @@ -5,21 +5,20 @@
|
| define('serial_service', [
|
| 'content/public/renderer/service_provider',
|
| 'device/serial/serial.mojom',
|
| + 'mojo/public/js/bindings/core',
|
| 'mojo/public/js/bindings/router',
|
| -], function(serviceProvider, serialMojom, routerModule) {
|
| +], function(serviceProvider, serialMojom, core, routerModule) {
|
| + /**
|
| + * A Javascript client for the serial service and connection Mojo services.
|
| + *
|
| + * This provides a thick client around the Mojo services, exposing a JS-style
|
| + * interface to serial connections and information about serial devices. This
|
| + * converts parameters and result between the Apps serial API types and the
|
| + * Mojo types.
|
| + */
|
|
|
| - function defineService(proxy, handle) {
|
| - if (!handle)
|
| - handle = serviceProvider.connectToService(proxy.NAME_);
|
| - var router = new routerModule.Router(handle);
|
| - var service = new proxy(router);
|
| - return {
|
| - service: service,
|
| - router: router,
|
| - };
|
| - }
|
| -
|
| - var service = defineService(serialMojom.SerialServiceProxy).service;
|
| + var service = new serialMojom.SerialServiceProxy(new routerModule.Router(
|
| + serviceProvider.connectToService(serialMojom.SerialServiceProxy.NAME_)));
|
|
|
| function getDevices() {
|
| return service.getDevices().then(function(response) {
|
| @@ -36,7 +35,240 @@ define('serial_service', [
|
| });
|
| }
|
|
|
| + var DEFAULT_CLIENT_OPTIONS = {
|
| + persistent: false,
|
| + name: '',
|
| + receiveTimeout: 0,
|
| + sendTimeout: 0,
|
| + bufferSize: 4096,
|
| + };
|
| +
|
| + var DATA_BITS_TO_MOJO = {
|
| + undefined: serialMojom.DataBits.NONE,
|
| + 'seven': serialMojom.DataBits.SEVEN,
|
| + 'eight': serialMojom.DataBits.EIGHT,
|
| + };
|
| + var STOP_BITS_TO_MOJO = {
|
| + undefined: serialMojom.StopBits.NONE,
|
| + 'one': serialMojom.StopBits.ONE,
|
| + 'two': serialMojom.StopBits.TWO,
|
| + };
|
| + var PARITY_BIT_TO_MOJO = {
|
| + undefined: serialMojom.ParityBit.NONE,
|
| + 'no': serialMojom.ParityBit.NO,
|
| + 'odd': serialMojom.ParityBit.ODD,
|
| + 'even': serialMojom.ParityBit.EVEN,
|
| + };
|
| +
|
| + function invertMap(input) {
|
| + var output = {};
|
| + for (var key in input) {
|
| + if (key == 'undefined')
|
| + output[input[key]] = undefined;
|
| + else
|
| + output[input[key]] = key;
|
| + }
|
| + return output;
|
| + }
|
| + var DATA_BITS_FROM_MOJO = invertMap(DATA_BITS_TO_MOJO);
|
| + var STOP_BITS_FROM_MOJO = invertMap(STOP_BITS_TO_MOJO);
|
| + var PARITY_BIT_FROM_MOJO = invertMap(PARITY_BIT_TO_MOJO);
|
| +
|
| + function getServiceOptions(options) {
|
| + var out = {};
|
| + if (options.dataBits)
|
| + out.data_bits = DATA_BITS_TO_MOJO[options.dataBits];
|
| + if (options.stopBits)
|
| + out.stop_bits = STOP_BITS_TO_MOJO[options.stopBits];
|
| + if (options.parityBit)
|
| + out.parity_bit = PARITY_BIT_TO_MOJO[options.parityBit];
|
| + if ('ctsFlowControl' in options) {
|
| + out.has_cts_flow_control = true;
|
| + out.cts_flow_control = options.ctsFlowControl;
|
| + }
|
| + if ('bitrate' in options)
|
| + out.bitrate = options.bitrate;
|
| + return out;
|
| + }
|
| +
|
| + function convertServiceInfo(result) {
|
| + if (!result.info)
|
| + throw new Error('Failed to get ConnectionInfo.');
|
| + return {
|
| + ctsFlowControl: !!result.info.cts_flow_control,
|
| + bitrate: result.info.bitrate || undefined,
|
| + dataBits: DATA_BITS_FROM_MOJO[result.info.data_bits],
|
| + stopBits: STOP_BITS_FROM_MOJO[result.info.stop_bits],
|
| + parityBit: PARITY_BIT_FROM_MOJO[result.info.parity_bit],
|
| + };
|
| + }
|
| +
|
| + function Connection(remoteConnection, router, id, options) {
|
| + this.remoteConnection_ = remoteConnection;
|
| + this.router_ = router;
|
| + this.id_ = id;
|
| + getConnections().then(function(connections) {
|
| + connections[this.id_] = this;
|
| + }.bind(this));
|
| + this.paused_ = false;
|
| + this.options_ = {};
|
| + for (var key in DEFAULT_CLIENT_OPTIONS) {
|
| + this.options_[key] = DEFAULT_CLIENT_OPTIONS[key];
|
| + }
|
| + this.setClientOptions_(options);
|
| + }
|
| +
|
| + Connection.create = function(path, options) {
|
| + options = options || {};
|
| + var serviceOptions = getServiceOptions(options);
|
| + var pipe = core.createMessagePipe();
|
| + service.connect(path, serviceOptions, pipe.handle0);
|
| + var router = new routerModule.Router(pipe.handle1);
|
| + var connection = new serialMojom.ConnectionProxy(router);
|
| + return connection.getInfo().then(convertServiceInfo).then(
|
| + function(info) {
|
| + return Promise.all([info, allocateConnectionId()]);
|
| + }).catch(function(e) {
|
| + router.close();
|
| + throw e;
|
| + }).then(function(results) {
|
| + var info = results[0];
|
| + var id = results[1];
|
| + var serialConnectionClient = new Connection(
|
| + connection, router, id, options);
|
| + var clientInfo = serialConnectionClient.getClientInfo_();
|
| + for (var key in clientInfo) {
|
| + info[key] = clientInfo[key];
|
| + }
|
| + return {
|
| + connection: serialConnectionClient,
|
| + info: info,
|
| + };
|
| + });
|
| + };
|
| +
|
| + Connection.prototype.close = function() {
|
| + this.router_.close();
|
| + return getConnections().then(function(connections) {
|
| + delete connections[this.id_]
|
| + return true;
|
| + }.bind(this));
|
| + };
|
| +
|
| + Connection.prototype.getClientInfo_ = function() {
|
| + var info = {
|
| + connectionId: this.id_,
|
| + paused: this.paused_,
|
| + }
|
| + for (var key in this.options_) {
|
| + info[key] = this.options_[key];
|
| + }
|
| + return info;
|
| + };
|
| +
|
| + Connection.prototype.getInfo = function() {
|
| + var info = this.getClientInfo_();
|
| + return this.remoteConnection_.getInfo().then(convertServiceInfo).then(
|
| + function(result) {
|
| + for (var key in result) {
|
| + info[key] = result[key];
|
| + }
|
| + return info;
|
| + }).catch(function() {
|
| + return info;
|
| + });
|
| + };
|
| +
|
| + Connection.prototype.setClientOptions_ = function(options) {
|
| + if ('name' in options)
|
| + this.options_.name = options.name;
|
| + if ('receiveTimeout' in options)
|
| + this.options_.receiveTimeout = options.receiveTimeout;
|
| + if ('sendTimeout' in options)
|
| + this.options_.sendTimeout = options.sendTimeout;
|
| + if ('bufferSize' in options)
|
| + this.options_.bufferSize = options.bufferSize;
|
| + };
|
| +
|
| + Connection.prototype.setOptions = function(options) {
|
| + this.setClientOptions_(options);
|
| + var serviceOptions = getServiceOptions(options);
|
| + if ($Object.keys(serviceOptions).length == 0)
|
| + return true;
|
| + return this.remoteConnection_.setOptions(serviceOptions).then(
|
| + function(result) {
|
| + return !!result.success;
|
| + }).catch(function() {
|
| + return false;
|
| + });
|
| + };
|
| +
|
| + Connection.prototype.getControlSignals = function() {
|
| + return this.remoteConnection_.getControlSignals().then(function(result) {
|
| + if (!result.signals)
|
| + throw new Error('Failed to get control signals.');
|
| + var signals = result.signals;
|
| + return {
|
| + dcd: !!signals.dcd,
|
| + cts: !!signals.cts,
|
| + ri: !!signals.ri,
|
| + dsr: !!signals.dsr,
|
| + };
|
| + });
|
| + };
|
| +
|
| + Connection.prototype.setControlSignals = function(signals) {
|
| + var controlSignals = {};
|
| + if ('dtr' in signals) {
|
| + controlSignals.has_dtr = true;
|
| + controlSignals.dtr = signals.dtr;
|
| + }
|
| + if ('rts' in signals) {
|
| + controlSignals.has_rts = true;
|
| + controlSignals.rts = signals.rts;
|
| + }
|
| + return this.remoteConnection_.setControlSignals(controlSignals).then(
|
| + function(result) {
|
| + return !!result.success;
|
| + });
|
| + };
|
| +
|
| + Connection.prototype.flush = function() {
|
| + return this.remoteConnection_.flush().then(function(result) {
|
| + return !!result.success;
|
| + });
|
| + };
|
| +
|
| + Connection.prototype.setPaused = function(paused) {
|
| + this.paused_ = paused;
|
| + };
|
| +
|
| + var connections_ = {};
|
| + var nextConnectionId_ = 0;
|
| +
|
| + // Wrap all access to |connections_| through getConnections to avoid adding
|
| + // any synchronous dependencies on it. This will likely be important when
|
| + // supporting persistent connections by stashing them.
|
| + function getConnections() {
|
| + return Promise.resolve(connections_);
|
| + }
|
| +
|
| + function getConnection(id) {
|
| + return getConnections().then(function(connections) {
|
| + if (!connections[id])
|
| + throw new Error ('Serial connection not found.');
|
| + return connections[id];
|
| + });
|
| + }
|
| +
|
| + function allocateConnectionId() {
|
| + return Promise.resolve(nextConnectionId_++);
|
| + }
|
| +
|
| return {
|
| getDevices: getDevices,
|
| + createConnection: Connection.create,
|
| + getConnection: getConnection,
|
| + getConnections: getConnections,
|
| };
|
| });
|
|
|