/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* global BATTERY, BUTTON */ var app = { activeServices: [], list: {}, manufactureDecoder: new MANUFACTUREDECODER(), // Application Constructor initialize: function() { this.bindEvents(); }, arrayBufferToIntArray: function(buffer) { var result; if (buffer) { var typedArray = new Uint8Array(buffer); result = []; for (var i = 0; i < typedArray.length; i++) { result[i] = typedArray[i]; } } return result; }, parseAdvertisingData: function(bytes) { var length, type, data, i = 0, advertisementData = {}; while (length !== 0) { length = bytes[i] & 0xFF; i++; type = bytes[i] & 0xFF; i++; data = bytes.slice(i, i + length - 1); // Length includes type byte, but not length byte i += length - 2; // Move to end of data i++; advertisementData[type] = data; } return advertisementData; }, handle255: function(buffer) { 'use strict'; var bin = buffer; console.log('Block255', bin); var manSpec = bin.map(function(i) { return i.toString(16) + ' '; }); console.log('manSpec: ', manSpec); var manID = ('0000' + ((bin[1] << 8) | bin[0]).toString(16)).slice(-4); console.log('ManID:', manID); switch (manID) { case '004c': return app.manufactureDecoder.decodeIbeacon(bin); break; case '1235': return app.manufactureDecoder.decodeSiliconLabsSensorPuck(bin); break; default: console.log('Unknown manID: ', manID); } return {} }, doScan: function() { 'use strict'; $('#ripple').show(); $('#tbody').empty(); var otherData = null; var msgText = ''; ble.startScan([], function(device) { otherData = null; msgText = ''; console.log(JSON.stringify(device)); var newId = device.id.replace(/:/g, ''); console.log(newId); this.list[newId] = device.id; var newTR = $(''); newTR.append($('').text(device.id)); if (device.hasOwnProperty('advertising')) { var advertBuffer = app.arrayBufferToIntArray(device.advertising); var parsed = app.parseAdvertisingData(advertBuffer); //console.log(parsed); if (parsed.hasOwnProperty('9')) { var name = parsed['9'].map(function(i) { return String.fromCharCode(i); }); console.log('Name: ', name.join('')); } if (parsed.hasOwnProperty('255')) { otherData = app.handle255(parsed['255']); console.log(otherData); } } if (typeof otherData !== 'undefined' && otherData !== null) { if (otherData.hasOwnProperty('msg')) { msgText = ' - ' + otherData.msg; } } if (device.hasOwnProperty('name')) { newTR.append($('').text(device.name + msgText)); } else { newTR.append($('').text('*** Unknown' + msgText)); } newTR.append($('').text(device.rssi)); $('#tbody').append(newTR); $('#output').append(JSON.stringify(device) + '
'); }.bind(this), function(e) { 'use strict'; console.error(e); }); setTimeout(ble.stopScan, 5000, function() { console.log('Scan complete'); $('#ripple').hide(); }, function() { console.log('stopScan failed'); $('#ripple').hide(); }); }, // Bind Event Listeners // // Bind any events that are required on startup. Common events are: // 'load', 'deviceready', 'offline', and 'online'. bindEvents: function() { var self = this; document.addEventListener('deviceready', this.onDeviceReady, false); $('#scan').on('click', function() { 'use strict'; this.doScan(); }.bind(this)); $('#tbody').on('click', 'tr', function() { 'use strict'; var tID = $(this).context.id; var id = self.list[tID]; console.log(tID, id); self.connect(id); }); }, // Deviceready Event Handler // // The scope of 'this' is the event. In order to call the 'receivedEvent' // function, we must explicitly call 'app.receivedEvent(...);' onDeviceReady: function() { }, serviceDiscovery: function(services) { 'use strict'; console.log(services); }, sensorMpu9250GyroConvert: function(data) { return data / (65536 / 500); }, sensorMpu9250AccConvert: function(data) { // Change /2 to match accel range...i.e. 16 g would be /16 return data / (32768 / 2); }, doAnimate: function() { 'use strict'; console.log('Animate..'); for (var t = 0; t < app.activeServices.length;t++) { app.activeServices[t].animateGraph(); } window.requestAnimFrame(app.doAnimate.bind(this)); } , connect: function(deviceId) { $('#results').slideUp(); console.log('Connect to ', deviceId); var onConnect = function(a) { var services = []; 'use strict'; console.log('A:', a); services = a.services; for (var t = 0; t < services.length; t++) { var ident = services[t].toUpperCase(); switch (ident) { case '180F': var batteryStat = new BATTERY(deviceId); batteryStat.startService(); batteryStat.readBatteryState(); app.activeServices.push(batteryStat); break; case 'FFE0': var buttonState = new BUTTON(deviceId); buttonState.startService(); app.activeServices.push(buttonState); break; case 'F000AA80-0451-4000-B000-000000000000': var cc2650_accel = new CC2650_ACCEL(deviceId); cc2650_accel.startService(); app.activeServices.push(cc2650_accel); break; case 'F000AA40-0451-4000-B000-000000000000': var cc2650_bar = new CC2650_BAR(deviceId); cc2650_bar.startService(); app.activeServices.push(cc2650_bar); break; case 'F000AA70-0451-4000-B000-000000000000': var cc2650_lux = new CC2650_LUX(deviceId); cc2650_lux.startService(); app.activeServices.push(cc2650_lux); break; case 'F000AA00-0451-4000-B000-000000000000': var cc2650_tmp = new CC2650_TMP(deviceId); cc2650_tmp.startService(); app.activeServices.push(cc2650_tmp); break; case 'F000AA20-0451-4000-B000-000000000000': var cc2650_hum = new CC2650_HUM(deviceId); cc2650_hum.startService(); app.activeServices.push(cc2650_hum); break; default: console.log('Unknown service: ', ident); } } // Starting animation.. window.requestAnimFrame(app.doAnimate.bind(this)); }; ble.connect(deviceId, onConnect, function(e) { 'use strict'; console.error(e); }); }, onError: function(reason) { console.error('ERROR: ' + reason); // Real apps should use notification.alert }, updateGyro: function(g) { 'use strict'; } }; window.requestAnimFrame = (function() { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60); }; })(); app.initialize();