incyclist-ant-plus
Version:
Incyclist library for ANT+ - originally forked from longhorn/ant-plus
314 lines (313 loc) • 14.3 kB
JavaScript
"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;
}
}