-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
updated Zephyr Heart Rate monitor sample to work with current API
- Loading branch information
Showing
6 changed files
with
199 additions
and
133 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,32 @@ | ||
// Defines the profile used by the Zephyr heart rate monitor | ||
var HXM_PROFILE = { | ||
uuid: '00001101-0000-1000-8000-00805f9b34fb', | ||
name: 'Zephyr HXM Heart Rate Monitor' | ||
}; | ||
|
||
chrome.app.runtime.onLaunched.addListener(function() { | ||
chrome.app.window.create('index.html', { | ||
bounds: { | ||
width: 640, | ||
height: 480 | ||
} | ||
width: 600, | ||
height: 350 | ||
}, | ||
singleton: true, | ||
id: "bluetoothhxm" | ||
}, function(win) { | ||
// Add the profile to the list of profiles we support | ||
chrome.bluetooth.addProfile(HXM_PROFILE, function(r) { | ||
console.log("Profile added"); | ||
}); | ||
|
||
// Make the profile available in the main content window. | ||
win.contentWindow.HXM_PROFILE = HXM_PROFILE; | ||
}); | ||
}); | ||
|
||
function removeProfile() { | ||
console.log("Removing Zephyr HXM profile"); | ||
chrome.bluetooth.removeProfile(HXM_PROFILE, function(r) { | ||
console.log("Profile removed"); | ||
}); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,12 @@ | ||
<html> | ||
<head> | ||
</head> | ||
<body> | ||
<iframe id="graph" src="graph.html" seamless="seamless" width="580px" height="420px"></iframe> | ||
<input type="button" id="close" value="Quit"></input> | ||
<!-- Uncomment for logging | ||
<pre id="log"></pre> | ||
--> | ||
<iframe id="graph" src="graph.html" seamless="seamless" width="580px" height="300px"></iframe> | ||
<input type="button" id="butQuit" value="Quit"></input> | ||
<input type="button" id="butConnect" value="Connect"></input> | ||
<input type="button" id="butDisconnect" value="Disconnect"></input> | ||
<span id="hr"></span> | ||
</body> | ||
<script src="main.js"></script> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,135 +1,175 @@ | ||
function log(msg) { | ||
var msg_str = (typeof(msg) == 'object') ? JSON.stringify(msg) : msg; | ||
console.log(msg_str); | ||
var READ_INTERVAL = 1000; | ||
|
||
var l = document.getElementById('log'); | ||
if (l) { | ||
l.innerText += msg_str + '\n'; | ||
} | ||
var _socket = null; | ||
var _readIntervalId = null; | ||
|
||
function init() { | ||
console.log("Starting Zephyr HXM demo..."); | ||
|
||
document.getElementById("butDisconnect") | ||
.addEventListener("click", disconnect); | ||
document.getElementById("butConnect") | ||
.addEventListener("click", findAndConnect); | ||
document.getElementById("butQuit").addEventListener("click", closeApp); | ||
|
||
// Add the listener to deal with our initial connection | ||
chrome.bluetooth.onConnection.addListener(onConnected); | ||
|
||
// Check the paired Bluetooth devices then connect to the HXM | ||
findAndConnect(); | ||
} | ||
|
||
function updateHeartRate(value) { | ||
document.getElementById('graph').contentWindow.postMessage( | ||
{heartrate: value}, '*'); | ||
/* | ||
HXM Specific Function | ||
*/ | ||
|
||
function updateHeartRate(heartrate) { | ||
document.getElementById("hr").innerText = heartrate; | ||
document.getElementById("graph") | ||
.contentWindow.postMessage({heartrate: heartrate}, "*"); | ||
} | ||
|
||
var kUUID = '00001101-0000-1000-8000-00805f9b34fb'; | ||
var readIntervalId; | ||
var readInterval = function (socket) { | ||
return function() { | ||
chrome.bluetooth.read({socket: {id: socket.id}}, function(data) { | ||
if (chrome.apps.lastError) { | ||
log('Read error:'); | ||
log(chrome.runtime.lastError); | ||
window.clearInterval(readIntervalId); | ||
} else { | ||
// Data parsing is based on the code in the openzephyr library: | ||
// http://code.google.com/p/zephyropen/source/browse/zephyropen/src/zephyropen/device/zephyr/ZephyrUtils.java | ||
if (data) { | ||
if ((data.byteLength % 60) != 0) { | ||
log('Payload is wrong size (' + data.byteLength + | ||
'). Discarding.'); | ||
return; | ||
} | ||
|
||
var offset = 0; | ||
while (offset + 60 <= data.byteLength) { | ||
var data_view = new Uint8Array(data, offset); | ||
offset += 60; | ||
|
||
if (data_view[0] != 2) { | ||
log('Check failed data[0] = ' + data_view[0]); | ||
continue; | ||
} | ||
|
||
if (data_view[1] != 38) { | ||
log('Check failed data[1] = ' + data_view[1]); | ||
continue; | ||
} | ||
|
||
if (data_view[2] != 55) { | ||
log('Check failed data[2] = ' + data_view[2]); | ||
continue; | ||
} | ||
|
||
if (data_view[59] != 3) { | ||
log('Check failed data[59] = ' + data_view[59]); | ||
continue; | ||
} | ||
|
||
var heartrate = data_view[12]; | ||
if (heartrate < 30 || heartrate > 240) { | ||
log('Heartrate out of range (' + heartrate + '). Discarding.'); | ||
return; | ||
} | ||
|
||
updateHeartRate(heartrate); | ||
log('HR=' + heartrate); | ||
} | ||
} | ||
} | ||
}); | ||
} | ||
function closeApp() { | ||
console.log("Close app."); | ||
disconnect(); | ||
window.close(); | ||
} | ||
|
||
function startReads(socket) { | ||
log('Starting reads'); | ||
readIntervalId = window.setInterval(readInterval(socket), 1000); | ||
function findAndConnect() { | ||
// Get's the device list, and passes that list to the connectToHXM | ||
// function as a callback. | ||
getDeviceList(connectToHXM); | ||
} | ||
|
||
var socketId_; | ||
var connectCallback = function(socket) { | ||
function onConnected(socket) { | ||
console.log("onConnected", socket); | ||
if (socket) { | ||
log('Connected! Socket ID is: ' + socket.id + ' on service ' + | ||
socket.serviceUuid); | ||
startReads(socket); | ||
socketId_ = socket.id; | ||
_socket = socket; | ||
_readIntervalId = window.setInterval(function() { | ||
// Reads the data from the socket and passes it to parseHXMData | ||
chrome.bluetooth.read({socket: _socket}, parseHXMData); | ||
}, READ_INTERVAL); | ||
} else { | ||
log('Failed to connect.'); | ||
console.error("Failed to connect."); | ||
} | ||
}; | ||
} | ||
|
||
function parseHXMData(data) { | ||
|
||
// Data parsing is based on the code in the openzephyr library: | ||
// http://code.google.com/p/zephyropen/source/browse/zephyropen/src/zephyropen/device/zephyr/ZephyrUtils.java | ||
if ((data) && ((data.byteLength % 60) === 0)) { | ||
var offset = 0; | ||
while (offset + 60 <= data.byteLength) { | ||
var data_view = new Uint8Array(data, offset); | ||
offset += 60; | ||
|
||
if (data_view[0] != 2) { | ||
console.log('Check failed data[0] = ' + data_view[0]); | ||
continue; | ||
} | ||
|
||
if (data_view[1] != 38) { | ||
console.log('Check failed data[1] = ' + data_view[1]); | ||
continue; | ||
} | ||
|
||
var connectToDevice = function(result) { | ||
if (chrome.runtime.lastError) { | ||
log('Error searching for a device to connect to.'); | ||
return; | ||
if (data_view[2] != 55) { | ||
console.log('Check failed data[2] = ' + data_view[2]); | ||
continue; | ||
} | ||
|
||
if (data_view[59] != 3) { | ||
console.log('Check failed data[59] = ' + data_view[59]); | ||
continue; | ||
} | ||
|
||
var heartrate = data_view[12]; | ||
if (heartrate < 30 || heartrate > 240) { | ||
console.log('Heartrate out of range (' + heartrate + '). Discarding.'); | ||
return; | ||
} | ||
|
||
updateHeartRate(heartrate); | ||
} | ||
} else { | ||
console.error("Error parsing data.", data, data.byteLength); | ||
} | ||
if (result.length == 0) { | ||
log('No devices found to connect to.'); | ||
return; | ||
} | ||
|
||
function connectToHXM(deviceList) { | ||
console.log("connectToHXM", deviceList); | ||
if (deviceList !== null) { | ||
// Iterates through the device list looking for a device that starts with | ||
// HXM as it's name then tries to connect to that device. | ||
for (var i in deviceList) { | ||
var device = deviceList[i]; | ||
if (device.name.indexOf("HXM") === 0) { | ||
console.log("Connecting to HXM", device); | ||
connect(device.address, HXM_PROFILE); | ||
} | ||
} | ||
} | ||
for (var i in result) { | ||
var device = result[i]; | ||
if (device.name.indexOf("HXM") === 0) { | ||
log('Connecting to device: ' + device.name + ' @ ' + device.address); | ||
chrome.bluetooth.connect( | ||
{device: {address: device.address}, profile: {uuid: kUUID}}, connectCallback); | ||
} | ||
|
||
|
||
/* | ||
Generic BlueTooth | ||
*/ | ||
|
||
function getDeviceList(callback) { | ||
console.log("Searching for bluetooth devices..."); | ||
var deviceList = []; | ||
|
||
// Get the BlueTooth adapter state and verify it's ready | ||
chrome.bluetooth.getAdapterState(function(adapterState) { | ||
if (adapterState.available && adapterState.powered) { | ||
|
||
// Gets the list of paired devices and adds each one to the deviceList | ||
// array, when done calls the callback with the list of devices. | ||
chrome.bluetooth.getDevices({ | ||
deviceCallback: function(device) { deviceList.push(device); } | ||
}, function () { | ||
console.log("Devices found", deviceList); | ||
if (callback) { | ||
callback(deviceList); | ||
} else { | ||
console.error("No callback specified."); | ||
} | ||
}); | ||
} else { | ||
// If the bluetooth adapter wasn't ready or is unavailble, return null | ||
console.log("Bluetooth adapter not ready or unavailable."); | ||
callback(null); | ||
} | ||
}); | ||
} | ||
|
||
function connect(deviceAddress, profile) { | ||
console.log("Connecting to device", deviceAddress, profile); | ||
chrome.bluetooth.connect({ | ||
device: {address: deviceAddress}, | ||
profile: profile | ||
}, function() { | ||
if (chrome.runtime.lastError) { | ||
console.error("Error on connection.", chrome.runtime.lastError.message); | ||
} | ||
}); | ||
} | ||
|
||
function disconnect() { | ||
console.log("End session."); | ||
if (_readIntervalId !== null) { | ||
console.log("Clearing interval."); | ||
clearInterval(_readIntervalId); | ||
} | ||
}; | ||
|
||
log('Starting Zephyr HXM demo...'); | ||
|
||
|
||
var kSimulate = false; | ||
if (kSimulate) { | ||
window.setInterval(function() { | ||
updateHeartRate(60 + Math.floor((Math.random()*10)+1)); | ||
}, 1000); | ||
} else { | ||
var devicesFound = []; | ||
chrome.bluetooth.getDevices({ | ||
profile: {uuid: kUUID}, | ||
deviceCallback: function(device) { devicesFound.push(device); } | ||
}, function() { | ||
connectToDevice(devicesFound); | ||
if (_socket !== null) { | ||
console.log("Disconnecting socket."); | ||
chrome.bluetooth.disconnect({socket: _socket}, function() { | ||
console.log("Socket closed."); | ||
_socket = null; | ||
}); | ||
} | ||
} | ||
|
||
document.getElementById('close').addEventListener('click', | ||
function() { | ||
if (!kSimulate) { | ||
chrome.bluetooth.disconnect({socket: {id: socketId_}}); | ||
} | ||
window.close(); | ||
}); | ||
init(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,19 @@ | ||
{ | ||
"name": "Heart Rate Monitor Integration Sample", | ||
"description": "Demo of Zephyr HXM Heart Rate Monitor interaction", | ||
"version": "1.1", | ||
"version": "1.2", | ||
"manifest_version": 2, | ||
"minimum_chrome_version": "23", | ||
"minimum_chrome_version": "30", | ||
"app": { | ||
"background": { | ||
"scripts": ["background.js"] | ||
} | ||
}, | ||
"permissions": [ | ||
"bluetooth" | ||
{"bluetooth":[{"uuid": "00001101-0000-1000-8000-00805f9b34fb"}]} | ||
], | ||
"sandbox": { | ||
"pages": ["graph.html"] | ||
} | ||
}, | ||
"offline_enabled": true | ||
} |