incyclist-devices 1.3.0 → 1.4.1

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 (71) hide show
  1. package/lib/CyclingMode.d.ts +72 -0
  2. package/lib/CyclingMode.js +66 -0
  3. package/lib/Device.d.ts +48 -10
  4. package/lib/Device.js +9 -8
  5. package/lib/DeviceProtocol.d.ts +40 -12
  6. package/lib/DeviceProtocol.js +16 -16
  7. package/lib/DeviceRegistry.d.ts +4 -4
  8. package/lib/DeviceRegistry.js +10 -10
  9. package/lib/DeviceSupport.d.ts +4 -3
  10. package/lib/DeviceSupport.js +32 -8
  11. package/lib/ant/AntAdapter.d.ts +7 -3
  12. package/lib/ant/AntAdapter.js +23 -3
  13. package/lib/ant/AntScanner.d.ts +15 -6
  14. package/lib/ant/AntScanner.js +372 -128
  15. package/lib/ant/antfe/AntFEAdapter.d.ts +1 -1
  16. package/lib/ant/antfe/AntFEAdapter.js +191 -92
  17. package/lib/ant/anthrm/AntHrmAdapter.d.ts +3 -1
  18. package/lib/ant/anthrm/AntHrmAdapter.js +70 -19
  19. package/lib/ant/utils.js +2 -1
  20. package/lib/calculations.d.ts +12 -13
  21. package/lib/calculations.js +88 -125
  22. package/lib/daum/DaumAdapter.d.ts +29 -6
  23. package/lib/daum/DaumAdapter.js +219 -96
  24. package/lib/daum/ERGCyclingMode.d.ts +28 -0
  25. package/lib/daum/ERGCyclingMode.js +207 -0
  26. package/lib/daum/PowerMeterCyclingMode.d.ts +18 -0
  27. package/lib/daum/PowerMeterCyclingMode.js +79 -0
  28. package/lib/daum/SmartTrainerCyclingMode.d.ts +41 -0
  29. package/lib/daum/SmartTrainerCyclingMode.js +344 -0
  30. package/lib/daum/classic/DaumClassicAdapter.d.ts +3 -1
  31. package/lib/daum/classic/DaumClassicAdapter.js +46 -32
  32. package/lib/daum/classic/DaumClassicCyclingMode.d.ts +13 -0
  33. package/lib/daum/classic/DaumClassicCyclingMode.js +98 -0
  34. package/lib/daum/classic/DaumClassicProtocol.d.ts +5 -3
  35. package/lib/daum/classic/DaumClassicProtocol.js +47 -8
  36. package/lib/daum/classic/ERGCyclingMode.d.ts +23 -0
  37. package/lib/daum/classic/ERGCyclingMode.js +171 -0
  38. package/lib/daum/classic/bike.d.ts +41 -37
  39. package/lib/daum/classic/bike.js +86 -53
  40. package/lib/daum/classic/utils.d.ts +3 -3
  41. package/lib/daum/classic/utils.js +18 -10
  42. package/lib/daum/indoorbike.d.ts +2 -1
  43. package/lib/daum/indoorbike.js +23 -21
  44. package/lib/daum/premium/DaumPremiumAdapter.d.ts +2 -2
  45. package/lib/daum/premium/DaumPremiumAdapter.js +30 -20
  46. package/lib/daum/premium/DaumPremiumProtocol.d.ts +11 -2
  47. package/lib/daum/premium/DaumPremiumProtocol.js +57 -10
  48. package/lib/daum/premium/bike.d.ts +63 -52
  49. package/lib/daum/premium/bike.js +254 -207
  50. package/lib/daum/premium/tcpserial.d.ts +18 -14
  51. package/lib/daum/premium/tcpserial.js +44 -20
  52. package/lib/daum/premium/utils.d.ts +2 -2
  53. package/lib/simulator/Simulator.d.ts +13 -7
  54. package/lib/simulator/Simulator.js +62 -21
  55. package/lib/utils.d.ts +3 -1
  56. package/lib/utils.js +39 -18
  57. package/package.json +12 -11
  58. package/lib/ant/AntScanner.unit.tests.d.ts +0 -1
  59. package/lib/ant/AntScanner.unit.tests.js +0 -25
  60. package/lib/ant/antfe/AntFEProcessor.d.ts +0 -40
  61. package/lib/ant/antfe/AntFEProcessor.js +0 -238
  62. package/lib/ant/antfe/AntHrmProtocol.d.ts +0 -9
  63. package/lib/ant/antfe/AntHrmProtocol.js +0 -30
  64. package/lib/ant/antfe/FEDevice.d.ts +0 -1
  65. package/lib/ant/antfe/FEDevice.js +0 -7
  66. package/lib/ant/antfe/bike.d.ts +0 -47
  67. package/lib/ant/antfe/bike.js +0 -602
  68. package/lib/ant/anthrm/anthrm.d.ts +0 -33
  69. package/lib/ant/anthrm/anthrm.js +0 -523
  70. package/lib/simulator/Simulator.unit.tests.d.ts +0 -1
  71. package/lib/simulator/Simulator.unit.tests.js +0 -79
@@ -20,7 +20,7 @@ export default class AntFEAdapter extends AntAdapter {
20
20
  onDeviceEvent(data: any): void;
21
21
  updateData(data: any, deviceData: any): any;
22
22
  transformData(bikeData: any): any;
23
- start(props?: any): Promise<unknown>;
23
+ start(props?: any): Promise<any>;
24
24
  stop(): Promise<boolean>;
25
25
  sendUpdate(request: any): Promise<void>;
26
26
  send(msg: any, logStr: any, callback?: any, expectedResponse?: any): void;
@@ -8,19 +8,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
15
  const gd_eventlog_1 = require("gd-eventlog");
13
- const AntAdapter_1 = require("../AntAdapter");
16
+ const AntAdapter_1 = __importDefault(require("../AntAdapter"));
14
17
  const utils_1 = require("../utils");
15
18
  const utils_2 = require("../../utils");
16
19
  const floatVal = (d) => d ? parseFloat(d) : d;
17
20
  const intVal = (d) => d ? parseInt(d) : d;
21
+ const hex = (v) => Math.abs(v).toString(16).toUpperCase();
18
22
  const TIMEOUT_ACK = 5000;
19
23
  const TIMEOUT_START = 10000;
24
+ const TIMEOUT_ATTACH = 3000;
25
+ const DEFAULT_USER_WEIGHT = 75;
26
+ const DEFAULT_BIKE_WEIGHT = 12.75;
20
27
  class AntFEAdapter extends AntAdapter_1.default {
21
28
  constructor(DeviceID, port, stick, protocol) {
22
29
  super(protocol);
23
30
  this.logger = new gd_eventlog_1.EventLogger('Ant+FE');
31
+ this.logger.logEvent({ message: 'Ant+FE Adapter created', DeviceID, port });
24
32
  this.deviceID = DeviceID;
25
33
  this.port = port;
26
34
  this.stick = stick;
@@ -44,18 +52,20 @@ class AntFEAdapter extends AntAdapter_1.default {
44
52
  getDisplayName() {
45
53
  const { DeviceID, ManId, ComputedHeartRate } = this.deviceData;
46
54
  const hrmStr = ComputedHeartRate ? ` (${ComputedHeartRate})` : '';
47
- return `${utils_1.getBrand(ManId)} FE ${DeviceID}${hrmStr}`;
55
+ return `${(0, utils_1.getBrand)(ManId)} FE ${DeviceID}${hrmStr}`;
48
56
  }
49
57
  onAttached() {
58
+ this.logger.logEvent({ message: 'Device connected' });
50
59
  this.connected = true;
51
60
  }
52
61
  onDeviceData(deviceData) {
53
- if (!this.started)
62
+ if (!this.started || this.isStopped())
54
63
  return;
55
64
  this.deviceData = deviceData;
56
65
  try {
57
66
  if (this.onDataFn && !(this.ignoreHrm && this.ignoreBike && this.ignorePower) && !this.paused) {
58
67
  if (!this.lastUpdate || (Date.now() - this.lastUpdate) > this.updateFrequency) {
68
+ this.logger.logEvent({ message: 'onDeviceData', data: deviceData });
59
69
  this.data = this.updateData(this.data, deviceData);
60
70
  const data = this.transformData(this.data);
61
71
  this.onDataFn(data);
@@ -68,40 +78,45 @@ class AntFEAdapter extends AntAdapter_1.default {
68
78
  }
69
79
  onDeviceEvent(data) {
70
80
  try {
71
- let stick = this.stick;
72
- const msg = this.currentCmd && this.currentCmd.msg ? this.currentCmd.msg.readUInt8(2) : '';
73
- const cmdInfo = this.currentCmd || {};
81
+ const cmdInfo = this.currentCmd;
82
+ if (!cmdInfo)
83
+ return;
84
+ const msg = cmdInfo.msg.readUInt8(2);
74
85
  const Constants = this.getProtocol().getAnt().Constants;
75
86
  const { expectedResponse } = cmdInfo;
76
- if (this.currentCmd !== undefined && data.message === msg && expectedResponse === undefined && data.code === 0) {
77
- this.currentCmd.response = { success: true };
78
- return;
79
- }
80
- if (this.currentCmd !== undefined && data.message === msg && data.code !== 0) {
81
- this.currentCmd.response = { success: false };
82
- return;
83
- }
84
- if (this.currentCmd !== undefined && data.message === 1 && expectedResponse === undefined && (data.code === 5 || data.code === 3)) {
85
- this.currentCmd.response = { success: true };
86
- return;
87
- }
88
- if (this.currentCmd !== undefined && data.message === 1 && expectedResponse !== undefined && data.code === expectedResponse) {
89
- this.currentCmd.response = { success: true };
90
- return;
87
+ if (data.message === msg) {
88
+ if (expectedResponse === undefined && data.code === Constants.EVENT_TRANSFER_TX_COMPLETED) {
89
+ this.currentCmd.response = { success: true, message: hex(data.message), code: hex(data.code) };
90
+ return;
91
+ }
92
+ if (expectedResponse === undefined && data.code !== Constants.EVENT_TRANSFER_TX_COMPLETED) {
93
+ this.currentCmd.response = { success: false, message: hex(data.message), code: hex(data.code) };
94
+ return;
95
+ }
91
96
  }
92
- if (this.currentCmd !== undefined && data.message === 1 && data.code === 6) {
93
- this.stick.write(this.currentCmd.msg);
94
- this.currentCmd.response = { success: false };
95
- return;
97
+ if (data.message === 1) {
98
+ if (expectedResponse !== undefined && data.code === expectedResponse) {
99
+ this.currentCmd.response = { success: true, message: hex(data.message), code: hex(data.code) };
100
+ return;
101
+ }
102
+ if (expectedResponse === undefined && (data.code === Constants.EVENT_TRANSFER_TX_COMPLETED || data.code === 3)) {
103
+ this.currentCmd.response = { success: true, message: hex(data.message), code: hex(data.code) };
104
+ return;
105
+ }
106
+ if (data.code === Constants.EVENT_TRANSFER_TX_FAILED || data.code === Constants.EVENT_CHANNEL_COLLISION) {
107
+ this.currentCmd.response = { success: false, message: hex(data.message), code: hex(data.code) };
108
+ return;
109
+ }
96
110
  }
97
111
  if (this.currentCmd !== undefined && data.message === Constants.MESSAGE_CHANNEL_ACKNOWLEDGED_DATA && data.code === 31) {
98
112
  this.logger.log("could not send (TRANSFER_IN_PROGRESS)");
113
+ this.currentCmd.response = { success: false, message: hex(data.message), code: hex(data.code) };
99
114
  return;
100
115
  }
101
- this.logger.logEvent({ message: "Incoming Event ", event: data });
116
+ this.logger.logEvent({ message: "Incoming Event ", event: { message: hex(data.message), code: hex(data.code) } });
102
117
  }
103
118
  catch (err) {
104
- this.logger.logEvent({ message: 'Error', fn: 'parseEvent', data: utils_2.hexstr(data), error: err.message });
119
+ this.logger.logEvent({ message: 'Error', fn: 'parseEvent', event: { message: hex(data.message), code: hex(data.code) }, error: err.message || err });
105
120
  }
106
121
  }
107
122
  updateData(data, deviceData) {
@@ -112,10 +127,18 @@ class AntFEAdapter extends AntAdapter_1.default {
112
127
  data.power = (deviceData.InstantaneousPower !== undefined ? deviceData.InstantaneousPower : data.power);
113
128
  data.pedalRpm = (deviceData.Cadence !== undefined ? deviceData.Cadence : data.pedalRpm);
114
129
  data.heartrate = (deviceData.HeartRate !== undefined ? deviceData.HeartRate : data.heartrate);
115
- if (deviceData.Distance !== undefined) {
130
+ if (deviceData.Distance !== undefined && deviceData.Distance !== 0) {
116
131
  data.distanceInternal = deviceData.Distance - data.distanceOffs;
117
132
  data.distance = data.distanceInternal / 1000;
118
133
  }
134
+ else {
135
+ if (this.lastUpdate && deviceData.Cadence !== undefined && deviceData.Cadence > 0 && data.speed) {
136
+ const t = (Date.now() - this.lastUpdate) / 1000;
137
+ const prevDistance = data.distanceInternal || 0;
138
+ data.distanceInternal = Math.round(data.speed / 3.6 * t) + prevDistance;
139
+ data.distance = data.distanceInternal / 1000;
140
+ }
141
+ }
119
142
  return data;
120
143
  }
121
144
  transformData(bikeData) {
@@ -148,102 +171,156 @@ class AntFEAdapter extends AntAdapter_1.default {
148
171
  return data;
149
172
  }
150
173
  start(props) {
174
+ const _super = Object.create(null, {
175
+ start: { get: () => super.start }
176
+ });
151
177
  return __awaiter(this, void 0, void 0, function* () {
178
+ yield _super.start.call(this, props);
152
179
  this.logger.logEvent({ message: 'start()' });
153
- const opts = props || {};
180
+ const args = props || {};
154
181
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
155
- if (this.ignoreHrm && this.ignoreBike && this.ignorePower)
182
+ if (this.ignoreHrm && this.ignoreBike && this.ignorePower) {
183
+ this.logger.logEvent({ message: 'start() not done: bike disabled' });
156
184
  return resolve(false);
185
+ }
157
186
  if (this.starting) {
187
+ this.logger.logEvent({ message: 'start() not done: bike starting' });
158
188
  return resolve(false);
159
189
  }
160
190
  if (this.started) {
191
+ this.logger.logEvent({ message: 'start() done: bike was already started' });
192
+ this.startWorker();
161
193
  return resolve(true);
162
194
  }
163
195
  this.starting = true;
164
196
  const Ant = this.getProtocol().getAnt();
165
197
  const protocol = this.getProtocol();
166
- protocol.attachSensors(this, Ant.FitnessEquipmentSensor, 'fitnessData')
167
- .then(() => __awaiter(this, void 0, void 0, function* () {
198
+ let start = Date.now();
199
+ let timeout = start + (args.timeout || TIMEOUT_ATTACH);
200
+ const ivAttach = setInterval(() => {
201
+ if (Date.now() > timeout) {
202
+ clearInterval(ivAttach);
203
+ this.starting = false;
204
+ reject(new Error('timeout'));
205
+ }
206
+ if (this.isStopped()) {
207
+ clearInterval(ivAttach);
208
+ this.starting = false;
209
+ reject(new Error('stopped'));
210
+ }
211
+ }, 100);
212
+ try {
213
+ if (!this.connected) {
214
+ this.logger.logEvent({ message: 'attach device ...' });
215
+ yield protocol.attachSensors(this, Ant.FitnessEquipmentSensor, 'fitnessData');
216
+ }
217
+ clearInterval(ivAttach);
168
218
  this.startWorker();
169
219
  const tsStart = Date.now();
170
220
  const iv = setInterval(() => __awaiter(this, void 0, void 0, function* () {
171
221
  if (this.connected) {
172
222
  clearInterval(iv);
173
- try {
174
- yield this.sendTrackResistance(0.0);
175
- yield this.sendUserConfiguration(opts.userWeight || 72, opts.bikeWeight || 12.75, opts.wheelDiameter, opts.gearRatio);
176
- }
177
- catch (err) {
178
- console.log('~~~err:', err);
179
- }
180
- this.started = true;
181
- this.starting = false;
182
- resolve(true);
223
+ let status = {
224
+ trackResistanceSent: false,
225
+ userSent: false,
226
+ };
227
+ (0, utils_2.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () {
228
+ if (this.isStopped())
229
+ resolve(false);
230
+ try {
231
+ if (!status.trackResistanceSent) {
232
+ yield this.sendTrackResistance(0.0);
233
+ status.trackResistanceSent = true;
234
+ }
235
+ if (!status.userSent) {
236
+ yield this.sendUserConfiguration(args.userWeight || DEFAULT_USER_WEIGHT, args.bikeWeight || DEFAULT_BIKE_WEIGHT, args.wheelDiameter, args.gearRatio);
237
+ status.userSent = true;
238
+ }
239
+ this.started = true;
240
+ this.starting = false;
241
+ resolve(true);
242
+ }
243
+ catch (err) {
244
+ throw (new Error(`could not start device, reason:${err.message || err}`));
245
+ }
246
+ }), 5, 1500)
247
+ .catch(err => {
248
+ this.logger.logEvent({ message: 'start() error', error: err.message || err });
249
+ this.starting = false;
250
+ reject(err);
251
+ });
183
252
  }
184
253
  else if ((Date.now() - tsStart) > TIMEOUT_START) {
185
254
  clearInterval(iv);
186
- this.started = true;
187
255
  try {
188
256
  yield protocol.detachSensor(this);
189
257
  }
190
258
  catch (err) { }
259
+ this.started = false;
191
260
  this.starting = false;
192
- reject(new Error('timeout'));
261
+ reject(new Error('could not start device, reason:timeout'));
193
262
  }
194
263
  }), 50);
195
- }))
196
- .catch(err => {
264
+ }
265
+ catch (err) {
266
+ this.logger.logEvent({ message: 'start() error', error: err.message });
197
267
  this.starting = false;
198
- reject(err);
199
- });
268
+ reject(new Error(`could not start device, reason:${err.message}`));
269
+ }
200
270
  }));
201
271
  });
202
272
  }
203
273
  stop() {
204
- this.logger.logEvent({ message: 'stop()' });
205
- this.stopWorker();
206
- const Messages = this.getProtocol().getAnt().Messages;
207
- const stick = this.stick;
208
- const channel = this.channel;
209
- stick.write(Messages.openChannel(channel));
210
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
211
- if (!this.started && !this.connected)
212
- return resolve(false);
213
- try {
214
- const protocol = this.getProtocol();
215
- yield protocol.detachSensor(this);
216
- this.started = false;
217
- this.connected = false;
218
- resolve(true);
219
- }
220
- catch (err) {
221
- this.connected = false;
222
- reject(err);
223
- }
224
- }));
274
+ const _super = Object.create(null, {
275
+ stop: { get: () => super.stop }
276
+ });
277
+ return __awaiter(this, void 0, void 0, function* () {
278
+ yield _super.stop.call(this);
279
+ this.logger.logEvent({ message: 'stop()' });
280
+ this.stopWorker();
281
+ const Messages = this.getProtocol().getAnt().Messages;
282
+ const stick = this.stick;
283
+ const channel = this.channel;
284
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
285
+ this.starting = false;
286
+ return resolve(true);
287
+ if (!this.started && !this.connected)
288
+ return resolve(false);
289
+ try {
290
+ stick.write(Messages.openChannel(channel));
291
+ const protocol = this.getProtocol();
292
+ yield protocol.detachSensor(this);
293
+ this.started = false;
294
+ this.connected = false;
295
+ this.logger.logEvent({ message: 'stop() finished' });
296
+ resolve(true);
297
+ }
298
+ catch (err) {
299
+ this.connected = false;
300
+ this.logger.logEvent({ message: 'stop() error', error: err.message });
301
+ reject(err);
302
+ }
303
+ }));
304
+ });
225
305
  }
226
306
  sendUpdate(request) {
227
307
  return __awaiter(this, void 0, void 0, function* () {
228
308
  this.logger.logEvent({ message: "sendBikeUpdate():", request });
229
309
  try {
310
+ const isReset = (!request || request.reset || Object.keys(request).length === 0);
230
311
  if (request.slope !== undefined) {
231
- yield this.sendTrackResistance(request.slope);
312
+ yield (0, utils_2.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () { return yield this.sendTrackResistance(request.slope); }), 2, 100);
232
313
  }
233
314
  if (request.targetPower !== undefined) {
234
- yield this.sendTargetPower(request.targetPower);
315
+ yield (0, utils_2.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () { return yield this.sendTargetPower(request.targetPower); }), 2, 100);
235
316
  }
236
317
  else if (request.maxPower !== undefined) {
237
318
  if (this.data.power && this.data.power > request.maxPower)
238
- yield this.sendTargetPower(request.maxPower);
319
+ yield (0, utils_2.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () { return yield this.sendTargetPower(request.maxPower); }), 2, 100);
239
320
  }
240
321
  else if (request.minPower !== undefined) {
241
322
  if (this.data.power && this.data.power < request.minPower)
242
- yield this.sendTargetPower(request.minPower);
243
- }
244
- if (request.maxHrm !== undefined) {
245
- }
246
- if (request.minHrm !== undefined) {
323
+ yield (0, utils_2.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () { return yield this.sendTargetPower(request.minPower); }), 2, 100);
247
324
  }
248
325
  }
249
326
  catch (err) {
@@ -267,10 +344,20 @@ class AntFEAdapter extends AntAdapter_1.default {
267
344
  });
268
345
  }
269
346
  startWorker() {
347
+ this.logger.logEvent({ message: 'startWorker()' });
270
348
  if (this.queue === undefined) {
271
349
  this.queue = new utils_2.Queue();
272
350
  }
273
- this.workerId = setInterval(() => { this.sendFromQueue(); }, 10);
351
+ if (this.workerId)
352
+ return;
353
+ this.workerId = setInterval(() => {
354
+ try {
355
+ this.sendFromQueue();
356
+ }
357
+ catch (err) {
358
+ this.logger.logEvent({ message: 'sendFromQueue error', error: err.message });
359
+ }
360
+ }, 10);
274
361
  }
275
362
  stopWorker() {
276
363
  if (!this.workerId)
@@ -280,8 +367,9 @@ class AntFEAdapter extends AntAdapter_1.default {
280
367
  this.workerId = undefined;
281
368
  }
282
369
  sendFromQueue() {
283
- if (this.queue === undefined)
370
+ if (this.queue === undefined) {
284
371
  return;
372
+ }
285
373
  if (this.currentCmd !== undefined) {
286
374
  const cmdInfo = this.currentCmd;
287
375
  if (this.currentCmd.response === undefined) {
@@ -304,7 +392,7 @@ class AntFEAdapter extends AntAdapter_1.default {
304
392
  this.currentCmd = undefined;
305
393
  if (callback !== undefined) {
306
394
  if (response && response.success === false) {
307
- callback(undefined, new Error('error'));
395
+ callback(undefined, new Error(`ANT error ${response.code}`));
308
396
  return;
309
397
  }
310
398
  callback(response);
@@ -317,14 +405,17 @@ class AntFEAdapter extends AntAdapter_1.default {
317
405
  this.currentCmd = this.queue.dequeue();
318
406
  this.currentCmd.tsStart = Date.now();
319
407
  const { msg, logStr } = this.currentCmd;
320
- this.logger.logEvent({ message: "sending", cmd: logStr, msg: utils_2.hexstr(msg), queueSize: this.queue.size() });
321
- this.stick.write(msg);
408
+ this.logger.logEvent({ message: "sending", cmd: logStr, msg: (0, utils_2.hexstr)(msg), queueSize: this.queue.size() });
409
+ if (this.stick)
410
+ this.stick.write(msg);
322
411
  }
323
412
  }
324
413
  sendUserConfiguration(userWeight, bikeWeight, wheelDiameter, gearRatio) {
325
- if (!this.connected)
326
- return;
327
414
  return new Promise((resolve, reject) => {
415
+ if (!this.connected)
416
+ reject(new Error('not connected'));
417
+ if (!this.queue)
418
+ this.startWorker();
328
419
  var payload = [];
329
420
  payload.push(this.channel);
330
421
  const logStr = `sendUserConfiguration(${userWeight},${bikeWeight},${wheelDiameter},${gearRatio})`;
@@ -363,9 +454,11 @@ class AntFEAdapter extends AntAdapter_1.default {
363
454
  });
364
455
  }
365
456
  sendBasicResistance(resistance) {
366
- if (!this.connected)
367
- return;
368
457
  return new Promise((resolve, reject) => {
458
+ if (!this.connected)
459
+ reject(new Error('not connected'));
460
+ if (!this.queue)
461
+ this.startWorker();
369
462
  var payload = [];
370
463
  payload.push(this.channel);
371
464
  const logStr = `sendBasicResistance(${resistance})`;
@@ -389,9 +482,11 @@ class AntFEAdapter extends AntAdapter_1.default {
389
482
  });
390
483
  }
391
484
  sendTargetPower(power) {
392
- if (!this.connected)
393
- return;
394
485
  return new Promise((resolve, reject) => {
486
+ if (!this.connected)
487
+ reject(new Error('not connected'));
488
+ if (!this.queue)
489
+ this.startWorker();
395
490
  var payload = [];
396
491
  payload.push(this.channel);
397
492
  const logStr = `sendTargetPower(${power})`;
@@ -415,9 +510,11 @@ class AntFEAdapter extends AntAdapter_1.default {
415
510
  });
416
511
  }
417
512
  sendWindResistance(windCoeff, windSpeed, draftFactor) {
418
- if (!this.connected)
419
- return;
420
513
  return new Promise((resolve, reject) => {
514
+ if (!this.connected)
515
+ reject(new Error('not connected'));
516
+ if (!this.queue)
517
+ this.startWorker();
421
518
  var payload = [];
422
519
  payload.push(this.channel);
423
520
  const logStr = `sendWindResistance(${windCoeff},${windSpeed},${draftFactor})`;
@@ -451,9 +548,11 @@ class AntFEAdapter extends AntAdapter_1.default {
451
548
  });
452
549
  }
453
550
  sendTrackResistance(slope, rrCoeff) {
454
- if (!this.connected)
455
- return;
456
551
  return new Promise((resolve, reject) => {
552
+ if (!this.connected)
553
+ reject(new Error('not connected'));
554
+ if (!this.queue)
555
+ this.startWorker();
457
556
  var payload = [];
458
557
  payload.push(this.channel);
459
558
  const logStr = `sendTrackResistance(${slope},${rrCoeff})`;
@@ -1,5 +1,7 @@
1
1
  import AntAdapter from '../AntAdapter';
2
2
  export default class AntHrmAdapter extends AntAdapter {
3
+ started: boolean;
4
+ starting: boolean;
3
5
  constructor(DeviceID: any, port: any, stick: any, protocol: any);
4
6
  isBike(): boolean;
5
7
  isHrm(): boolean;
@@ -9,6 +11,6 @@ export default class AntHrmAdapter extends AntAdapter {
9
11
  getDisplayName(): string;
10
12
  onDeviceData(deviceData: any): void;
11
13
  updateData(data: any, deviceData: any): any;
12
- start(): Promise<unknown>;
14
+ start(props?: any): Promise<any>;
13
15
  stop(): Promise<boolean>;
14
16
  }
@@ -8,10 +8,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
15
  const gd_eventlog_1 = require("gd-eventlog");
13
- const AntAdapter_1 = require("../AntAdapter");
16
+ const AntAdapter_1 = __importDefault(require("../AntAdapter"));
14
17
  const utils_1 = require("../utils");
18
+ const DEFAULT_START_TIMEOUT = 5000;
15
19
  class AntHrmAdapter extends AntAdapter_1.default {
16
20
  constructor(DeviceID, port, stick, protocol) {
17
21
  super(protocol);
@@ -19,10 +23,13 @@ class AntHrmAdapter extends AntAdapter_1.default {
19
23
  this.deviceID = DeviceID;
20
24
  this.port = port;
21
25
  this.stick = stick;
26
+ this.paused = false;
22
27
  this.deviceData = {
23
28
  DeviceID
24
29
  };
25
30
  this.data = {};
31
+ this.started = false;
32
+ this.starting = false;
26
33
  }
27
34
  isBike() { return false; }
28
35
  isHrm() { return true; }
@@ -36,14 +43,16 @@ class AntHrmAdapter extends AntAdapter_1.default {
36
43
  getDisplayName() {
37
44
  const { DeviceID, manID, ComputedHeartRate } = this.deviceData;
38
45
  const hrmStr = ComputedHeartRate ? ` (${ComputedHeartRate})` : '';
39
- return `${utils_1.getBrand(manID)} Hrm ${DeviceID}${hrmStr}`;
46
+ return `${(0, utils_1.getBrand)(manID)} Hrm ${DeviceID}${hrmStr}`;
40
47
  }
41
48
  onDeviceData(deviceData) {
49
+ if (!this.started)
50
+ return;
42
51
  this.deviceData = deviceData;
43
52
  try {
44
53
  if (this.onDataFn && !this.ignoreHrm && !this.paused) {
45
- if (!this.lastUpdate || (Date.now() - this.lastUpdate) > this.updateFrequency) {
46
- console.log('~~deviceData', deviceData);
54
+ if (this.lastUpdate === undefined || (Date.now() - this.lastUpdate) > this.updateFrequency) {
55
+ this.logger.logEvent({ message: 'onDeviceData', data: deviceData });
47
56
  const data = this.updateData(this.data, deviceData);
48
57
  this.onDataFn(data);
49
58
  this.lastUpdate = Date.now();
@@ -57,34 +66,76 @@ class AntHrmAdapter extends AntAdapter_1.default {
57
66
  data.heartrate = deviceData.ComputedHeartRate;
58
67
  return data;
59
68
  }
60
- start() {
69
+ start(props) {
70
+ const _super = Object.create(null, {
71
+ start: { get: () => super.start }
72
+ });
61
73
  return __awaiter(this, void 0, void 0, function* () {
74
+ yield _super.start.call(this, props);
62
75
  this.logger.logEvent({ message: 'start()' });
76
+ const args = props || {};
63
77
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
64
78
  if (this.ignoreHrm)
65
79
  resolve(false);
80
+ if (this.starting) {
81
+ this.logger.logEvent({ message: 'start() not done: bike starting' });
82
+ return resolve(false);
83
+ }
84
+ if (this.started) {
85
+ this.logger.logEvent({ message: 'start() done: bike was already started' });
86
+ return resolve(true);
87
+ }
88
+ this.starting = true;
66
89
  const Ant = this.getProtocol().getAnt();
67
90
  const protocol = this.getProtocol();
91
+ let start = Date.now();
92
+ let timeout = start + (args.timeout || DEFAULT_START_TIMEOUT);
93
+ const iv = setInterval(() => {
94
+ if (Date.now() > timeout) {
95
+ clearInterval(iv);
96
+ this.starting = false;
97
+ reject(new Error('timeout'));
98
+ }
99
+ if (this.isStopped()) {
100
+ clearInterval(iv);
101
+ this.starting = false;
102
+ reject(new Error('stopped'));
103
+ }
104
+ }, 100);
68
105
  protocol.attachSensors(this, Ant.HeartRateSensor, 'hbData')
69
- .then(() => resolve(true))
106
+ .then(() => {
107
+ this.starting = false;
108
+ this.started = true;
109
+ clearInterval(iv);
110
+ resolve(true);
111
+ })
70
112
  .catch(err => reject(err));
71
113
  }));
72
114
  });
73
115
  }
74
116
  stop() {
75
- this.logger.logEvent({ message: 'stop()' });
76
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
77
- if (this.ignoreHrm)
78
- return resolve(false);
79
- try {
80
- const protocol = this.getProtocol();
81
- yield protocol.detachSensor(this);
82
- resolve(true);
83
- }
84
- catch (err) {
85
- reject(err);
86
- }
87
- }));
117
+ const _super = Object.create(null, {
118
+ stop: { get: () => super.stop }
119
+ });
120
+ return __awaiter(this, void 0, void 0, function* () {
121
+ yield _super.stop.call(this);
122
+ this.logger.logEvent({ message: 'stop()' });
123
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
124
+ this.starting = false;
125
+ return resolve(true);
126
+ this.started = false;
127
+ if (this.ignoreHrm)
128
+ return resolve(false);
129
+ try {
130
+ const protocol = this.getProtocol();
131
+ yield protocol.detachSensor(this);
132
+ resolve(true);
133
+ }
134
+ catch (err) {
135
+ reject(err);
136
+ }
137
+ }));
138
+ });
88
139
  }
89
140
  }
90
141
  exports.default = AntHrmAdapter;
package/lib/ant/utils.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getBrand = void 0;
4
- exports.getBrand = (manId) => {
4
+ const getBrand = (manId) => {
5
5
  if (manId === undefined)
6
6
  return "ANT+";
7
7
  switch (manId) {
@@ -20,3 +20,4 @@ exports.getBrand = (manId) => {
20
20
  return "ANT+";
21
21
  }
22
22
  };
23
+ exports.getBrand = getBrand;