// 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();