ant-plus
Version:
A node module for ANT+
190 lines • 7.73 kB
JavaScript
"use strict";
/*
* ANT+ profile: https://www.thisisant.com/developer/ant-plus/device-profiles/#521_tab
* Spec sheet: https://www.thisisant.com/resources/bicycle-power/
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.MuscleOxygenScanner = exports.MuscleOxygenSensor = void 0;
const ant_1 = require("./ant");
class MuscleOxygenSensorState {
constructor(deviceID) {
this.DeviceID = deviceID;
}
}
class MuscleOxygenScanState extends MuscleOxygenSensorState {
}
class MuscleOxygenSensor extends ant_1.AntPlusSensor {
attach(channel, deviceID) {
super.attach(channel, 'receive', deviceID, MuscleOxygenSensor.deviceType, 0, 255, 8192);
this.state = new MuscleOxygenSensorState(deviceID);
}
updateState(deviceId, data) {
this.state.DeviceID = deviceId;
updateState(this, this.state, data);
}
_sendTimeCmd(cmd, cbk) {
const now = new Date();
const utc = Math.round((now.getTime() - Date.UTC(1989, 11, 31, 0, 0, 0, 0)) / 1000);
const offset = -Math.round(now.getTimezoneOffset() / 15);
const payload = [0x10, cmd & 0xFF, 0xFF, offset & 0xFF, (utc >> 0) & 0xFF, (utc >> 8) & 0xFF, (utc >> 16) & 0xFF, (utc >> 24) & 0xFF];
const msg = ant_1.Messages.acknowledgedData(this.channel, payload);
this.send(msg, cbk);
}
setUTCTime(cbk) {
this._sendTimeCmd(0x00, cbk);
}
startSession(cbk) {
this._sendTimeCmd(0x01, cbk);
}
stopSession(cbk) {
this._sendTimeCmd(0x02, cbk);
}
setLap(cbk) {
this._sendTimeCmd(0x03, cbk);
}
}
exports.MuscleOxygenSensor = MuscleOxygenSensor;
MuscleOxygenSensor.deviceType = 0x1F;
class MuscleOxygenScanner extends ant_1.AntPlusScanner {
constructor() {
super(...arguments);
this.states = {};
}
deviceType() {
return MuscleOxygenSensor.deviceType;
}
createStateIfNew(deviceId) {
if (!this.states[deviceId]) {
this.states[deviceId] = new MuscleOxygenScanState(deviceId);
}
}
updateRssiAndThreshold(deviceId, rssi, threshold) {
this.states[deviceId].Rssi = rssi;
this.states[deviceId].Threshold = threshold;
}
updateState(deviceId, data) {
updateState(this, this.states[deviceId], data);
}
}
exports.MuscleOxygenScanner = MuscleOxygenScanner;
function updateState(sensor, state, data) {
const oldEventCount = state._EventCount || 0;
const page = data.readUInt8(ant_1.Messages.BUFFER_INDEX_MSG_DATA);
switch (page) {
case 0x01: {
let eventCount = data.readUInt8(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 1);
const notifications = data.readUInt8(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 2);
const capabilities = data.readUInt16LE(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 3);
const total = data.readUInt16LE(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 4) & 0xFFF;
const previous = (data.readUInt16LE(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 5) >> 4) & 0x3FF;
const current = (data.readUInt16LE(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 6) >> 6) & 0x3FF;
if (eventCount !== oldEventCount) {
state._EventCount = eventCount;
if (oldEventCount > eventCount) { //Hit rollover value
eventCount += 255;
}
}
state.UTCTimeRequired = (notifications & 0x01) === 0x01;
state.SupportANTFS = (capabilities & 0x01) === 0x01;
switch ((capabilities >> 1) & 0x7) {
case 1:
state.MeasurementInterval = 0.25;
break;
case 2:
state.MeasurementInterval = 0.5;
break;
case 3:
state.MeasurementInterval = 1;
break;
case 4:
state.MeasurementInterval = 2;
break;
default: delete state.MeasurementInterval;
}
switch (total) {
case 0xFFE:
state.TotalHemoglobinConcentration = 'AmbientLightTooHigh';
break;
case 0xFFF:
state.TotalHemoglobinConcentration = 'Invalid';
break;
default: state.TotalHemoglobinConcentration = total;
}
switch (previous) {
case 0x3FE:
state.PreviousSaturatedHemoglobinPercentage = 'AmbientLightTooHigh';
break;
case 0x3FF:
state.PreviousSaturatedHemoglobinPercentage = 'Invalid';
break;
default: state.PreviousSaturatedHemoglobinPercentage = previous;
}
switch (current) {
case 0x3FE:
state.CurrentSaturatedHemoglobinPercentage = 'AmbientLightTooHigh';
break;
case 0x3FF:
state.CurrentSaturatedHemoglobinPercentage = 'Invalid';
break;
default: state.CurrentSaturatedHemoglobinPercentage = current;
}
break;
}
case 0x50: {
state.HwVersion = data.readUInt8(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 3);
state.ManId = data.readUInt16LE(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 4);
state.ModelNum = data.readUInt16LE(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 6);
break;
}
case 0x51: {
const swRevSup = data.readUInt8(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 2);
const swRevMain = data.readUInt8(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 3);
const serial = data.readInt32LE(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 4);
state.SwVersion = swRevMain;
if (swRevSup !== 0xFF) {
state.SwVersion += swRevSup / 1000;
}
if (serial !== 0xFFFFFFFF) {
state.SerialNumber = serial;
}
break;
}
case 0x52: {
const batteryId = data.readUInt8(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 2);
const operatingTime = data.readUInt32LE(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 3) & 0xFFFFFF;
const batteryFrac = data.readInt32LE(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 6);
const batteryStatus = data.readInt32LE(ant_1.Messages.BUFFER_INDEX_MSG_DATA + 7);
state.OperatingTime = operatingTime * (((batteryStatus & 0x80) === 0x80) ? 2 : 16);
state.BatteryVoltage = (batteryStatus & 0x0F) + (batteryFrac / 256);
const batteryFlags = (batteryStatus & 0x70) >>> 4;
switch (batteryFlags) {
case 1:
state.BatteryStatus = 'New';
break;
case 2:
state.BatteryStatus = 'Good';
break;
case 3:
state.BatteryStatus = 'Ok';
break;
case 4:
state.BatteryStatus = 'Low';
break;
case 5:
state.BatteryStatus = 'Critical';
break;
default:
state.BatteryVoltage = undefined;
state.BatteryStatus = 'Invalid';
break;
}
break;
}
default:
return;
}
if (page !== 0x01 || state._EventCount !== oldEventCount) {
sensor.emit('oxygenData', state);
}
}
//# sourceMappingURL=muscle-oxygen-sensors.js.map