I am creating an application using Cordova which requires interpreting data from a Bluetooth HR monitor (capable of recording raw RR intervals, such as the Polar H7). I am using the cordova-plugin-ble-central
I am having a difficult time making sense of the data received from the monitor, despite trawling the internet for answers and reading the Bluetooth Heart Rate Service Characteristic specification numerous times.
Here is my function which runs each time data is received:
onData: function(buffer) {
console.log(buffer);
// var data8 = new Uint8Array(buffer);
var data16 = new Uint16Array(buffer);
var rrIntervals = data.slice(1);
for (i=0; i<rrIntervals.length; i++) {
rrInterval = rrIntervals[i];
heartRate.addReading(rrInterval); // process RR interval elsewhere
}
},
When I log the data received in buffer, the following is output to the console: console output
I know how to extract RR intervals (highlighted in yellow), but I don't really understand what the other values represent, which I require as users might be connecting with other monitors which don't transmit RR intervals etc.
A quick plain English explanation of what the data received means and how to parse it would be much appreciated. For example, what number constitutes the flags field, and how to convert this to binary to extract the sub-fields (ie. to check if RR intervals present - I know this is determined by the 5th bit in the flags field.)
The plugin also states that 'Raw data is passed from native code to the success callback as an ArrayBuffer' but I don't know how to check the flags to determine if the data from the specific HR monitor is in 8 or 16 bit format. Below is another console log of when I create both Uint8 and Uint16 arrays from the data received. Again, I have highlighted the heart rate and RR intervals, but I need to know what the other values represent and how to parse them correctly.
console log with Uint8 and Uint16 output
The whole code is below:
var heartRateSpec = {
service: '180d',
measurement: '2a37'
};
var app = {
initialize: function() {
this.bindEvents();
},
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
onDeviceReady: function() {
app.scan();
},
scan: function() {
app.status("Scanning for Heart Rate Monitor");
var foundHeartRateMonitor = false;
function onScan(peripheral) {
// this is demo code, assume there is only one heart rate monitor
console.log("Found " + JSON.stringify(peripheral));
foundHeartRateMonitor = true;
ble.connect(peripheral.id, app.onConnect, app.onDisconnect);
}
function scanFailure(reason) {
alert("BLE Scan Failed");
}
ble.scan([heartRateSpec.service], 5, onScan, scanFailure);
setTimeout(function() {
if (!foundHeartRateMonitor) {
app.status("Did not find a heart rate monitor.");
}
}, 5000);
},
onConnect: function(peripheral) {
app.status("Connected to " + peripheral.id);
ble.startNotification(peripheral.id, heartRateSpec.service, heartRateSpec.measurement, app.onData, app.onError);
},
onDisconnect: function(reason) {
alert("Disconnectedz " + reason);
beatsPerMinute.innerHTML = "...";
app.status("Disconnected");
},
onData: function(buffer) {
var data = new Uint16Array(buffer);
if (heartRate.hasStarted() == false) {
heartRate.beginReading(Date.now());
} else {
var rrIntervals = data.slice(1);
for (i=0; i<rrIntervals.length; i++) {
rrInterval = rrIntervals[i];
heartRate.addReading(rrInterval);
}
}
},
onError: function(reason) {
alert("There was an error " + reason);
},
status: function(message) {
console.log(message);
statusDiv.innerHTML = message;
}
};
app.initialize();
Many thanks in advance for any help or advice.