incyclist-devices 2.2.9 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/lib/antv2/base/interface.js +2 -2
  2. package/lib/antv2/factories/index.d.ts +1 -0
  3. package/lib/antv2/factories/index.js +17 -0
  4. package/lib/antv2/fe/adapter.js +5 -4
  5. package/lib/antv2/index.d.ts +1 -0
  6. package/lib/antv2/index.js +12 -8
  7. package/lib/base/adpater.js +1 -1
  8. package/lib/ble/adapter-factory.d.ts +20 -24
  9. package/lib/ble/adapter-factory.js +13 -36
  10. package/lib/ble/base/adapter.d.ts +16 -5
  11. package/lib/ble/base/adapter.js +169 -52
  12. package/lib/ble/base/comms.d.ts +2 -74
  13. package/lib/ble/base/comms.js +3 -596
  14. package/lib/ble/base/interface.d.ts +96 -0
  15. package/lib/ble/base/interface.js +544 -0
  16. package/lib/ble/base/peripheral.d.ts +34 -0
  17. package/lib/ble/base/peripheral.js +286 -0
  18. package/lib/ble/base/sensor.d.ts +31 -0
  19. package/lib/ble/base/sensor.js +130 -0
  20. package/lib/ble/base/types.d.ts +7 -0
  21. package/lib/ble/base/types.js +7 -0
  22. package/lib/ble/bindings/mock.js +6 -0
  23. package/lib/ble/bindings/types.d.ts +3 -4
  24. package/lib/ble/ble-interface.d.ts +7 -4
  25. package/lib/ble/ble-interface.js +16 -2
  26. package/lib/ble/ble-peripheral.d.ts +1 -0
  27. package/lib/ble/ble-peripheral.js +7 -11
  28. package/lib/ble/consts.d.ts +0 -6
  29. package/lib/ble/consts.js +1 -7
  30. package/lib/ble/cp/adapter.d.ts +3 -3
  31. package/lib/ble/cp/adapter.js +12 -13
  32. package/lib/ble/cp/comm.d.ts +1 -1
  33. package/lib/ble/cp/comm.js +2 -2
  34. package/lib/ble/cp/index.d.ts +1 -1
  35. package/lib/ble/cp/index.js +2 -2
  36. package/lib/ble/cp/sensor.d.ts +27 -0
  37. package/lib/ble/cp/sensor.js +107 -0
  38. package/lib/ble/elite/comms.d.ts +1 -1
  39. package/lib/ble/elite/comms.js +2 -2
  40. package/lib/ble/factories/adapter-factory.d.ts +32 -0
  41. package/lib/ble/factories/adapter-factory.js +104 -0
  42. package/lib/ble/factories/index.d.ts +2 -0
  43. package/lib/ble/factories/index.js +18 -0
  44. package/lib/ble/factories/interface-factory.d.ts +7 -0
  45. package/lib/ble/factories/interface-factory.js +18 -0
  46. package/lib/ble/fm/adapter.d.ts +9 -4
  47. package/lib/ble/fm/adapter.js +104 -108
  48. package/lib/ble/fm/comms.d.ts +1 -1
  49. package/lib/ble/fm/comms.js +3 -3
  50. package/lib/ble/fm/consts.d.ts +93 -0
  51. package/lib/ble/fm/consts.js +55 -1
  52. package/lib/ble/fm/index.d.ts +1 -1
  53. package/lib/ble/fm/index.js +2 -2
  54. package/lib/ble/fm/sensor.d.ts +44 -0
  55. package/lib/ble/fm/sensor.js +384 -0
  56. package/lib/ble/hr/adapter.d.ts +3 -3
  57. package/lib/ble/hr/adapter.js +5 -8
  58. package/lib/ble/hr/comm.d.ts +1 -1
  59. package/lib/ble/hr/comm.js +2 -2
  60. package/lib/ble/hr/index.d.ts +1 -1
  61. package/lib/ble/hr/index.js +2 -2
  62. package/lib/ble/hr/sensor.d.ts +17 -0
  63. package/lib/ble/hr/sensor.js +52 -0
  64. package/lib/ble/index.d.ts +4 -3
  65. package/lib/ble/index.js +29 -13
  66. package/lib/ble/tacx/adapter.d.ts +4 -2
  67. package/lib/ble/tacx/adapter.js +26 -66
  68. package/lib/ble/tacx/comms.d.ts +1 -1
  69. package/lib/ble/tacx/comms.js +2 -2
  70. package/lib/ble/tacx/consts.d.ts +23 -0
  71. package/lib/ble/tacx/consts.js +27 -0
  72. package/lib/ble/tacx/index.d.ts +1 -1
  73. package/lib/ble/tacx/index.js +2 -2
  74. package/lib/ble/tacx/sensor.d.ts +63 -0
  75. package/lib/ble/tacx/sensor.js +596 -0
  76. package/lib/ble/types.d.ts +81 -52
  77. package/lib/ble/utils.d.ts +7 -2
  78. package/lib/ble/utils.js +84 -9
  79. package/lib/ble/wahoo/adapter.d.ts +2 -2
  80. package/lib/ble/wahoo/adapter.js +4 -72
  81. package/lib/ble/wahoo/comms.d.ts +1 -1
  82. package/lib/ble/wahoo/comms.js +2 -2
  83. package/lib/ble/wahoo/consts.d.ts +16 -0
  84. package/lib/ble/wahoo/consts.js +7 -0
  85. package/lib/ble/wahoo/index.d.ts +1 -1
  86. package/lib/ble/wahoo/index.js +2 -2
  87. package/lib/ble/wahoo/sensor.d.ts +48 -0
  88. package/lib/ble/wahoo/sensor.js +356 -0
  89. package/lib/direct-connect/base/comms.d.ts +3 -0
  90. package/lib/direct-connect/base/comms.js +7 -0
  91. package/lib/direct-connect/base/interface.d.ts +75 -0
  92. package/lib/direct-connect/base/interface.js +306 -0
  93. package/lib/direct-connect/base/peripheral.d.ts +50 -0
  94. package/lib/direct-connect/base/peripheral.js +413 -0
  95. package/lib/direct-connect/base/sensor.d.ts +3 -0
  96. package/lib/direct-connect/base/sensor.js +7 -0
  97. package/lib/direct-connect/bindings/index.d.ts +1 -0
  98. package/lib/direct-connect/bindings/index.js +17 -0
  99. package/lib/direct-connect/bindings/types.d.ts +36 -0
  100. package/lib/direct-connect/bindings/types.js +2 -0
  101. package/lib/direct-connect/consts.d.ts +17 -0
  102. package/lib/direct-connect/consts.js +20 -0
  103. package/lib/direct-connect/index.d.ts +3 -0
  104. package/lib/direct-connect/index.js +22 -0
  105. package/lib/direct-connect/messages/CharacteristicNotification.d.ts +12 -0
  106. package/lib/direct-connect/messages/CharacteristicNotification.js +23 -0
  107. package/lib/direct-connect/messages/DiscoverCharacteristics.d.ts +22 -0
  108. package/lib/direct-connect/messages/DiscoverCharacteristics.js +43 -0
  109. package/lib/direct-connect/messages/DiscoverServices.d.ts +15 -0
  110. package/lib/direct-connect/messages/DiscoverServices.js +33 -0
  111. package/lib/direct-connect/messages/EnableCharacteristicNotifications.d.ts +18 -0
  112. package/lib/direct-connect/messages/EnableCharacteristicNotifications.js +35 -0
  113. package/lib/direct-connect/messages/ReadCharacteristic.d.ts +18 -0
  114. package/lib/direct-connect/messages/ReadCharacteristic.js +34 -0
  115. package/lib/direct-connect/messages/WriteCharacteristic.d.ts +18 -0
  116. package/lib/direct-connect/messages/WriteCharacteristic.js +36 -0
  117. package/lib/direct-connect/messages/error.d.ts +5 -0
  118. package/lib/direct-connect/messages/error.js +18 -0
  119. package/lib/direct-connect/messages/factory.d.ts +6 -0
  120. package/lib/direct-connect/messages/factory.js +44 -0
  121. package/lib/direct-connect/messages/index.d.ts +9 -0
  122. package/lib/direct-connect/messages/index.js +25 -0
  123. package/lib/direct-connect/messages/message.d.ts +20 -0
  124. package/lib/direct-connect/messages/message.js +90 -0
  125. package/lib/direct-connect/types.d.ts +24 -0
  126. package/lib/direct-connect/types.js +9 -0
  127. package/lib/direct-connect/utils.d.ts +5 -0
  128. package/lib/direct-connect/utils.js +73 -0
  129. package/lib/factories/adapters.js +16 -4
  130. package/lib/factories/interfaces.d.ts +2 -1
  131. package/lib/factories/interfaces.js +10 -7
  132. package/lib/index.d.ts +5 -4
  133. package/lib/index.js +6 -2
  134. package/lib/serial/bindings/tcp.d.ts +5 -4
  135. package/lib/serial/bindings/tcp.js +16 -23
  136. package/lib/types/device.d.ts +2 -1
  137. package/lib/types/device.js +1 -0
  138. package/lib/utils/operation.d.ts +17 -0
  139. package/lib/utils/operation.js +20 -0
  140. package/lib/utils/task.d.ts +44 -0
  141. package/lib/utils/task.js +127 -0
  142. package/package.json +3 -1
@@ -0,0 +1,596 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const consts_1 = require("../consts");
16
+ const consts_2 = require("./consts");
17
+ const sensor_1 = __importDefault(require("../fm/sensor"));
18
+ const utils_1 = require("../utils");
19
+ class TacxAdvancedFitnessMachineDevice extends sensor_1.default {
20
+ constructor(peripheral, props) {
21
+ super(peripheral, props);
22
+ this.prevCrankData = undefined;
23
+ this.currentCrankData = undefined;
24
+ this.timeOffset = 0;
25
+ this.tsPrevWrite = undefined;
26
+ this.prevMessages = {};
27
+ this.data = {};
28
+ this.hasFECData = false;
29
+ this.messageCnt = 0;
30
+ this.tacxRx = consts_2.TACX_FE_C_RX;
31
+ this.tacxTx = consts_2.TACX_FE_C_TX;
32
+ }
33
+ reset() {
34
+ this.data = {};
35
+ }
36
+ getRequiredCharacteristics() {
37
+ return [consts_1.INDOOR_BIKE_DATA, '2a37', consts_1.FTMS_STATUS, consts_1.CSP_MEASUREMENT, consts_1.CSC_MEASUREMENT, this.tacxRx];
38
+ }
39
+ onData(characteristic, data) {
40
+ const isDuplicate = this.isDuplicate(characteristic, data);
41
+ if (isDuplicate) {
42
+ return false;
43
+ }
44
+ this.messageCnt++;
45
+ try {
46
+ const uuid = characteristic.toLocaleLowerCase();
47
+ let res = undefined;
48
+ if (uuid && (0, utils_1.matches)(uuid, this.tacxRx)) {
49
+ res = this.parseFECMessage(data);
50
+ }
51
+ else {
52
+ switch (uuid) {
53
+ case consts_1.CSP_MEASUREMENT:
54
+ res = this.parsePower(data, this.hasFECData);
55
+ break;
56
+ case consts_1.INDOOR_BIKE_DATA:
57
+ res = this.parseIndoorBikeData(data, this.hasFECData);
58
+ break;
59
+ case '2a37':
60
+ res = this.parseHrm(data);
61
+ break;
62
+ case consts_1.CSC_MEASUREMENT:
63
+ res = this.parseCSC(data, this.hasFECData);
64
+ break;
65
+ case consts_1.FTMS_STATUS:
66
+ if (!this.hasFECData)
67
+ res = this.parseFitnessMachineStatus(data);
68
+ break;
69
+ default:
70
+ break;
71
+ }
72
+ }
73
+ if (res)
74
+ this.emit('data', res);
75
+ return res;
76
+ }
77
+ catch (err) {
78
+ this.logEvent({ message: 'error', fn: 'tacx.onData()', error: err.message || err, stack: err.stack });
79
+ }
80
+ }
81
+ isDuplicate(characteristic, data) {
82
+ const uuid = (0, utils_1.beautifyUUID)(characteristic);
83
+ const message = data.toString('hex');
84
+ const prev = this.prevMessages[uuid];
85
+ if ((prev === null || prev === void 0 ? void 0 : prev.message) === message && Date.now() - (prev === null || prev === void 0 ? void 0 : prev.ts) < 1000) {
86
+ return true;
87
+ }
88
+ this.prevMessages[uuid] = { ts: Date.now(), message };
89
+ return false;
90
+ }
91
+ setTargetPower(power) {
92
+ return __awaiter(this, void 0, void 0, function* () {
93
+ if (this.data.targetPower !== undefined && this.data.targetPower === power)
94
+ return true;
95
+ return yield this.sendTargetPower(power);
96
+ });
97
+ }
98
+ setSlope(slope) {
99
+ return __awaiter(this, void 0, void 0, function* () {
100
+ return yield this.sendTrackResistance(slope, this.crr);
101
+ });
102
+ }
103
+ requestControl() {
104
+ return __awaiter(this, void 0, void 0, function* () {
105
+ return true;
106
+ });
107
+ }
108
+ parseCrankData(crankData) {
109
+ if (!this.prevCrankData) {
110
+ this.prevCrankData = Object.assign(Object.assign({}, crankData), { cntUpdateMissing: -1 });
111
+ return {};
112
+ }
113
+ const c = this.currentCrankData = crankData;
114
+ const p = this.prevCrankData;
115
+ let rpm = this.data.cadence;
116
+ let hasUpdate = c.time !== p.time;
117
+ if (hasUpdate) {
118
+ let time = c.time - p.time;
119
+ let revs = c.revolutions - p.revolutions;
120
+ if (c.time < p.time) {
121
+ time += 0x10000;
122
+ this.timeOffset += 0x10000;
123
+ }
124
+ if (c.revolutions < p.revolutions)
125
+ revs += 0x10000;
126
+ rpm = 1024 * 60 * revs / time;
127
+ }
128
+ else if (p.cntUpdateMissing < 0 || p.cntUpdateMissing > 2) {
129
+ rpm = 0;
130
+ }
131
+ const cntUpdateMissing = p.cntUpdateMissing;
132
+ this.prevCrankData = this.currentCrankData;
133
+ if (hasUpdate)
134
+ this.prevCrankData.cntUpdateMissing = 0;
135
+ else
136
+ this.prevCrankData.cntUpdateMissing = cntUpdateMissing + 1;
137
+ return { rpm, time: this.timeOffset + c.time };
138
+ }
139
+ parseCSC(_data, logOnly = false) {
140
+ const data = Buffer.from(_data);
141
+ this.logEvent({ message: 'BLE CSC message', data: data.toString('hex') });
142
+ if (logOnly)
143
+ return this.data;
144
+ let offset = 0;
145
+ const flags = data.readUInt8(offset);
146
+ offset++;
147
+ if (flags & 0x01) {
148
+ offset += 6;
149
+ }
150
+ if (flags & 0x02) {
151
+ const crankData = {
152
+ revolutions: data.readUInt16LE(offset),
153
+ time: data.readUInt16LE(offset + 2)
154
+ };
155
+ const { rpm, time } = this.parseCrankData(crankData);
156
+ this.data.cadence = rpm;
157
+ this.data.time = time;
158
+ }
159
+ return this.data;
160
+ }
161
+ parsePower(_data, logOnly = false) {
162
+ const data = Buffer.from(_data);
163
+ this.logEvent({ message: 'BLE CSP message', data: data.toString('hex') });
164
+ if (logOnly)
165
+ return this.data;
166
+ try {
167
+ let offset = 4;
168
+ const flags = data.readUInt16LE(0);
169
+ this.data.instantaneousPower = data.readUInt16LE(2);
170
+ if (flags & 0x1)
171
+ data.readUInt8(offset++);
172
+ if (flags & 0x4) {
173
+ offset += 2;
174
+ }
175
+ if (flags & 0x10) {
176
+ offset += 6;
177
+ }
178
+ if (flags & 0x20) {
179
+ const crankData = {
180
+ revolutions: data.readUInt16LE(offset),
181
+ time: data.readUInt16LE(offset + 2)
182
+ };
183
+ const { rpm, time } = this.parseCrankData(crankData);
184
+ this.data.cadence = rpm;
185
+ this.data.time = time;
186
+ }
187
+ }
188
+ catch (err) {
189
+ this.logEvent({ message: 'error', fn: 'parsePower()', error: err.message || err, stack: err.stack });
190
+ }
191
+ const { instantaneousPower, cadence, time } = this.data;
192
+ return { instantaneousPower, cadence, time, raw: data.toString('hex') };
193
+ }
194
+ parseIndoorBikeData(_data, logOnly) {
195
+ this.logEvent({ message: 'BLE INDOOR_BIKE_DATA message', data: _data.toString('hex') });
196
+ if (logOnly)
197
+ return this.data;
198
+ return super.parseIndoorBikeData(_data);
199
+ }
200
+ resetState() {
201
+ const state = this.data;
202
+ delete state.time;
203
+ delete state.totalDistance;
204
+ delete state.RealSpeed;
205
+ delete state.VirtualSpeed;
206
+ delete state.heartrate;
207
+ delete state.HeartRateSource;
208
+ delete state.EventCount;
209
+ delete state.cadence;
210
+ delete state.AccumulatedPower;
211
+ delete state.instantaneousPower;
212
+ delete state.averagePower;
213
+ delete state.TrainerStatus;
214
+ delete state.TargetStatus;
215
+ }
216
+ parseFEState(capStateBF) {
217
+ switch ((capStateBF & 0x70) >> 4) {
218
+ case 1:
219
+ this.data.State = 'OFF';
220
+ break;
221
+ case 2:
222
+ this.data.State = 'READY';
223
+ this.resetState();
224
+ break;
225
+ case 3:
226
+ this.data.State = 'IN_USE';
227
+ break;
228
+ case 4:
229
+ this.data.State = 'FINISHED';
230
+ break;
231
+ default:
232
+ delete this.data.State;
233
+ break;
234
+ }
235
+ if (capStateBF & 0x80) {
236
+ }
237
+ }
238
+ parseGeneralFE(data) {
239
+ const equipmentTypeBF = data.readUInt8(1);
240
+ let elapsedTime = data.readUInt8(2);
241
+ let distance = data.readUInt8(3);
242
+ const speed = data.readUInt16LE(4);
243
+ const heartRate = data.readUInt8(6);
244
+ const capStateBF = data.readUInt8(7);
245
+ this.parseFEEquipmentType(equipmentTypeBF);
246
+ this.parseFEHeartrate(heartRate, capStateBF);
247
+ this.parseFETime(elapsedTime);
248
+ this.parseFEDistance(capStateBF, distance);
249
+ this.data.speed = speed / 1000;
250
+ this.parseFERealSpeed(capStateBF, speed);
251
+ this.parseFEState(capStateBF);
252
+ return this.data;
253
+ }
254
+ parseFEEquipmentType(equipmentTypeBF) {
255
+ switch (equipmentTypeBF & 0x1F) {
256
+ case 19:
257
+ this.data.EquipmentType = 'Treadmill';
258
+ break;
259
+ case 20:
260
+ this.data.EquipmentType = 'Elliptical';
261
+ break;
262
+ case 21:
263
+ this.data.EquipmentType = 'StationaryBike';
264
+ break;
265
+ case 22:
266
+ this.data.EquipmentType = 'Rower';
267
+ break;
268
+ case 23:
269
+ this.data.EquipmentType = 'Climber';
270
+ break;
271
+ case 24:
272
+ this.data.EquipmentType = 'NordicSkier';
273
+ break;
274
+ case 25:
275
+ this.data.EquipmentType = 'Trainer';
276
+ break;
277
+ default:
278
+ this.data.EquipmentType = 'General';
279
+ break;
280
+ }
281
+ }
282
+ parseFEHeartrate(heartRate, capStateBF) {
283
+ if (heartRate !== 0xFF) {
284
+ switch (capStateBF & 0x03) {
285
+ case 3: {
286
+ this.data.heartrate = heartRate;
287
+ this.data.HeartRateSource = 'HandContact';
288
+ break;
289
+ }
290
+ case 2: {
291
+ this.data.heartrate = heartRate;
292
+ this.data.HeartRateSource = 'EM';
293
+ break;
294
+ }
295
+ case 1: {
296
+ this.data.heartrate = heartRate;
297
+ this.data.HeartRateSource = 'ANT+';
298
+ break;
299
+ }
300
+ default: {
301
+ delete this.data.heartrate;
302
+ delete this.data.HeartRateSource;
303
+ break;
304
+ }
305
+ }
306
+ }
307
+ }
308
+ parseFETime(elapsedTime) {
309
+ elapsedTime /= 4;
310
+ const oldElapsedTime = (this.data.time || 0) % 64;
311
+ if (elapsedTime !== oldElapsedTime) {
312
+ if (oldElapsedTime > elapsedTime) {
313
+ elapsedTime += 64;
314
+ }
315
+ }
316
+ this.data.time = (this.data.time || 0) + elapsedTime - oldElapsedTime;
317
+ }
318
+ parseFEDistance(capStateBF, distance) {
319
+ if (capStateBF & 0x04) {
320
+ const oldDistance = (this.data.time || 0) % 256;
321
+ if (distance !== oldDistance) {
322
+ if (oldDistance > distance) {
323
+ distance += 256;
324
+ }
325
+ }
326
+ this.data.totalDistance = (this.data.totalDistance || 0) + distance - oldDistance;
327
+ }
328
+ else {
329
+ delete this.data.totalDistance;
330
+ }
331
+ }
332
+ parseFERealSpeed(capStateBF, speed) {
333
+ if (capStateBF & 0x08) {
334
+ this.data.VirtualSpeed = speed / 1000;
335
+ delete this.data.RealSpeed;
336
+ }
337
+ else {
338
+ delete this.data.VirtualSpeed;
339
+ this.data.RealSpeed = speed / 1000;
340
+ }
341
+ }
342
+ parseTrainerData(data) {
343
+ const oldEventCount = this.data.EventCount || 0;
344
+ let eventCount = data.readUInt8(1);
345
+ const cadence = data.readUInt8(2);
346
+ let accPower = data.readUInt16LE(3);
347
+ const power = data.readUInt16LE(5) & 0xFFF;
348
+ const trainerStatus = data.readUInt8(6) >> 4;
349
+ const flagStateBF = data.readUInt8(7);
350
+ if (eventCount !== oldEventCount) {
351
+ this.data.EventCount = eventCount;
352
+ if (oldEventCount > eventCount) {
353
+ eventCount += 255;
354
+ }
355
+ }
356
+ if (cadence !== 0xFF) {
357
+ this.data.cadence = cadence;
358
+ }
359
+ if (power !== 0xFFF) {
360
+ this.data.instantaneousPower = power;
361
+ const oldAccPower = (this.data.AccumulatedPower || 0) % 65536;
362
+ if (accPower !== oldAccPower) {
363
+ if (oldAccPower > accPower) {
364
+ accPower += 65536;
365
+ }
366
+ }
367
+ this.data.AccumulatedPower = (this.data.AccumulatedPower || 0) + accPower - oldAccPower;
368
+ this.data.averagePower = (accPower - oldAccPower) / (eventCount - oldEventCount);
369
+ }
370
+ this.data.TrainerStatus = trainerStatus;
371
+ switch (flagStateBF & 0x03) {
372
+ case 0:
373
+ this.data.TargetStatus = 'OnTarget';
374
+ break;
375
+ case 1:
376
+ this.data.TargetStatus = 'LowSpeed';
377
+ break;
378
+ case 2:
379
+ this.data.TargetStatus = 'HighSpeed';
380
+ break;
381
+ default:
382
+ delete this.data.TargetStatus;
383
+ break;
384
+ }
385
+ this.parseFEState(flagStateBF);
386
+ if (power !== undefined && cadence !== undefined)
387
+ this.hasFECData = true;
388
+ return this.data;
389
+ }
390
+ parseProductInformation(data) {
391
+ const swRevSup = data.readUInt8(2);
392
+ const swRevMain = data.readUInt8(3);
393
+ const serial = data.readInt32LE(4);
394
+ this.data.SwVersion = swRevMain;
395
+ if (swRevSup !== 0xFF) {
396
+ this.data.SwVersion += swRevSup / 1000;
397
+ }
398
+ if (serial !== 0xFFFFFFFF) {
399
+ this.data.SerialNumber = serial;
400
+ }
401
+ return this.data;
402
+ }
403
+ parseFECMessage(_data) {
404
+ const data = Buffer.from(_data);
405
+ this.logEvent({ message: 'FE-C message', data: data.toString('hex') });
406
+ const c = data.readUInt8(0);
407
+ if (c !== consts_2.SYNC_BYTE) {
408
+ this.logEvent({ message: 'SYNC missing', raw: data.toString('hex') });
409
+ return;
410
+ }
411
+ const len = data.readUInt8(1);
412
+ const messageId = data.readUInt8(4);
413
+ let res;
414
+ try {
415
+ switch (messageId) {
416
+ case consts_2.ANTMessages.generalFE:
417
+ res = this.parseGeneralFE(data.subarray(4, len + 3));
418
+ break;
419
+ case consts_2.ANTMessages.trainerData:
420
+ res = this.parseTrainerData(data.subarray(4, len + 3));
421
+ break;
422
+ case consts_2.ANTMessages.productInformation:
423
+ res = this.parseProductInformation(data.subarray(4, len + 3));
424
+ break;
425
+ }
426
+ if (res)
427
+ res.raw = data.toString('hex');
428
+ }
429
+ catch (err) {
430
+ this.logEvent({ message: 'error', fn: 'parseFECMessage()', error: err.message || err, stack: err.stack });
431
+ }
432
+ return res;
433
+ }
434
+ getChecksum(message) {
435
+ let checksum = 0;
436
+ message.forEach((byte) => {
437
+ checksum = (checksum ^ byte) % 0xFF;
438
+ });
439
+ return checksum;
440
+ }
441
+ buildMessage(payload = [], msgID = 0x00) {
442
+ const m = [];
443
+ m.push(consts_2.SYNC_BYTE);
444
+ m.push(payload.length);
445
+ m.push(msgID);
446
+ payload.forEach((byte) => {
447
+ m.push(byte);
448
+ });
449
+ m.push(this.getChecksum(m));
450
+ return Buffer.from(m);
451
+ }
452
+ sendMessage(message) {
453
+ return __awaiter(this, void 0, void 0, function* () {
454
+ this.logEvent({ message: 'write', characteristic: this.tacxTx, data: message.toString('hex') });
455
+ yield this.write(this.tacxTx, message, { withoutResponse: true });
456
+ return true;
457
+ });
458
+ }
459
+ sendUserConfiguration(userWeight, bikeWeight, wheelDiameter, gearRatio) {
460
+ return __awaiter(this, void 0, void 0, function* () {
461
+ const logStr = `sendUserConfiguration(${userWeight},${bikeWeight},${wheelDiameter},${gearRatio})`;
462
+ this.logEvent({ message: logStr });
463
+ let m = userWeight === undefined ? 0xFFFF : userWeight;
464
+ let mb = bikeWeight === undefined ? 0xFFF : bikeWeight;
465
+ let d = wheelDiameter === undefined ? 0xFF : wheelDiameter;
466
+ let gr = gearRatio === undefined ? 0x00 : gearRatio;
467
+ let dOffset = 0xFF;
468
+ if (m !== 0xFFFF)
469
+ m = Math.trunc(m * 100);
470
+ if (mb !== 0xFFF)
471
+ mb = Math.trunc(mb * 20);
472
+ if (d !== 0xFF) {
473
+ d = d * 1000;
474
+ dOffset = d % 10;
475
+ d = Math.trunc(d / 10);
476
+ }
477
+ if (gr !== 0x00) {
478
+ gr = Math.trunc(gr / 0.03);
479
+ }
480
+ const payload = [];
481
+ payload.push(consts_2.DEFAULT_CHANNEL);
482
+ payload.push(0x37);
483
+ payload.push(m & 0xFF);
484
+ payload.push((m >> 8) & 0xFF);
485
+ payload.push(0xFF);
486
+ payload.push(((mb & 0xF) << 4) | (dOffset & 0xF));
487
+ payload.push((mb >> 4) & 0xF);
488
+ payload.push(d & 0xFF);
489
+ payload.push(gr & 0xFF);
490
+ const data = this.buildMessage(payload, consts_2.ACKNOWLEDGED_DATA);
491
+ return yield this.sendMessage(data);
492
+ });
493
+ }
494
+ sendBasicResistance(resistance) {
495
+ return __awaiter(this, void 0, void 0, function* () {
496
+ const logStr = `sendBasicResistance(${resistance})`;
497
+ this.logEvent({ message: logStr });
498
+ let res = resistance === undefined ? 0 : resistance;
499
+ res = res / 0.5;
500
+ const payload = [];
501
+ payload.push(consts_2.DEFAULT_CHANNEL);
502
+ payload.push(0x30);
503
+ payload.push(0xFF);
504
+ payload.push(0xFF);
505
+ payload.push(0xFF);
506
+ payload.push(0xFF);
507
+ payload.push(0xFF);
508
+ payload.push(0xFF);
509
+ payload.push(res & 0xFF);
510
+ const data = this.buildMessage(payload, consts_2.ACKNOWLEDGED_DATA);
511
+ return yield this.sendMessage(data);
512
+ });
513
+ }
514
+ sendTargetPower(power) {
515
+ return __awaiter(this, void 0, void 0, function* () {
516
+ const logStr = `sendTargetPower(${power})`;
517
+ this.logEvent({ message: logStr });
518
+ let p = power === undefined ? 0x00 : power;
519
+ p = p * 4;
520
+ const payload = [];
521
+ payload.push(consts_2.DEFAULT_CHANNEL);
522
+ payload.push(0x31);
523
+ payload.push(0xFF);
524
+ payload.push(0xFF);
525
+ payload.push(0xFF);
526
+ payload.push(0xFF);
527
+ payload.push(0xFF);
528
+ payload.push(p & 0xFF);
529
+ payload.push((p >> 8) & 0xFF);
530
+ const data = this.buildMessage(payload, consts_2.ACKNOWLEDGED_DATA);
531
+ return yield this.sendMessage(data);
532
+ });
533
+ }
534
+ sendWindResistance(windCoeff, windSpeed, draftFactor) {
535
+ return __awaiter(this, void 0, void 0, function* () {
536
+ const logStr = `sendWindResistance(${windCoeff},${windSpeed},${draftFactor})`;
537
+ this.logEvent({ message: logStr });
538
+ let wc = windCoeff === undefined ? 0xFF : windCoeff;
539
+ let ws = windSpeed === undefined ? 0xFF : windSpeed;
540
+ let df = draftFactor === undefined ? 0xFF : draftFactor;
541
+ if (wc !== 0xFF) {
542
+ wc = Math.trunc(wc / 0.01);
543
+ }
544
+ if (ws !== 0xFF) {
545
+ ws = Math.trunc(ws + 127);
546
+ }
547
+ if (df !== 0xFF) {
548
+ df = Math.trunc(df / 0.01);
549
+ }
550
+ const payload = [];
551
+ payload.push(consts_2.DEFAULT_CHANNEL);
552
+ payload.push(0x32);
553
+ payload.push(0xFF);
554
+ payload.push(0xFF);
555
+ payload.push(0xFF);
556
+ payload.push(0xFF);
557
+ payload.push(wc & 0xFF);
558
+ payload.push(ws & 0xFF);
559
+ payload.push(df & 0xFF);
560
+ const data = this.buildMessage(payload, consts_2.ACKNOWLEDGED_DATA);
561
+ return yield this.sendMessage(data);
562
+ });
563
+ }
564
+ sendTrackResistance(slope, rrCoeff) {
565
+ return __awaiter(this, void 0, void 0, function* () {
566
+ const logStr = `sendTrackResistance(${slope},${rrCoeff})`;
567
+ this.logEvent({ message: logStr });
568
+ let s = slope === undefined ? 0xFFFF : slope;
569
+ let rr = rrCoeff === undefined ? 0xFF : rrCoeff;
570
+ if (s !== 0xFFFF) {
571
+ s = Math.trunc((s + 200) / 0.01);
572
+ }
573
+ if (rr !== 0xFF) {
574
+ rr = Math.trunc(rr / 0.00005);
575
+ }
576
+ const payload = [];
577
+ payload.push(consts_2.DEFAULT_CHANNEL);
578
+ payload.push(0x33);
579
+ payload.push(0xFF);
580
+ payload.push(0xFF);
581
+ payload.push(0xFF);
582
+ payload.push(0xFF);
583
+ payload.push(s & 0xFF);
584
+ payload.push((s >> 8) & 0xFF);
585
+ payload.push(rr & 0xFF);
586
+ const data = this.buildMessage(payload, consts_2.ACKNOWLEDGED_DATA);
587
+ return yield this.sendMessage(data);
588
+ });
589
+ }
590
+ }
591
+ TacxAdvancedFitnessMachineDevice.profile = 'Smart Trainer';
592
+ TacxAdvancedFitnessMachineDevice.protocol = 'tacx';
593
+ TacxAdvancedFitnessMachineDevice.services = [consts_2.TACX_FE_C_BLE];
594
+ TacxAdvancedFitnessMachineDevice.characteristics = ['2acc', '2ad2', '2ad6', '2ad8', '2ad9', '2ada', consts_2.TACX_FE_C_RX, consts_2.TACX_FE_C_TX];
595
+ TacxAdvancedFitnessMachineDevice.detectionPriority = 10;
596
+ exports.default = TacxAdvancedFitnessMachineDevice;