From 142801607502ee81f5188a7c55c9eea108f48f9f Mon Sep 17 00:00:00 2001 From: Evan Xd Date: Fri, 19 Jun 2015 18:50:09 +0800 Subject: [PATCH] Support to connect multiple devices --- lib/bluetooth_device.js | 38 +++++++++++++++++++ lib/bluetooth_helper.js | 81 ++++++++++++++++++++--------------------- 2 files changed, 78 insertions(+), 41 deletions(-) create mode 100644 lib/bluetooth_device.js diff --git a/lib/bluetooth_device.js b/lib/bluetooth_device.js new file mode 100644 index 0000000..7992fba --- /dev/null +++ b/lib/bluetooth_device.js @@ -0,0 +1,38 @@ +/* global EventEmitter2 */ +'use strict'; + +(function(exports) { + function BluetoothDevice(name, address) { + this.name = name; + this.address = address; + } + + BluetoothDevice.prototype = Object.create(EventEmitter2.prototype); + + ['writeCharacteristic', 'notifyCharacteristic'].forEach(function(item) { + Object.defineProperty(BluetoothDevice.prototype, item, { + set: function(value) { + this['_' + item] = value; + }, + get: function() { + return this['_' + item]; + } + }); + }); + + BluetoothDevice.prototype.send = function(data) { + data = this._parseHexString(data); + this.writeCharacteristic.writeValue(data); + }; + + BluetoothDevice.prototype._parseHexString = function(str) { + var arrayBuffer = new ArrayBuffer(Math.ceil(str.length / 2)); + var uint8Array = new Uint8Array(arrayBuffer); + for (var i = 0, j = 0; i < str.length; i += 2, j++) { + uint8Array[j] = parseInt(str.substr(i, 2), 16); + } + return arrayBuffer; + }; + + exports.BluetoothDevice = BluetoothDevice; +}(window)); diff --git a/lib/bluetooth_helper.js b/lib/bluetooth_helper.js index 860992b..15f911e 100644 --- a/lib/bluetooth_helper.js +++ b/lib/bluetooth_helper.js @@ -1,4 +1,4 @@ -/* global EventEmitter2 */ +/* global BluetoothDevice */ 'use strict'; (function(exports) { @@ -7,44 +7,35 @@ var BLE_TX_UUID = '713d0002-503e-4c75-ba94-3148f18d941e'; var bluetooth = navigator.mozBluetooth; - function BluetoothHelper(name, address) { - this.name = name; - this.address = address; + function BluetoothHelper() { + this._devices = []; + this.startScan(); } - BluetoothHelper.prototype = Object.create(EventEmitter2.prototype); - - BluetoothHelper.prototype.address = null, - BluetoothHelper.prototype.name = null, - BluetoothHelper.prototype.isConnected = false, - BluetoothHelper.prototype._bluetooth = null, + BluetoothHelper.prototype._devices = null, BluetoothHelper.prototype._gatt = null, - BluetoothHelper.prototype._writeChar = null, - BluetoothHelper.prototype._notifyChar = null, + BluetoothHelper.prototype._isScanning = false, - BluetoothHelper.prototype.send = function(data) { - data = this._parseHexString(data); - this._writeChar.writeValue(data); - }; + BluetoothHelper.prototype.addDevice = function(name, address) { + var device = new BluetoothDevice(name, address); + // TODO: Pop the device from array once it is disconnected. + this._devices.push(device); + return device; + }, - BluetoothHelper.prototype._parseHexString = function(str) { - var arrayBuffer = new ArrayBuffer(Math.ceil(str.length / 2)); - var uint8Array = new Uint8Array(arrayBuffer); - for (var i = 0, j = 0; i < str.length; i += 2, j++) { - uint8Array[j] = parseInt(str.substr(i, 2), 16); + BluetoothHelper.prototype.startScan = function() { + if (this._isScanning) { + return; } - return arrayBuffer; - }; - - BluetoothHelper.prototype.connect = function() { if (bluetooth.defaultAdapter) { - // For stability, We use startLeScan to instead of startDiscovery. + // For stability, We use startScan to instead of startDiscovery. return bluetooth.defaultAdapter.startLeScan([]).then(scan => { + this._isScanning = true; this._scan = scan; scan.addEventListener('devicefound', this._handleDevicefound.bind(this)); }).catch(() => { - this.connect(); + this.startScan(); }); } else { bluetooth.addEventListener('attributechanged', @@ -52,13 +43,16 @@ } }; - BluetoothHelper.prototype.disconnect = function() { + BluetoothHelper.prototype.stopScan = function() { + if (!this._isScanning) { + return; + } if (this._gatt) { return this._gatt.disconnect().then(() => { return bluetooth.defaultAdapter.stopLeScan(this._scan); }).then(() => { - this.emit('disconnected'); - this.isConnected = false; + this._isScanning = false; + this.emit('scanningstoped'); }); } else { return Promise.reject('GATT is undefined.'); @@ -71,7 +65,7 @@ case 'defaultAdapter': bluetooth.removeEventListener('attributechanged', this._handleAttributechanged); - this.connect(); + this.startScan(); break; } } @@ -81,34 +75,39 @@ var devcie = evt.device; var gatt = devcie.gatt; this._gatt = gatt; - if (devcie.name === this.name || - devcie.address === this.address) { - this.name = devcie.name; - this.address = devcie.address; + devcie = this._devices.find(function(item) { + return (item.address === devcie.address || + item.name === devcie.name) && + !devcie.paired; + }); + if (devcie) { gatt.connect().then(() => { - return this._discoverServices(); + this._discoverServices(devcie); }); } }; - BluetoothHelper.prototype._discoverServices = function() { + BluetoothHelper.prototype._discoverServices = function(devcie) { var gatt = this._gatt; return gatt.discoverServices().then(() => { var service = gatt.services.find(function(service) { return service.uuid === BLE_SERVICE_UUID; }); - this._writeChar = + var writeCharacteristic = service.characteristics.find(function(characteristic) { return characteristic.uuid === BLE_RX_UUID; }); - this._notifyChar = + var notifyCharacteristic = service.characteristics.find(function(characteristic) { return characteristic.uuid === BLE_TX_UUID; }); - this.emit('connected'); - this.isConnected = true; + devcie.writeCharacteristic = writeCharacteristic; + devcie.notifyCharacteristic = notifyCharacteristic; + devcie.emit('connected', devcie); }); }; + exports.Bluetooth = new BluetoothHelper(); + // For testing. exports.BluetoothHelper = BluetoothHelper; }(window));