UNPKG

gd-ant-plus

Version:

A node module for ANT+ - forked from longhorn/ant-plus

176 lines 7.54 kB
"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.BicyclePowerScanner = exports.BicyclePowerSensor = void 0; const Ant = require("./ant"); const Constants = Ant.Constants; const Messages = Ant.Messages; class BicyclePowerSensorState { constructor(deviceID) { this.offset = 0; this.DeviceID = deviceID; } } class BicyclePowerScanState extends BicyclePowerSensorState { } class BicyclePowerSensor extends Ant.AntPlusSensor { constructor(stick) { super(stick); this.decodeDataCbk = this.decodeData.bind(this); } attach(channel, deviceID) { super.attach(channel, 'receive', deviceID, BicyclePowerSensor.deviceType, 0, 255, 8182); this.state = new BicyclePowerSensorState(deviceID); } decodeData(data) { if (data.readUInt8(Messages.BUFFER_INDEX_CHANNEL_NUM) !== this.channel) { return; } switch (data.readUInt8(Messages.BUFFER_INDEX_MSG_TYPE)) { case Constants.MESSAGE_CHANNEL_BROADCAST_DATA: case Constants.MESSAGE_CHANNEL_ACKNOWLEDGED_DATA: case Constants.MESSAGE_CHANNEL_BURST_DATA: if (this.deviceID === 0) { this.write(Messages.requestMessage(this.channel, Constants.MESSAGE_CHANNEL_ID)); } updateState(this, this.state, data); break; case Constants.MESSAGE_CHANNEL_ID: this.deviceID = data.readUInt16LE(Messages.BUFFER_INDEX_MSG_DATA); this.transmissionType = data.readUInt8(Messages.BUFFER_INDEX_MSG_DATA + 3); this.state.DeviceID = this.deviceID; break; default: break; } } } exports.BicyclePowerSensor = BicyclePowerSensor; BicyclePowerSensor.deviceType = 0x0B; class BicyclePowerScanner extends Ant.AntPlusScanner { constructor(stick) { super(stick); this.states = {}; this.decodeDataCbk = this.decodeData.bind(this); } scan() { super.scan('receive'); } decodeData(data) { if (data.length <= Messages.BUFFER_INDEX_EXT_MSG_BEGIN || !(data.readUInt8(Messages.BUFFER_INDEX_EXT_MSG_BEGIN) & 0x80)) { console.log('wrong message format'); return; } const deviceId = data.readUInt16LE(Messages.BUFFER_INDEX_EXT_MSG_BEGIN + 1); const deviceType = data.readUInt8(Messages.BUFFER_INDEX_EXT_MSG_BEGIN + 3); if (deviceType !== BicyclePowerScanner.deviceType) { return; } if (!this.states[deviceId]) { this.states[deviceId] = new BicyclePowerScanState(deviceId); } if (data.readUInt8(Messages.BUFFER_INDEX_EXT_MSG_BEGIN) & 0x40) { if (data.readUInt8(Messages.BUFFER_INDEX_EXT_MSG_BEGIN + 5) === 0x20) { this.states[deviceId].Rssi = data.readInt8(Messages.BUFFER_INDEX_EXT_MSG_BEGIN + 6); this.states[deviceId].Threshold = data.readInt8(Messages.BUFFER_INDEX_EXT_MSG_BEGIN + 7); } } switch (data.readUInt8(Messages.BUFFER_INDEX_MSG_TYPE)) { case Constants.MESSAGE_CHANNEL_BROADCAST_DATA: case Constants.MESSAGE_CHANNEL_ACKNOWLEDGED_DATA: case Constants.MESSAGE_CHANNEL_BURST_DATA: updateState(this, this.states[deviceId], data); break; default: break; } } } exports.BicyclePowerScanner = BicyclePowerScanner; BicyclePowerScanner.deviceType = 0x0B; function updateState(sensor, state, data) { const page = data.readUInt8(Messages.BUFFER_INDEX_MSG_DATA); switch (page) { case 0x01: { const calID = data.readUInt8(Messages.BUFFER_INDEX_MSG_DATA + 1); if (calID === 0x10) { const calParam = data.readUInt8(Messages.BUFFER_INDEX_MSG_DATA + 2); if (calParam === 0x01) { state.offset = data.readUInt16LE(Messages.BUFFER_INDEX_MSG_DATA + 6); } } break; } case 0x10: { const pedalPower = data.readUInt8(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; } } else { state.PedalPower = undefined; state.RightPedalPower = undefined; state.LeftPedalPower = undefined; } const cadence = data.readUInt8(Messages.BUFFER_INDEX_MSG_DATA + 3); if (cadence !== 0xFF) { state.Cadence = cadence; } else { state.Cadence = undefined; } state.AccumulatedPower = data.readUInt16LE(Messages.BUFFER_INDEX_MSG_DATA + 4); state.Power = data.readUInt16LE(Messages.BUFFER_INDEX_MSG_DATA + 6); break; } case 0x20: { const oldEventCount = state.EventCount; const oldTimeStamp = state.TimeStamp; const oldTorqueTicksStamp = state.TorqueTicksStamp; let eventCount = data.readUInt8(Messages.BUFFER_INDEX_MSG_DATA + 1); const slope = data.readUInt16LE(Messages.BUFFER_INDEX_MSG_DATA + 3); let timeStamp = data.readUInt16LE(Messages.BUFFER_INDEX_MSG_DATA + 5); let torqueTicksStamp = data.readUInt16LE(Messages.BUFFER_INDEX_MSG_DATA + 7); if (timeStamp !== oldTimeStamp && eventCount !== oldEventCount) { state.EventCount = eventCount; if (oldEventCount > eventCount) { //Hit rollover value eventCount += 255; } state.TimeStamp = timeStamp; if (oldTimeStamp > timeStamp) { //Hit rollover value timeStamp += 65400; } state.Slope = slope; state.TorqueTicksStamp = torqueTicksStamp; if (oldTorqueTicksStamp > torqueTicksStamp) { //Hit rollover value torqueTicksStamp += 65535; } const elapsedTime = (timeStamp - oldTimeStamp) * 0.0005; const torqueTicks = torqueTicksStamp - oldTorqueTicksStamp; const cadencePeriod = elapsedTime / (eventCount - oldEventCount); // s const cadence = Math.round(60 / cadencePeriod); // rpm state.CalculatedCadence = cadence; const torqueFrequency = (1 / (elapsedTime / torqueTicks)) - state.offset; // Hz const torque = torqueFrequency / (slope / 10); // Nm state.CalculatedTorque = torque; state.CalculatedPower = torque * cadence * Math.PI / 30; // Watts } break; } default: return; } sensor.emit('powerData', state); } //# sourceMappingURL=bicycle-power-sensors.js.map