UNPKG

obniz

Version:

obniz sdk for javascript

277 lines (276 loc) 9.34 kB
"use strict"; /** * @packageDocumentation * @module Parts.UA1200BLE */ /* eslint rulesdir/non-ascii: 0 */ Object.defineProperty(exports, "__esModule", { value: true }); /** UA1200BLE management class UA1200BLEを管理するクラス */ class UA1200BLE { constructor(peripheral, timezoneOffsetMinute) { if (!peripheral || !UA1200BLE.isDevice(peripheral)) { throw new Error('peripheral is not UA1200BLE'); } this._peripheral = peripheral; this._timezoneOffsetMinute = timezoneOffsetMinute; } static info() { return { name: 'UA1200BLE', }; } /** * Verify that the received peripheral is from the UA1200BLE * * 受け取ったPeripheralがUA1200BLEのものかどうかを確認する * * @param peripheral instance of BleRemotePeripheral BleRemotePeripheralのインスタンス * * @returns Whether it is UA1200BLE * * UA1200BLEかどうか */ static isDevice(peripheral) { return (peripheral.localName && peripheral.localName.startsWith('UA-1200BLE_')); } /** * Judge whether it is cooperation mode * * (When in cooperation mode, no data exists even when connected) * * 連携モードかどうかの判定 * * (連携モードのときは接続してもデータが存在しません) * * @param peripheral instance of BleRemotePeripheral BleRemotePeripheralのインスタンス * * @returns Whether it is cooperation mode or not * * 連携モードかどうか */ static isCooperationMode(peripheral) { const peripheralHex = peripheral.adv_data .map((e) => e.toString(16)) .join(''); const peripheralArray = [ // "2", // "1", // "6", // "11", // "7", 'e4', 'ab', '90', '56', 'd', '0', '5c', '97', '6d', '1b', '34', '5a', '0', 'f0', '3b', '23', // "5", // "ff", // "69", // "0", // "0", // "ff", ].join(''); return peripheralHex.indexOf(peripheralArray) > -1; } /** * Pair with the device * * デバイスとペアリング * * @returns pairing key ペアリングキー */ async pairingWait() { if (!this._peripheral) { throw new Error('UA1200BLE not found'); } this._peripheral.ondisconnect = (reason) => { if (typeof this.ondisconnect === 'function') { this.ondisconnect(reason); } }; let key = null; await this._peripheral.connectWait({ pairingOption: { onPairedCallback: (pairingKey) => { key = pairingKey; }, }, }); const { customServiceChar } = this._getCharsCoopMode(); await customServiceChar.writeWait([2, 1, 3]); // disconnect req return key; } /** * Get data from the UA1200BLE * * UA1200BLEからデータを取得 * * @returns data from the UA1200BLE UA1200BLEから受け取ったデータ */ async getDataWait() { if (!this._peripheral) { throw new Error('UA1200BLE not found'); } this._peripheral.ondisconnect = (reason) => { if (this.ondisconnect) { this.ondisconnect(reason); } }; await this._peripheral.connectWait(); if (!this._peripheral) { throw new Error('UA1200BLE not found'); } const results = []; // Advertise mode (BP-00 or BP-01 in pp.7) // const { bloodPressureMeasurementChar, customServiceChar } = this._getCharsCoopMode(); // await customServiceChar.writeWait([2, 0, 0xe1]); // bloodPressureMeasurementChar.registerNotifyWait((data: number[]) => { // results.push(this._analyzeData(data)); // }); // await this._writeTimeCharWait(this._timezoneOffsetMinute); // await this._writeCCCDChar(); const { bloodPressureMeasurementChar, timeChar, } = this._getCharsSingleMode(); await this._writeTimeCharWait(this._timezoneOffsetMinute); await bloodPressureMeasurementChar.registerNotifyWait((data) => { results.push(this._analyzeData(data)); }); return await new Promise((resolve, reject) => { if (!this._peripheral) return; this._peripheral.ondisconnect = (reason) => { resolve(results); if (this.ondisconnect) { this.ondisconnect(reason); } }; }); } _readSFLOAT_LE(buffer, index) { // convert SFLOAT Little Endian (not sfloat!) to numerical value const data = buffer.readUInt16LE(index); let mantissa = data & 0x0fff; if ((mantissa & 0x0800) > 0) { mantissa = -1 * (~(mantissa - 0x01) & 0x0fff); } const exponential = data >> 12; return mantissa * Math.pow(10, exponential); } _analyzeData(data) { const buf = Buffer.from(data); const flags = buf.readUInt8(0); let index = 1; const result = {}; if (flags & 0x01) { // Blood Pressure Unit Flag // kPa result.SystolicPressure_kPa = this._readSFLOAT_LE(buf, index); index += 2; result.DiastolicPressure_kPa = this._readSFLOAT_LE(buf, index); index += 2; result.MeanArterialPressure_kPa = this._readSFLOAT_LE(buf, index); index += 2; } else { // mmHg result.SystolicPressure_mmHg = this._readSFLOAT_LE(buf, index); index += 2; result.DiastolicPressure_mmHg = this._readSFLOAT_LE(buf, index); index += 2; result.MeanArterialPressure_mmHg = this._readSFLOAT_LE(buf, index); index += 2; } if (flags & 0x02) { // Time Stamp Flag // TODO: get Time stamp // result.date = { // year: buf.readUInt16LE(index), // month: buf.readUInt8(index + 2), // day: buf.readUInt8(index + 3), // hour: buf.readUInt8(index + 4), // minute: buf.readUInt8(index + 5), // second: buf.readUInt8(index + 6), // }; index += 7; } if (flags & 0x04) { // Pulse Rate Flag result.PulseRate = this._readSFLOAT_LE(buf, index); index += 2; } if (flags & 0x08) { // UserIdFlag index += 1; } if (flags & 0x10) { // UserIdFlag const ms = buf[index]; result.bodyMoved = (ms & 0b1) !== 0; result.cuffFitLoose = (ms & 0b10) !== 0; result.irregularPulseDetected = (ms & 0b100) !== 0; result.improperMeasurement = (ms & 0b100000) !== 0; index += 1; } return result; } _getCharsCoopMode() { if (!this._peripheral) { throw new Error('UA1200BLE not found'); } const bloodPressureMeasurementChar = this._peripheral .getService('1810') .getCharacteristic('2A35'); const customServiceChar = this._peripheral .getService('233bf0005a341b6d975c000d5690abe4') // Primary Service Custom Service(pp.26) .getCharacteristic('233bf0015a341b6d975c000d5690abe4'); // Custom Characteristic(pp.27) return { bloodPressureMeasurementChar, customServiceChar, }; } _getCharsSingleMode() { if (!this._peripheral) { throw new Error('UA1200BLE not found'); } const bloodPressureMeasurementChar = this._peripheral .getService('1810') .getCharacteristic('2A35'); const timeChar = this._peripheral .getService('1805') .getCharacteristic('2A2B'); // const CCCDChar = this._peripheral.getService("1810")!.getCharacteristic("2902")!; return { bloodPressureMeasurementChar, timeChar, // CCCDChar, }; } async _writeTimeCharWait(timeOffsetMinute) { const { timeChar } = this._getCharsSingleMode(); const date = new Date(); date.setTime(Date.now() + 1000 * 60 * timeOffsetMinute); const buf = Buffer.alloc(9); // Current Time Service(pp.11) buf.writeUInt16LE(date.getUTCFullYear(), 0); buf.writeUInt8(date.getUTCMonth() + 1, 2); buf.writeUInt8(date.getUTCDate(), 3); buf.writeUInt8(date.getUTCHours(), 4); buf.writeUInt8(date.getUTCMinutes(), 5); buf.writeUInt8(date.getUTCSeconds(), 6); buf.writeUInt8(date.getDay(), 7); buf.writeUInt8(0, 8); const arr = Array.from(buf); await timeChar.writeWait(arr); } } exports.default = UA1200BLE;