incyclist-devices 1.2.0 → 1.4.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 (70) hide show
  1. package/LICENSE +21 -0
  2. package/lib/CyclingMode.d.ts +72 -0
  3. package/lib/CyclingMode.js +66 -0
  4. package/lib/Device.d.ts +48 -10
  5. package/lib/Device.js +9 -8
  6. package/lib/DeviceProtocol.d.ts +40 -12
  7. package/lib/DeviceProtocol.js +16 -16
  8. package/lib/DeviceRegistry.d.ts +4 -4
  9. package/lib/DeviceRegistry.js +10 -10
  10. package/lib/DeviceSupport.d.ts +4 -3
  11. package/lib/DeviceSupport.js +32 -8
  12. package/lib/ant/AntAdapter.d.ts +9 -2
  13. package/lib/ant/AntAdapter.js +26 -2
  14. package/lib/ant/AntScanner.d.ts +16 -6
  15. package/lib/ant/AntScanner.js +379 -138
  16. package/lib/ant/antfe/AntFEAdapter.d.ts +4 -2
  17. package/lib/ant/antfe/AntFEAdapter.js +209 -72
  18. package/lib/ant/anthrm/AntHrmAdapter.d.ts +4 -1
  19. package/lib/ant/anthrm/AntHrmAdapter.js +73 -19
  20. package/lib/ant/utils.js +2 -1
  21. package/lib/calculations.d.ts +12 -13
  22. package/lib/calculations.js +88 -125
  23. package/lib/daum/DaumAdapter.d.ts +29 -6
  24. package/lib/daum/DaumAdapter.js +219 -96
  25. package/lib/daum/ERGCyclingMode.d.ts +28 -0
  26. package/lib/daum/ERGCyclingMode.js +207 -0
  27. package/lib/daum/PowerMeterCyclingMode.d.ts +18 -0
  28. package/lib/daum/PowerMeterCyclingMode.js +79 -0
  29. package/lib/daum/SmartTrainerCyclingMode.d.ts +41 -0
  30. package/lib/daum/SmartTrainerCyclingMode.js +344 -0
  31. package/lib/daum/classic/DaumClassicAdapter.d.ts +3 -1
  32. package/lib/daum/classic/DaumClassicAdapter.js +46 -32
  33. package/lib/daum/classic/DaumClassicCyclingMode.d.ts +13 -0
  34. package/lib/daum/classic/DaumClassicCyclingMode.js +98 -0
  35. package/lib/daum/classic/DaumClassicProtocol.d.ts +5 -3
  36. package/lib/daum/classic/DaumClassicProtocol.js +39 -6
  37. package/lib/daum/classic/ERGCyclingMode.d.ts +23 -0
  38. package/lib/daum/classic/ERGCyclingMode.js +171 -0
  39. package/lib/daum/classic/bike.d.ts +41 -37
  40. package/lib/daum/classic/bike.js +86 -53
  41. package/lib/daum/classic/utils.d.ts +3 -3
  42. package/lib/daum/classic/utils.js +16 -10
  43. package/lib/daum/indoorbike.d.ts +2 -1
  44. package/lib/daum/indoorbike.js +23 -21
  45. package/lib/daum/premium/DaumPremiumAdapter.d.ts +2 -2
  46. package/lib/daum/premium/DaumPremiumAdapter.js +30 -20
  47. package/lib/daum/premium/DaumPremiumProtocol.d.ts +11 -2
  48. package/lib/daum/premium/DaumPremiumProtocol.js +49 -8
  49. package/lib/daum/premium/bike.d.ts +63 -52
  50. package/lib/daum/premium/bike.js +258 -207
  51. package/lib/daum/premium/tcpserial.d.ts +18 -14
  52. package/lib/daum/premium/tcpserial.js +50 -20
  53. package/lib/daum/premium/utils.d.ts +2 -2
  54. package/lib/simulator/Simulator.d.ts +13 -7
  55. package/lib/simulator/Simulator.js +62 -21
  56. package/lib/utils.d.ts +3 -1
  57. package/lib/utils.js +39 -18
  58. package/package.json +12 -11
  59. package/lib/ant/AntScanner.unit.tests.d.ts +0 -1
  60. package/lib/ant/AntScanner.unit.tests.js +0 -25
  61. package/lib/ant/antfe/AntFEProcessor.d.ts +0 -40
  62. package/lib/ant/antfe/AntFEProcessor.js +0 -238
  63. package/lib/ant/antfe/AntHrmProtocol.d.ts +0 -9
  64. package/lib/ant/antfe/AntHrmProtocol.js +0 -30
  65. package/lib/ant/antfe/bike.d.ts +0 -47
  66. package/lib/ant/antfe/bike.js +0 -602
  67. package/lib/ant/anthrm/anthrm.d.ts +0 -33
  68. package/lib/ant/anthrm/anthrm.js +0 -523
  69. package/lib/simulator/Simulator.unit.tests.d.ts +0 -1
  70. package/lib/simulator/Simulator.unit.tests.js +0 -79
@@ -12,6 +12,7 @@ export default class AntFEAdapter extends AntAdapter {
12
12
  isBike(): boolean;
13
13
  isHrm(): boolean;
14
14
  isPower(): boolean;
15
+ getProfile(): string;
15
16
  getName(): string;
16
17
  getDisplayName(): string;
17
18
  onAttached(): void;
@@ -19,10 +20,11 @@ export default class AntFEAdapter extends AntAdapter {
19
20
  onDeviceEvent(data: any): void;
20
21
  updateData(data: any, deviceData: any): any;
21
22
  transformData(bikeData: any): any;
22
- start(props?: any): Promise<unknown>;
23
+ start(props?: any): Promise<any>;
23
24
  stop(): Promise<boolean>;
24
25
  sendUpdate(request: any): Promise<void>;
25
- send(msg: any, logStr: any, callback?: any): void;
26
+ send(msg: any, logStr: any, callback?: any, expectedResponse?: any): void;
27
+ sendAsync(msg: any, logStr: any, expectedResponse: any): Promise<unknown>;
26
28
  startWorker(): void;
27
29
  stopWorker(): void;
28
30
  sendFromQueue(): 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;
18
- const TIMEOUT_ACK = 500;
19
- const TIMEOUT_START = 5000;
21
+ const hex = (v) => Math.abs(v).toString(16).toUpperCase();
22
+ const TIMEOUT_ACK = 5000;
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;
@@ -35,35 +43,29 @@ class AntFEAdapter extends AntAdapter_1.default {
35
43
  isBike() { return true; }
36
44
  isHrm() { return this.deviceData.HeartRate !== undefined; }
37
45
  isPower() { return true; }
46
+ getProfile() {
47
+ return 'Smart Trainer';
48
+ }
38
49
  getName() {
39
50
  return `Ant+FE ${this.deviceID}`;
40
51
  }
41
52
  getDisplayName() {
42
53
  const { DeviceID, ManId, ComputedHeartRate } = this.deviceData;
43
54
  const hrmStr = ComputedHeartRate ? ` (${ComputedHeartRate})` : '';
44
- return `${utils_1.getBrand(ManId)} FE ${DeviceID}${hrmStr}`;
55
+ return `${(0, utils_1.getBrand)(ManId)} FE ${DeviceID}${hrmStr}`;
45
56
  }
46
57
  onAttached() {
47
- console.log('~~attched', this.getName(), this.channel);
48
- const Messages = this.getProtocol().getAnt().Messages;
49
- const stick = this.stick;
50
- const channel = this.channel;
51
- const { DeviceID } = this.deviceData;
52
- stick.write(Messages.assignChannel(channel, "transmit"));
53
- stick.write(Messages.setFrequency(channel, 57));
54
- stick.write(Messages.setPeriod(channel, 8192));
55
- stick.write(Messages.setDevice(channel, DeviceID, 0x11, 0x0));
56
- stick.write(Messages.openChannel(channel));
58
+ this.logger.logEvent({ message: 'Device connected' });
57
59
  this.connected = true;
58
60
  }
59
61
  onDeviceData(deviceData) {
60
- if (!this.started)
62
+ if (!this.started || this.isStopped())
61
63
  return;
62
64
  this.deviceData = deviceData;
63
65
  try {
64
66
  if (this.onDataFn && !(this.ignoreHrm && this.ignoreBike && this.ignorePower) && !this.paused) {
65
67
  if (!this.lastUpdate || (Date.now() - this.lastUpdate) > this.updateFrequency) {
66
- console.log('~~deviceData', deviceData);
68
+ this.logger.logEvent({ message: 'onDeviceData', data: deviceData });
67
69
  this.data = this.updateData(this.data, deviceData);
68
70
  const data = this.transformData(this.data);
69
71
  this.onDataFn(data);
@@ -76,24 +78,45 @@ class AntFEAdapter extends AntAdapter_1.default {
76
78
  }
77
79
  onDeviceEvent(data) {
78
80
  try {
79
- const Constants = this.getProtocol().getAnt().Constants;
80
- let stick = this.stick;
81
- if (stick.currentCmd !== undefined && data.message === 1 && data.code === Constants.EVENT_TRANSFER_TX_COMPLETED) {
82
- stick.currentCmd.response = { success: true };
81
+ const cmdInfo = this.currentCmd;
82
+ if (!cmdInfo)
83
83
  return;
84
+ const msg = cmdInfo.msg.readUInt8(2);
85
+ const Constants = this.getProtocol().getAnt().Constants;
86
+ const { expectedResponse } = cmdInfo;
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
+ }
84
96
  }
85
- if (stick.currentCmd !== undefined && data.message === 1 && data.code === Constants.EVENT_TRANSFER_TX_FAILED) {
86
- stick.currentCmd.response = { success: false };
87
- 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
+ }
88
110
  }
89
- if (stick.currentCmd !== undefined && data.message === Constants.MESSAGE_CHANNEL_ACKNOWLEDGED_DATA && data.code === 31) {
111
+ if (this.currentCmd !== undefined && data.message === Constants.MESSAGE_CHANNEL_ACKNOWLEDGED_DATA && data.code === 31) {
90
112
  this.logger.log("could not send (TRANSFER_IN_PROGRESS)");
113
+ this.currentCmd.response = { success: false, message: hex(data.message), code: hex(data.code) };
91
114
  return;
92
115
  }
93
- this.logger.logEvent({ message: "Incoming Event ", event: data });
116
+ this.logger.logEvent({ message: "Incoming Event ", event: { message: hex(data.message), code: hex(data.code) } });
94
117
  }
95
118
  catch (err) {
96
- 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 });
97
120
  }
98
121
  }
99
122
  updateData(data, deviceData) {
@@ -104,10 +127,18 @@ class AntFEAdapter extends AntAdapter_1.default {
104
127
  data.power = (deviceData.InstantaneousPower !== undefined ? deviceData.InstantaneousPower : data.power);
105
128
  data.pedalRpm = (deviceData.Cadence !== undefined ? deviceData.Cadence : data.pedalRpm);
106
129
  data.heartrate = (deviceData.HeartRate !== undefined ? deviceData.HeartRate : data.heartrate);
107
- if (deviceData.Distance !== undefined) {
130
+ if (deviceData.Distance !== undefined && deviceData.Distance !== 0) {
108
131
  data.distanceInternal = deviceData.Distance - data.distanceOffs;
109
132
  data.distance = data.distanceInternal / 1000;
110
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
+ }
111
142
  return data;
112
143
  }
113
144
  transformData(bikeData) {
@@ -140,89 +171,156 @@ class AntFEAdapter extends AntAdapter_1.default {
140
171
  return data;
141
172
  }
142
173
  start(props) {
174
+ const _super = Object.create(null, {
175
+ start: { get: () => super.start }
176
+ });
143
177
  return __awaiter(this, void 0, void 0, function* () {
178
+ yield _super.start.call(this, props);
144
179
  this.logger.logEvent({ message: 'start()' });
145
- console.log('~~start', this.started, this.connected, this.starting);
146
- const opts = props || {};
180
+ const args = props || {};
147
181
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
148
- 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' });
149
184
  return resolve(false);
185
+ }
150
186
  if (this.starting) {
187
+ this.logger.logEvent({ message: 'start() not done: bike starting' });
151
188
  return resolve(false);
152
189
  }
153
190
  if (this.started) {
191
+ this.logger.logEvent({ message: 'start() done: bike was already started' });
192
+ this.startWorker();
154
193
  return resolve(true);
155
194
  }
156
195
  this.starting = true;
157
196
  const Ant = this.getProtocol().getAnt();
158
197
  const protocol = this.getProtocol();
159
- protocol.attachSensors(this, Ant.FitnessEquipmentSensor, 'fitnessData')
160
- .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);
161
218
  this.startWorker();
162
219
  const tsStart = Date.now();
163
220
  const iv = setInterval(() => __awaiter(this, void 0, void 0, function* () {
164
221
  if (this.connected) {
165
222
  clearInterval(iv);
166
- try {
167
- yield this.sendTrackResistance(0.0);
168
- yield this.sendUserConfiguration(opts.userWeight || 72, opts.bikeWeight || 12.75, opts.wheelDiameter, opts.gearRatio);
169
- }
170
- catch (err) {
171
- console.log('~~~err:', err);
172
- }
173
- this.started = true;
174
- this.starting = false;
175
- 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
+ });
176
252
  }
177
253
  else if ((Date.now() - tsStart) > TIMEOUT_START) {
178
254
  clearInterval(iv);
179
- this.started = true;
180
255
  try {
181
256
  yield protocol.detachSensor(this);
182
257
  }
183
258
  catch (err) { }
259
+ this.started = false;
184
260
  this.starting = false;
185
- reject(new Error('timeout'));
261
+ reject(new Error('could not start device, reason:timeout'));
186
262
  }
187
263
  }), 50);
188
- }))
189
- .catch(err => {
264
+ }
265
+ catch (err) {
266
+ this.logger.logEvent({ message: 'start() error', error: err.message });
190
267
  this.starting = false;
191
- reject(err);
192
- });
268
+ reject(new Error(`could not start device, reason:${err.message}`));
269
+ }
193
270
  }));
194
271
  });
195
272
  }
196
273
  stop() {
197
- this.logger.logEvent({ message: 'stop()' });
198
- console.log('~~~stop', this.started, this.connected);
199
- this.stopWorker();
200
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
201
- return resolve(true);
202
- }));
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
+ });
203
305
  }
204
306
  sendUpdate(request) {
205
307
  return __awaiter(this, void 0, void 0, function* () {
206
308
  this.logger.logEvent({ message: "sendBikeUpdate():", request });
207
- console.log('~~sendUpdate', request);
208
309
  try {
310
+ const isReset = (!request || request.reset || Object.keys(request).length === 0);
209
311
  if (request.slope !== undefined) {
210
- 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);
211
313
  }
212
314
  if (request.targetPower !== undefined) {
213
- 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);
214
316
  }
215
317
  else if (request.maxPower !== undefined) {
216
318
  if (this.data.power && this.data.power > request.maxPower)
217
- 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);
218
320
  }
219
321
  else if (request.minPower !== undefined) {
220
322
  if (this.data.power && this.data.power < request.minPower)
221
- yield this.sendTargetPower(request.minPower);
222
- }
223
- if (request.maxHrm !== undefined) {
224
- }
225
- 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);
226
324
  }
227
325
  }
228
326
  catch (err) {
@@ -230,17 +328,36 @@ class AntFEAdapter extends AntAdapter_1.default {
230
328
  }
231
329
  });
232
330
  }
233
- send(msg, logStr, callback) {
331
+ send(msg, logStr, callback, expectedResponse) {
234
332
  if (this.workerId === undefined) {
235
333
  return;
236
334
  }
237
- this.queue.enqueue({ msg, logStr, callback });
335
+ this.queue.enqueue({ msg, logStr, callback, expectedResponse });
336
+ }
337
+ sendAsync(msg, logStr, expectedResponse) {
338
+ return new Promise((resolve, reject) => {
339
+ this.send(msg, logStr, (res, err) => {
340
+ if (err)
341
+ return reject(err);
342
+ resolve(res);
343
+ }, expectedResponse);
344
+ });
238
345
  }
239
346
  startWorker() {
347
+ this.logger.logEvent({ message: 'startWorker()' });
240
348
  if (this.queue === undefined) {
241
349
  this.queue = new utils_2.Queue();
242
350
  }
243
- this.workerId = setInterval(() => { this.sendFromQueue(); }, 100);
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);
244
361
  }
245
362
  stopWorker() {
246
363
  if (!this.workerId)
@@ -250,8 +367,9 @@ class AntFEAdapter extends AntAdapter_1.default {
250
367
  this.workerId = undefined;
251
368
  }
252
369
  sendFromQueue() {
253
- if (this.queue === undefined || !this.connected)
370
+ if (this.queue === undefined) {
254
371
  return;
372
+ }
255
373
  if (this.currentCmd !== undefined) {
256
374
  const cmdInfo = this.currentCmd;
257
375
  if (this.currentCmd.response === undefined) {
@@ -261,7 +379,6 @@ class AntFEAdapter extends AntAdapter_1.default {
261
379
  timeout = TIMEOUT_ACK;
262
380
  let duration = Date.now() - tsStart;
263
381
  if (duration > timeout) {
264
- console.log('~~~timeout');
265
382
  this.logger.logEvent({ message: 'timeout', cmd: logStr, timeout: `${timeout}ms` });
266
383
  this.currentCmd = undefined;
267
384
  if (callback !== undefined) {
@@ -275,7 +392,7 @@ class AntFEAdapter extends AntAdapter_1.default {
275
392
  this.currentCmd = undefined;
276
393
  if (callback !== undefined) {
277
394
  if (response && response.success === false) {
278
- callback(undefined, new Error('error'));
395
+ callback(undefined, new Error(`ANT error ${response.code}`));
279
396
  return;
280
397
  }
281
398
  callback(response);
@@ -288,13 +405,17 @@ class AntFEAdapter extends AntAdapter_1.default {
288
405
  this.currentCmd = this.queue.dequeue();
289
406
  this.currentCmd.tsStart = Date.now();
290
407
  const { msg, logStr } = this.currentCmd;
291
- this.logger.logEvent({ message: "sending", cmd: logStr, msg: utils_2.hexstr(msg), queueSize: this.queue.size() });
292
- console.log('~~sending', logStr, utils_2.hexstr(msg));
293
- 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);
294
411
  }
295
412
  }
296
413
  sendUserConfiguration(userWeight, bikeWeight, wheelDiameter, gearRatio) {
297
414
  return new Promise((resolve, reject) => {
415
+ if (!this.connected)
416
+ reject(new Error('not connected'));
417
+ if (!this.queue)
418
+ this.startWorker();
298
419
  var payload = [];
299
420
  payload.push(this.channel);
300
421
  const logStr = `sendUserConfiguration(${userWeight},${bikeWeight},${wheelDiameter},${gearRatio})`;
@@ -334,6 +455,10 @@ class AntFEAdapter extends AntAdapter_1.default {
334
455
  }
335
456
  sendBasicResistance(resistance) {
336
457
  return new Promise((resolve, reject) => {
458
+ if (!this.connected)
459
+ reject(new Error('not connected'));
460
+ if (!this.queue)
461
+ this.startWorker();
337
462
  var payload = [];
338
463
  payload.push(this.channel);
339
464
  const logStr = `sendBasicResistance(${resistance})`;
@@ -358,6 +483,10 @@ class AntFEAdapter extends AntAdapter_1.default {
358
483
  }
359
484
  sendTargetPower(power) {
360
485
  return new Promise((resolve, reject) => {
486
+ if (!this.connected)
487
+ reject(new Error('not connected'));
488
+ if (!this.queue)
489
+ this.startWorker();
361
490
  var payload = [];
362
491
  payload.push(this.channel);
363
492
  const logStr = `sendTargetPower(${power})`;
@@ -382,6 +511,10 @@ class AntFEAdapter extends AntAdapter_1.default {
382
511
  }
383
512
  sendWindResistance(windCoeff, windSpeed, draftFactor) {
384
513
  return new Promise((resolve, reject) => {
514
+ if (!this.connected)
515
+ reject(new Error('not connected'));
516
+ if (!this.queue)
517
+ this.startWorker();
385
518
  var payload = [];
386
519
  payload.push(this.channel);
387
520
  const logStr = `sendWindResistance(${windCoeff},${windSpeed},${draftFactor})`;
@@ -416,6 +549,10 @@ class AntFEAdapter extends AntAdapter_1.default {
416
549
  }
417
550
  sendTrackResistance(slope, rrCoeff) {
418
551
  return new Promise((resolve, reject) => {
552
+ if (!this.connected)
553
+ reject(new Error('not connected'));
554
+ if (!this.queue)
555
+ this.startWorker();
419
556
  var payload = [];
420
557
  payload.push(this.channel);
421
558
  const logStr = `sendTrackResistance(${slope},${rrCoeff})`;
@@ -1,13 +1,16 @@
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;
6
8
  isPower(): boolean;
9
+ getProfile(): string;
7
10
  getName(): string;
8
11
  getDisplayName(): string;
9
12
  onDeviceData(deviceData: any): void;
10
13
  updateData(data: any, deviceData: any): any;
11
- start(): Promise<unknown>;
14
+ start(props?: any): Promise<any>;
12
15
  stop(): Promise<boolean>;
13
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,28 +23,36 @@ 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; }
29
36
  isPower() { return false; }
37
+ getProfile() {
38
+ return 'Heartrate Monitor';
39
+ }
30
40
  getName() {
31
41
  return `Ant+Hrm ${this.deviceID}`;
32
42
  }
33
43
  getDisplayName() {
34
44
  const { DeviceID, manID, ComputedHeartRate } = this.deviceData;
35
45
  const hrmStr = ComputedHeartRate ? ` (${ComputedHeartRate})` : '';
36
- return `${utils_1.getBrand(manID)} Hrm ${DeviceID}${hrmStr}`;
46
+ return `${(0, utils_1.getBrand)(manID)} Hrm ${DeviceID}${hrmStr}`;
37
47
  }
38
48
  onDeviceData(deviceData) {
49
+ if (!this.started)
50
+ return;
39
51
  this.deviceData = deviceData;
40
52
  try {
41
53
  if (this.onDataFn && !this.ignoreHrm && !this.paused) {
42
- if (!this.lastUpdate || (Date.now() - this.lastUpdate) > this.updateFrequency) {
43
- console.log('~~deviceData', deviceData);
54
+ if (this.lastUpdate === undefined || (Date.now() - this.lastUpdate) > this.updateFrequency) {
55
+ this.logger.logEvent({ message: 'onDeviceData', data: deviceData });
44
56
  const data = this.updateData(this.data, deviceData);
45
57
  this.onDataFn(data);
46
58
  this.lastUpdate = Date.now();
@@ -54,34 +66,76 @@ class AntHrmAdapter extends AntAdapter_1.default {
54
66
  data.heartrate = deviceData.ComputedHeartRate;
55
67
  return data;
56
68
  }
57
- start() {
69
+ start(props) {
70
+ const _super = Object.create(null, {
71
+ start: { get: () => super.start }
72
+ });
58
73
  return __awaiter(this, void 0, void 0, function* () {
74
+ yield _super.start.call(this, props);
59
75
  this.logger.logEvent({ message: 'start()' });
76
+ const args = props || {};
60
77
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
61
78
  if (this.ignoreHrm)
62
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;
63
89
  const Ant = this.getProtocol().getAnt();
64
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);
65
105
  protocol.attachSensors(this, Ant.HeartRateSensor, 'hbData')
66
- .then(() => resolve(true))
106
+ .then(() => {
107
+ this.starting = false;
108
+ this.started = true;
109
+ clearInterval(iv);
110
+ resolve(true);
111
+ })
67
112
  .catch(err => reject(err));
68
113
  }));
69
114
  });
70
115
  }
71
116
  stop() {
72
- this.logger.logEvent({ message: 'stop()' });
73
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
74
- if (this.ignoreHrm)
75
- return resolve(false);
76
- try {
77
- const protocol = this.getProtocol();
78
- yield protocol.detachSensor(this);
79
- resolve(true);
80
- }
81
- catch (err) {
82
- reject(err);
83
- }
84
- }));
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
+ });
85
139
  }
86
140
  }
87
141
  exports.default = AntHrmAdapter;