// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /** * Custom bindings for the Serial API. * * The bindings are implemented by asynchronously delegating to the * serial_service module. The functions that apply to a particular connection * are delegated to the appropriate method on the Connection object specified by * the ID parameter. */ var binding = require('binding').Binding.create('serial'); var context = requireNative('v8_context'); var eventBindings = require('event_bindings'); var utils = require('utils'); var serialServicePromise = function() { // getBackgroundPage is not available in unit tests so fall back to the // current page's serial_service module. if (!chrome.runtime.getBackgroundPage) return requireAsync('serial_service'); // Load the serial_service module from the background page if one exists. This // is necessary for serial connections created in one window to be usable // after that window is closed. This is necessary because the Mojo async // waiter only functions while the v8 context remains. return utils.promise(chrome.runtime.getBackgroundPage).then(function(bgPage) { return context.GetModuleSystem(bgPage).requireAsync('serial_service'); }).catch(function() { return requireAsync('serial_service'); }); }(); function forwardToConnection(methodName) { return function(connectionId) { var args = $Array.slice(arguments, 1); return serialServicePromise.then(function(serialService) { return serialService.getConnection(connectionId); }).then(function(connection) { return $Function.apply(connection[methodName], connection, args); }); }; } binding.registerCustomHook(function(bindingsAPI) { var apiFunctions = bindingsAPI.apiFunctions; apiFunctions.setHandleRequestWithPromise('getDevices', function() { return serialServicePromise.then(function(serialService) { return serialService.getDevices(); }); }); apiFunctions.setHandleRequestWithPromise('connect', function(path, options) { return serialServicePromise.then(function(serialService) { return serialService.createConnection(path, options); }).then(function(result) { var id = result.info.connectionId; result.connection.onData = function(data) { eventBindings.dispatchEvent( 'serial.onReceive', [{connectionId: id, data: data}]); }; result.connection.onError = function(error) { eventBindings.dispatchEvent( 'serial.onReceiveError', [{connectionId: id, error: error}]); }; return result.info; }).catch (function(e) { throw new Error('Failed to connect to the port.'); }); }); apiFunctions.setHandleRequestWithPromise( 'disconnect', forwardToConnection('close')); apiFunctions.setHandleRequestWithPromise( 'getInfo', forwardToConnection('getInfo')); apiFunctions.setHandleRequestWithPromise( 'update', forwardToConnection('setOptions')); apiFunctions.setHandleRequestWithPromise( 'getControlSignals', forwardToConnection('getControlSignals')); apiFunctions.setHandleRequestWithPromise( 'setControlSignals', forwardToConnection('setControlSignals')); apiFunctions.setHandleRequestWithPromise( 'flush', forwardToConnection('flush')); apiFunctions.setHandleRequestWithPromise( 'setPaused', forwardToConnection('setPaused')); apiFunctions.setHandleRequestWithPromise( 'send', forwardToConnection('send')); apiFunctions.setHandleRequestWithPromise('getConnections', function() { return serialServicePromise.then(function(serialService) { return serialService.getConnections(); }).then(function(connections) { var promises = []; for (var id in connections) { promises.push(connections[id].getInfo()); } return Promise.all(promises); }); }); }); exports.binding = binding.generate();