Interpreting/parsing 数据来自蓝牙心率监测器 (Cordova)

Interpreting/parsing data from Bluetooth heart rate monitor (Cordova)

我正在使用 Cordova 创建一个应用程序,它需要解释来自蓝牙 HR 监视器(能够记录原始 RR 间隔,例如 Polar H7)的数据。我正在使用 cordova-plugin-ble-central

尽管在互联网上搜索答案并多次阅读 Bluetooth Heart Rate Service Characteristic specification,但我还是很难理解从显示器接收到的数据。

这是我每次收到数据时运行的函数:

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
    }
},

当我记录缓冲区中接收到的数据时,以下内容输出到控制台: console output

我知道如何提取 RR 间隔(以黄色突出显示),但我不太了解其他值代表什么,我需要这些值,因为用户可能正在连接其他不传输 RR 间隔的监视器等.

如果能快速简单地用英语解释接收到的数据的含义以及如何解析数据,我们将不胜感激。例如,什么数字构成标志字段,以及如何将其转换为二进制以提取子字段(即检查是否存在 RR 间隔 - 我知道这是由标志字段中的第 5 位决定的。)

该插件还声明 'Raw data is passed from native code to the success callback as an ArrayBuffer' 但我不知道如何检查标志以确定来自特定 HR 监视器的数据是 8 位还是 16 位格式。下面是我根据收到的数据创建 Uint8 和 Uint16 数组时的另一个控制台日志。同样,我强调了心率和 RR 间隔,但我需要知道其他值代表什么以及如何正确解析它们。

console log with Uint8 and Uint16 output

完整代码如下:

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

非常感谢您的帮助或建议。

更新以获取更深入的解释,请查看 this post I wrote on the subject

我已经弄明白了 - 这是对遇到类似问题的任何人的快速解释:

传入onData(buffer)的数据只是二进制数据,因此无论我们将其转换为Uint8Array还是Uint16Array,它仍然表示相同的二进制数据。当然,Uint16 中的整数可能会更大,因为它们包含 16 位而不是 8 位。

标志字段始终由第一个字节表示,因此我们可以通过将数据(作为缓冲区传入)转换为 Uint8Array 并访问该数组的第一个元素(索引为 0 的元素)来获取此信息.

然后我们可以使用按位运算来检查各个位域。例如,Bluetooth Heart Rate Service Characteristic specification 告诉我们第五位表示读数是否包含 RR 间隔 (1) 或不包含任何 (0)。

下面我们可以看到第五位是二进制的16:

128 64  32  16  8   4   2   1
0   0   0   1   0   0   0   0  

因此,操作 16 & flag(其中 flag 是包含标志字段的字节)将 return 16(可以提升为 true)如果读数包含 RR 间隔和 0(提升为 false)如果没有。