UNPKG

incyclist-ant-plus

Version:

Incyclist library for ANT+ - originally forked from longhorn/ant-plus

314 lines (313 loc) 14.3 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.BicyclePowerSensorState = void 0; const consts_1 = require("../consts"); const messages_1 = require("../messages"); const base_sensor_1 = __importStar(require("./base-sensor")); class BicyclePowerSensorState extends base_sensor_1.SensorState { constructor() { super(...arguments); this.Cadence = undefined; this.CalculatedCadence = undefined; this.Power = undefined; this.CalculatedPower = undefined; this.CalculatedTorque = undefined; this.Offset = 0; this._0x10_EventCount = 0; this._0x10_UpdateTime = Date.now(); this.PedalPower = undefined; this.RightPedalPower = undefined; this.LeftPedalPower = undefined; this.AccumulatedPower = 0; this._0x12_EventCount = 0; this._0x12_UpdateTime = Date.now(); this.CrankTicks = 0; this.AccumulatedCrankPeriod = 0; this.AccumulatedTorque = 0; this._0x20_EventCount = 0; this._0x20_EventRepeat = 0; this.Slope = 0; this.TimeStamp = 0; this.CrankTicksStamp = 0; this.TorqueTicksStamp = 0; } } exports.BicyclePowerSensorState = BicyclePowerSensorState; const DEVICE_TYPE = 0x0B; const PROFILE = 'PWR'; const PERIOD = 8182; class BicyclePowerSensor extends base_sensor_1.default { constructor() { super(...arguments); this.states = {}; } getDeviceType() { return DEVICE_TYPE; } getProfile() { return PROFILE; } getDeviceID() { return this.deviceID; } getChannelConfiguration() { return { type: 'receive', transmissionType: 0, timeout: consts_1.Constants.TIMEOUT_NEVER, period: PERIOD, frequency: 57 }; } onEvent(data) { return; } onMessage(data) { const channel = this.getChannel(); if (!channel) return; const channelNo = channel.getChannelNo(); const deviceID = data.readUInt16LE(messages_1.Messages.BUFFER_INDEX_EXT_MSG_BEGIN + 1); const deviceType = data.readUInt8(messages_1.Messages.BUFFER_INDEX_EXT_MSG_BEGIN + 3); if (data.readUInt8(messages_1.Messages.BUFFER_INDEX_CHANNEL_NUM) !== channelNo || deviceType !== this.getDeviceType()) { return; } if (!this.states[deviceID]) { this.states[deviceID] = new BicyclePowerSensorState(deviceID); this.states[deviceID].Channel = this.channel.getChannelNo(); } if (data.readUInt8(messages_1.Messages.BUFFER_INDEX_EXT_MSG_BEGIN) & 0x40) { if (data.readUInt8(messages_1.Messages.BUFFER_INDEX_EXT_MSG_BEGIN + 5) === 0x20) { this.states[deviceID].Rssi = data.readInt8(messages_1.Messages.BUFFER_INDEX_EXT_MSG_BEGIN + 6); this.states[deviceID].Threshold = data.readInt8(messages_1.Messages.BUFFER_INDEX_EXT_MSG_BEGIN + 7); } } switch (data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_TYPE)) { case consts_1.Constants.MESSAGE_CHANNEL_BROADCAST_DATA: case consts_1.Constants.MESSAGE_CHANNEL_ACKNOWLEDGED_DATA: case consts_1.Constants.MESSAGE_CHANNEL_BURST_DATA: updateState(this.states[deviceID], data); if (this.deviceID === 0 || this.deviceID === deviceID) { channel.onDeviceData(this.getProfile(), deviceID, this.states[deviceID]); } break; default: break; } } } exports.default = BicyclePowerSensor; function updateState(state, data) { state._RawData = data; const page = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA); switch (page) { case 0x01: { const calID = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 1); if (calID === 0x10) { const calParam = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 2); if (calParam === 0x01) { state.Offset = data.readUInt16LE(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 6); } } break; } case 0x10: { const oldUpdateTime = state._0x10_UpdateTime; const oldEventCount = state._0x10_EventCount; const oldAccumulatedPower = state.AccumulatedPower; const oldCadence = state.Cadence | 62.5; let delay = 125000 / oldCadence; const eventTime = Date.now(); const eventCount = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 1); const accumulatedPower = data.readUInt16LE(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 4); if ((oldAccumulatedPower === accumulatedPower) && (eventTime - oldUpdateTime >= delay)) { state.Cadence = state.Cadence === undefined ? undefined : 0; state.Power = 0; } else if (oldEventCount !== eventCount) { state._0x10_UpdateTime = eventTime; state._0x10_EventCount = eventCount; state.AccumulatedPower = accumulatedPower; const pedalPower = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 2); if (pedalPower !== 0xFF) { if (pedalPower & 0x80) { state.PedalPower = pedalPower & 0x7F; state.RightPedalPower = state.PedalPower; state.LeftPedalPower = 100 - state.RightPedalPower; } else { state.PedalPower = pedalPower & 0x7F; state.RightPedalPower = undefined; state.LeftPedalPower = undefined; } } let cadence = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 3); state.Cadence = cadence === 0xFF ? undefined : cadence; state.Power = data.readUInt16LE(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 6); } break; } case 0x12: { const oldUpdateTime = state._0x12_UpdateTime; const oldEventCount = state._0x12_EventCount; const oldCrankTicks = state.CrankTicks; const oldAccumulatedPeriod = state.AccumulatedCrankPeriod; const oldAccumulatedTorque = state.AccumulatedTorque; const oldCadence = state.Cadence | 62.5; let delay = 125000 / oldCadence; const eventTime = Date.now(); let eventCount = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 1); if ((oldEventCount === eventCount) && (eventTime - oldUpdateTime >= delay)) { state.Cadence = state.Cadence === undefined ? undefined : 0; state.CalculatedTorque = 0; state.CalculatedPower = 0; state.CalculatedCadence = 0; } else { state._0x12_UpdateTime = eventTime; state._0x12_EventCount = eventCount; if (oldEventCount > eventCount) { eventCount += 256; } let crankTicks = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 2); state.CrankTicks = crankTicks; if (oldCrankTicks > crankTicks) { crankTicks += 256; } let cadence = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 3); state.Cadence = cadence === 0xFF ? undefined : cadence; let accumulatedPeriod = data.readUInt16LE(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 4); state.AccumulatedCrankPeriod = accumulatedPeriod; if (oldAccumulatedPeriod > accumulatedPeriod) { accumulatedPeriod += 65536; } let accumulatedTorque = data.readUInt16LE(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 6); state.AccumulatedTorque = accumulatedTorque; if (oldAccumulatedTorque > accumulatedTorque) { accumulatedTorque += 65536; } const rotationEvents = eventCount - oldEventCount; const rotationPeriod = (accumulatedPeriod - oldAccumulatedPeriod) / 2048; const angularVel = 2 * Math.PI * rotationEvents / rotationPeriod; const torque = (accumulatedTorque - oldAccumulatedTorque) / (32 * rotationEvents); state.CalculatedTorque = torque; state.CalculatedPower = angularVel * torque; state.CalculatedCadence = 60 * rotationEvents / rotationPeriod; } break; } case 0x20: { const oldEventCount = state._0x20_EventCount; const oldTimeStamp = state.TimeStamp; const oldTorqueTicksStamp = state.TorqueTicksStamp; let eventCount = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 1); const slope = data.readUInt16LE(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 3); let timeStamp = data.readUInt16LE(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 5); let torqueTicksStamp = data.readUInt16LE(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 7); if ((oldEventCount === eventCount) && (state._0x20_EventRepeat >= 12)) { state.CalculatedTorque = 0; state.CalculatedPower = 0; state.CalculatedCadence = 0; } else if (timeStamp !== oldTimeStamp && eventCount !== oldEventCount) { state._0x20_EventCount = eventCount; if (oldEventCount > eventCount) { eventCount += 255; } state.CrankTicksStamp = state.TimeStamp = timeStamp; if (oldTimeStamp > timeStamp) { timeStamp += 65400; } state.Slope = slope; state.TorqueTicksStamp = torqueTicksStamp; if (oldTorqueTicksStamp > torqueTicksStamp) { torqueTicksStamp += 65535; } const elapsedTime = (timeStamp - oldTimeStamp) * 0.0005; const torqueTicks = torqueTicksStamp - oldTorqueTicksStamp; const cadencePeriod = elapsedTime / (eventCount - oldEventCount); const cadence = Math.round(60 / cadencePeriod); state.CalculatedCadence = cadence; const torqueFrequency = (1 / (elapsedTime / torqueTicks)) - state.Offset; const torque = torqueFrequency / (slope / 10); state.CalculatedTorque = torque; state.CalculatedPower = torque * cadence * Math.PI / 30; } break; } case 0x50: { state.ManId = data.readUInt16LE(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 4); state.SerialNumber = state.DeviceID; state.SerialNumber |= data.readUInt16LE(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 2) << 16; state.SerialNumber >>>= 0; break; } case 0x51: { state.HwVersion = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 1); state.SwVersion = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 2); state.ModelNum = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 3); break; } case 0x52: { const batteryLevel = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 1); const batteryFrac = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 2); const batteryStatus = data.readUInt8(messages_1.Messages.BUFFER_INDEX_MSG_DATA + 3); if (batteryLevel !== 0xFF) { state.BatteryLevel = batteryLevel; } 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; } }