incyclist-devices 1.5.10 → 1.5.12

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 (136) hide show
  1. package/LICENSE +0 -0
  2. package/lib/DeviceSupport.d.ts +36 -36
  3. package/lib/DeviceSupport.js +82 -82
  4. package/lib/ant/AntAdapter.d.ts +50 -50
  5. package/lib/ant/AntAdapter.js +109 -109
  6. package/lib/ant/AntScanner.d.ts +60 -60
  7. package/lib/ant/AntScanner.js +651 -651
  8. package/lib/ant/antfe/AntFEAdapter.d.ts +83 -83
  9. package/lib/ant/antfe/AntFEAdapter.js +652 -652
  10. package/lib/ant/antfe/ant-fe-adv-st-mode.d.ts +9 -9
  11. package/lib/ant/antfe/ant-fe-adv-st-mode.js +51 -51
  12. package/lib/ant/antfe/ant-fe-erg-mode.d.ts +6 -6
  13. package/lib/ant/antfe/ant-fe-erg-mode.js +14 -14
  14. package/lib/ant/antfe/ant-fe-st-mode.d.ts +5 -5
  15. package/lib/ant/antfe/ant-fe-st-mode.js +13 -13
  16. package/lib/ant/anthrm/AntHrmAdapter.d.ts +16 -16
  17. package/lib/ant/anthrm/AntHrmAdapter.js +130 -130
  18. package/lib/ant/antpwr/pwr-adapter.d.ts +49 -49
  19. package/lib/ant/antpwr/pwr-adapter.js +251 -251
  20. package/lib/ant/utils.d.ts +1 -1
  21. package/lib/ant/utils.js +23 -23
  22. package/lib/antv2/AntAdapter.d.ts +48 -0
  23. package/lib/antv2/AntAdapter.js +104 -0
  24. package/lib/antv2/adapter-factory.d.ts +11 -11
  25. package/lib/antv2/adapter-factory.js +40 -40
  26. package/lib/antv2/ant-binding.d.ts +13 -13
  27. package/lib/antv2/ant-binding.js +27 -27
  28. package/lib/antv2/ant-device.d.ts +51 -51
  29. package/lib/antv2/ant-device.js +115 -115
  30. package/lib/antv2/ant-interface.d.ts +37 -37
  31. package/lib/antv2/ant-interface.js +255 -255
  32. package/lib/antv2/fe.d.ts +29 -29
  33. package/lib/antv2/fe.js +262 -262
  34. package/lib/antv2/hr.d.ts +18 -18
  35. package/lib/antv2/hr.js +93 -93
  36. package/lib/antv2/incyclist-protocol.d.ts +37 -37
  37. package/lib/antv2/incyclist-protocol.js +126 -126
  38. package/lib/antv2/pwr.d.ts +28 -28
  39. package/lib/antv2/pwr.js +163 -163
  40. package/lib/antv2/sensor-factory.d.ts +5 -5
  41. package/lib/antv2/sensor-factory.js +20 -20
  42. package/lib/ble/ble-device.d.ts +63 -63
  43. package/lib/ble/ble-device.js +444 -444
  44. package/lib/ble/ble-erg-mode.d.ts +18 -18
  45. package/lib/ble/ble-erg-mode.js +132 -132
  46. package/lib/ble/ble-interface.d.ts +100 -100
  47. package/lib/ble/ble-interface.js +721 -721
  48. package/lib/ble/ble-peripheral.d.ts +36 -36
  49. package/lib/ble/ble-peripheral.js +200 -200
  50. package/lib/ble/ble-st-mode.d.ts +15 -15
  51. package/lib/ble/ble-st-mode.js +95 -95
  52. package/lib/ble/ble.d.ts +129 -129
  53. package/lib/ble/ble.js +86 -86
  54. package/lib/ble/consts.d.ts +14 -14
  55. package/lib/ble/consts.js +17 -17
  56. package/lib/ble/elite.d.ts +90 -90
  57. package/lib/ble/elite.js +322 -322
  58. package/lib/ble/fm.d.ts +125 -125
  59. package/lib/ble/fm.js +745 -745
  60. package/lib/ble/hrm.d.ts +48 -48
  61. package/lib/ble/hrm.js +134 -134
  62. package/lib/ble/incyclist-protocol.d.ts +31 -31
  63. package/lib/ble/incyclist-protocol.js +153 -153
  64. package/lib/ble/pwr.d.ts +89 -89
  65. package/lib/ble/pwr.js +321 -321
  66. package/lib/ble/tacx.d.ts +92 -90
  67. package/lib/ble/tacx.js +763 -731
  68. package/lib/ble/wahoo-kickr.d.ts +98 -98
  69. package/lib/ble/wahoo-kickr.js +496 -496
  70. package/lib/calculations.d.ts +13 -13
  71. package/lib/calculations.js +150 -150
  72. package/lib/cycling-mode.d.ts +76 -76
  73. package/lib/cycling-mode.js +79 -79
  74. package/lib/daum/DaumAdapter.d.ts +66 -66
  75. package/lib/daum/DaumAdapter.js +396 -396
  76. package/lib/daum/DaumPowerMeterCyclingMode.d.ts +8 -8
  77. package/lib/daum/DaumPowerMeterCyclingMode.js +21 -21
  78. package/lib/daum/ERGCyclingMode.d.ts +26 -26
  79. package/lib/daum/ERGCyclingMode.js +201 -201
  80. package/lib/daum/SmartTrainerCyclingMode.d.ts +41 -41
  81. package/lib/daum/SmartTrainerCyclingMode.js +344 -344
  82. package/lib/daum/classic/DaumClassicAdapter.d.ts +22 -18
  83. package/lib/daum/classic/DaumClassicAdapter.js +183 -146
  84. package/lib/daum/classic/DaumClassicCyclingMode.d.ts +13 -13
  85. package/lib/daum/classic/DaumClassicCyclingMode.js +97 -97
  86. package/lib/daum/classic/DaumClassicProtocol.d.ts +27 -27
  87. package/lib/daum/classic/DaumClassicProtocol.js +185 -185
  88. package/lib/daum/classic/bike.d.ts +68 -64
  89. package/lib/daum/classic/bike.js +467 -456
  90. package/lib/daum/classic/utils.d.ts +13 -13
  91. package/lib/daum/classic/utils.js +143 -143
  92. package/lib/daum/constants.d.ts +19 -19
  93. package/lib/daum/constants.js +22 -22
  94. package/lib/daum/premium/DaumClassicCyclingMode.d.ts +14 -14
  95. package/lib/daum/premium/DaumClassicCyclingMode.js +86 -86
  96. package/lib/daum/premium/DaumPremiumAdapter.d.ts +16 -14
  97. package/lib/daum/premium/DaumPremiumAdapter.js +163 -139
  98. package/lib/daum/premium/DaumPremiumProtocol.d.ts +32 -32
  99. package/lib/daum/premium/DaumPremiumProtocol.js +207 -207
  100. package/lib/daum/premium/bike.d.ts +127 -123
  101. package/lib/daum/premium/bike.js +904 -894
  102. package/lib/daum/premium/tcpserial.d.ts +33 -33
  103. package/lib/daum/premium/tcpserial.js +123 -123
  104. package/lib/daum/premium/utils.d.ts +62 -62
  105. package/lib/daum/premium/utils.js +376 -376
  106. package/lib/device.d.ts +92 -92
  107. package/lib/device.js +71 -71
  108. package/lib/kettler/comms.d.ts +59 -59
  109. package/lib/kettler/comms.js +242 -242
  110. package/lib/kettler/ergo-racer/ERGCyclingMode.d.ts +25 -25
  111. package/lib/kettler/ergo-racer/ERGCyclingMode.js +144 -144
  112. package/lib/kettler/ergo-racer/adapter.d.ts +101 -101
  113. package/lib/kettler/ergo-racer/adapter.js +639 -639
  114. package/lib/kettler/ergo-racer/protocol.d.ts +41 -41
  115. package/lib/kettler/ergo-racer/protocol.js +203 -203
  116. package/lib/modes/power-base.d.ts +20 -20
  117. package/lib/modes/power-base.js +70 -70
  118. package/lib/modes/power-meter.d.ts +20 -20
  119. package/lib/modes/power-meter.js +78 -78
  120. package/lib/modes/simulator.d.ts +29 -29
  121. package/lib/modes/simulator.js +140 -140
  122. package/lib/protocol.d.ts +74 -74
  123. package/lib/protocol.js +41 -41
  124. package/lib/registry.d.ts +8 -8
  125. package/lib/registry.js +33 -33
  126. package/lib/simulator/Simulator.d.ts +69 -69
  127. package/lib/simulator/Simulator.js +288 -288
  128. package/lib/types/command.d.ts +8 -8
  129. package/lib/types/command.js +2 -2
  130. package/lib/types/route.d.ts +24 -24
  131. package/lib/types/route.js +9 -9
  132. package/lib/types/user.d.ts +11 -11
  133. package/lib/types/user.js +9 -9
  134. package/lib/utils.d.ts +14 -14
  135. package/lib/utils.js +114 -114
  136. package/package.json +47 -47
@@ -1,651 +1,651 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
- Object.defineProperty(o, "default", { enumerable: true, value: v });
11
- }) : function(o, v) {
12
- o["default"] = v;
13
- });
14
- var __importStar = (this && this.__importStar) || function (mod) {
15
- if (mod && mod.__esModule) return mod;
16
- var result = {};
17
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
- __setModuleDefault(result, mod);
19
- return result;
20
- };
21
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
22
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
23
- return new (P || (P = Promise))(function (resolve, reject) {
24
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
25
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
26
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
27
- step((generator = generator.apply(thisArg, _arguments || [])).next());
28
- });
29
- };
30
- var __importDefault = (this && this.__importDefault) || function (mod) {
31
- return (mod && mod.__esModule) ? mod : { "default": mod };
32
- };
33
- Object.defineProperty(exports, "__esModule", { value: true });
34
- exports.AntScanner = exports.AntProtocol = void 0;
35
- const gd_eventlog_1 = require("gd-eventlog");
36
- const protocol_1 = __importStar(require("../protocol"));
37
- const AntHrmAdapter_1 = __importDefault(require("./anthrm/AntHrmAdapter"));
38
- const pwr_adapter_1 = __importDefault(require("./antpwr/pwr-adapter"));
39
- const AntFEAdapter_1 = __importDefault(require("./antfe/AntFEAdapter"));
40
- const LOGGER_NAME = 'ANT+Scanner';
41
- const DEFAULT_SCAN_TIMEOUT = 30000;
42
- const TIMEOUT_STARTUP = 3000;
43
- const hex = (n, len) => {
44
- const c = "0";
45
- let s = n.toString(16);
46
- if (s.length < len)
47
- return `0x${c.repeat(len - s.length)}${s}`;
48
- return `0x${s}`;
49
- };
50
- const isStickPresent = (stick, retries) => __awaiter(void 0, void 0, void 0, function* () {
51
- let n = 0;
52
- while (n < retries) {
53
- try {
54
- return stick.is_present();
55
- }
56
- catch (e) {
57
- n++;
58
- yield new Promise(resolve => setTimeout(resolve, 1000));
59
- }
60
- }
61
- return false;
62
- });
63
- class AntProfile {
64
- constructor(profile, AntScannerClass, stick, message, onNewDevice, onData) {
65
- if (process.env.ANT_PROFILE_DEBUG)
66
- console.log('adding profile', profile, AntScannerClass, message, onNewDevice, onData);
67
- this.ids = [];
68
- this.scanner = new AntScannerClass(stick);
69
- this.scanner.on(message, data => {
70
- try {
71
- if (process.env.ANT_PROFILE_DEBUG)
72
- console.log(data);
73
- if (data.DeviceID) {
74
- if (this.ids.find(id => id === data.DeviceID)) {
75
- if (onData)
76
- onData(profile, data.DeviceID, data);
77
- return;
78
- }
79
- this.ids.push(data.DeviceID);
80
- if (onNewDevice)
81
- onNewDevice(profile, data.DeviceID);
82
- }
83
- }
84
- catch (err) {
85
- }
86
- });
87
- }
88
- getScanner() {
89
- return this.scanner;
90
- }
91
- getProfile() {
92
- return this.profile;
93
- }
94
- }
95
- class AntProtocol extends protocol_1.default {
96
- constructor(antClass) {
97
- super();
98
- this.logger = new gd_eventlog_1.EventLogger(LOGGER_NAME);
99
- this.ant = antClass;
100
- this.activeScans = {};
101
- this.sensors = {};
102
- this.sticks = [];
103
- this.scanning = false;
104
- this.profiles = [
105
- { name: 'Heartrate Monitor', Adapter: AntHrmAdapter_1.default },
106
- { name: 'Smart Trainer', Adapter: AntFEAdapter_1.default },
107
- { name: 'Power Meter', Adapter: pwr_adapter_1.default }
108
- ];
109
- }
110
- add(settings) {
111
- this.logger.logEvent({ message: 'adding device', settings });
112
- const { profile, deviceID, port } = settings;
113
- const profileInfo = this.profiles.find(i => i.name === profile);
114
- if (profileInfo) {
115
- let device;
116
- try {
117
- device = new profileInfo.Adapter(deviceID, port, undefined, this);
118
- this.devices.push(device);
119
- return device;
120
- }
121
- catch (err) {
122
- this.logger.logEvent({ message: 'adding device error', error: err.message });
123
- return;
124
- }
125
- }
126
- this.logger.logEvent({ message: 'adding device: profile not found' });
127
- }
128
- getAnt() {
129
- return this.ant || protocol_1.default.getAnt();
130
- }
131
- getName() { return 'Ant'; }
132
- getInterfaces() { return [protocol_1.INTERFACE.ANT]; }
133
- isBike() { return true; }
134
- isHrm() { return true; }
135
- isPower() { return true; }
136
- isScanning() { return Object.keys(this.activeScans).length > 0; }
137
- getSupportedProfiles() {
138
- return this.profiles.map(i => i.name);
139
- }
140
- getUSBDeviceInfo(d) {
141
- if (!d)
142
- return;
143
- return ({
144
- port: `usb:${d.busNumber}-${d.deviceAddress}`,
145
- vendor: d.deviceDescriptor.idVendor,
146
- product: d.deviceDescriptor.idProduct,
147
- inUse: d.inUse
148
- });
149
- }
150
- getStickInfo(sticks) {
151
- const isStick = i => {
152
- return (i && i.vendor === 0x0FCF && (i.product === 0x1008 || i.product === 0x1009));
153
- };
154
- const inUse = i => i && i.inUse;
155
- return sticks
156
- .map(d => this.getUSBDeviceInfo(d))
157
- .reduce((r, i) => r + `${r === '' ? '' : ','}[${i.port} ${hex(i.vendor, 4)} ${hex(i.product, 4)}${isStick(i) ? '*' : ''}${inUse(i) ? 'x' : ''}]`, '');
158
- }
159
- findStickByPort(port) {
160
- const info = this.sticks.find(i => i.port === port);
161
- if (info)
162
- return info.stick;
163
- }
164
- logStickInfo() {
165
- const sticks = this.ant.getSticks();
166
- const info = this.getStickInfo(sticks);
167
- this.logger.logEvent({ message: 'stick info', info });
168
- }
169
- getDetailedStickInfo(stick) {
170
- const devices = stick.getDevices();
171
- if (devices.length > 0) {
172
- const device = devices[0];
173
- try {
174
- const config = JSON.parse(JSON.stringify(device.configDescriptor));
175
- const interfaces = config ? config.interfaces : [];
176
- delete config.interfaces;
177
- this.logger.logEvent({ message: 'USB DeviceConfig', config, interfaces });
178
- }
179
- catch (err) {
180
- this.logger.logEvent({ message: 'USB Error', error: err.message });
181
- }
182
- }
183
- }
184
- getStick(onStart, onError) {
185
- return __awaiter(this, void 0, void 0, function* () {
186
- if (!this.ant)
187
- return;
188
- const startupAttempt = (stick, name) => {
189
- return new Promise((resolve, reject) => {
190
- this.logger.logEvent({ message: `${name} startup attempt` });
191
- if (stick.scanConnected) {
192
- onStart(this);
193
- resolve(stick);
194
- return;
195
- }
196
- if (isStickPresent(stick, 2)) {
197
- stick.on('error', (err) => {
198
- this.logger.logEvent({ message: `${name} startup error`, error: err.message });
199
- onError(err.message);
200
- });
201
- stick.on('startup', () => {
202
- if (stick.scanConnected)
203
- return;
204
- this.logger.logEvent({ message: `${name} startup completed` });
205
- stick.scanConnected = true;
206
- onStart(stick);
207
- resolve(stick);
208
- });
209
- const devices = stick.getDevices();
210
- if (devices && devices.length > 0) {
211
- devices.forEach(d => {
212
- d.closeFn = d.close;
213
- d.close = () => { };
214
- });
215
- }
216
- else {
217
- this.logger.logEvent({ message: `${name} startup failed: no devices ` });
218
- resolve(null);
219
- }
220
- this.getDetailedStickInfo(stick);
221
- let open = false;
222
- try {
223
- open = stick.open();
224
- if (open) {
225
- this.logger.logEvent({ message: `found ${name}` });
226
- const timeoutStartup = Date.now() + TIMEOUT_STARTUP;
227
- const iv = setInterval(() => {
228
- if (!stick.scanConnected && Date.now() > timeoutStartup) {
229
- clearInterval(iv);
230
- this.logger.logEvent({ message: `${name} startup timeout` });
231
- }
232
- if (stick.scanConnected)
233
- clearInterval(iv);
234
- }, 100);
235
- return stick;
236
- }
237
- }
238
- catch (openErr) {
239
- this.logger.logEvent({ message: 'Open Error', error: openErr.message });
240
- }
241
- if (devices && devices.length > 0) {
242
- devices.forEach(d => {
243
- d.close = d.closeFn;
244
- });
245
- }
246
- if (!open) {
247
- while (devices.length) {
248
- let device;
249
- try {
250
- device = devices.shift();
251
- device.open();
252
- const iface = device.interfaces[0];
253
- let kernelDriverActive = undefined;
254
- let claimRequested = false;
255
- try {
256
- kernelDriverActive = iface.isKernelDriverActive();
257
- if (kernelDriverActive) {
258
- iface.detachKernelDriver();
259
- }
260
- claimRequested = true;
261
- iface.claim();
262
- }
263
- catch (kernelErr) {
264
- this.logger.logEvent({ message: 'Kernel Error', error: kernelErr.message, kernelDriverActive, claimRequested });
265
- }
266
- break;
267
- }
268
- catch (deviceErr) {
269
- this.logger.logEvent({ message: 'Device Error', error: deviceErr.message });
270
- if (device) {
271
- try {
272
- device.close();
273
- }
274
- catch (_a) { }
275
- }
276
- }
277
- }
278
- }
279
- }
280
- this.logger.logEvent({ message: `${name} startup failed: no stick present` });
281
- resolve(null);
282
- });
283
- };
284
- let stick = undefined;
285
- stick = yield startupAttempt(new this.ant.GarminStick2(), 'GarminStick2');
286
- if (!stick)
287
- stick = yield startupAttempt(new this.ant.GarminStick3(), 'GarminStick3');
288
- if (!stick)
289
- onError('No stick found');
290
- else
291
- return stick;
292
- });
293
- }
294
- getFirstStick() {
295
- return __awaiter(this, void 0, void 0, function* () {
296
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
297
- if (!this.ant)
298
- return reject(new Error('Ant not supported'));
299
- if (this.sticks && this.sticks.length > 0 && this.sticks[0].connected) {
300
- this.logger.logEvent({ message: 'stick already connected' });
301
- return resolve(this.sticks[0]);
302
- }
303
- try {
304
- let start = Date.now();
305
- let timeout = start + 5000;
306
- let found = false;
307
- const iv = setInterval(() => {
308
- if (!found && Date.now() > timeout) {
309
- clearInterval(iv);
310
- reject(new Error('timeout'));
311
- }
312
- }, 100);
313
- this.getStick((stick) => {
314
- clearInterval(iv);
315
- const port = this.getUSBDeviceInfo(stick.device).port;
316
- if (!this.sticks.find(i => i.port === port)) {
317
- this.sticks.push({ port, stick, connected: true });
318
- }
319
- resolve({ port, stick });
320
- }, (reason) => {
321
- resolve(undefined);
322
- });
323
- }
324
- catch (err) {
325
- this.logger.logEvent({ message: 'getFirstStick error', error: err.message, stack: err.stack });
326
- }
327
- }));
328
- });
329
- }
330
- closeStick(stick) {
331
- this.logger.logEvent({ message: 'closing stick' });
332
- return new Promise((resolve, reject) => {
333
- stick.on('shutdown', () => {
334
- this.logger.logEvent({ message: 'stick shutdown' });
335
- stick.removeAllListeners('shutdown');
336
- const port = this.getUSBDeviceInfo(stick.device).port;
337
- const idx = this.sticks.findIndex(i => i.port === port);
338
- if (idx !== -1) {
339
- this.sticks[idx].connected = false;
340
- }
341
- this.sensors = {};
342
- resolve(true);
343
- });
344
- try {
345
- stick.detach_all();
346
- setTimeout(() => {
347
- try {
348
- stick.close();
349
- }
350
- catch (err) { }
351
- this.logger.logEvent({ message: 'stick closed' });
352
- stick.scanConnected = false;
353
- this.sensors = {};
354
- }, 1000);
355
- }
356
- catch (err) {
357
- reject(err);
358
- }
359
- });
360
- }
361
- stopScanOnStick(stickInfo) {
362
- const { stick, port } = stickInfo;
363
- const state = this.activeScans[port];
364
- return this.closeStick(stick)
365
- .then(() => {
366
- state.isScanning = false;
367
- this.scanning = this.stillScanning();
368
- if (state.iv) {
369
- clearInterval(state.iv);
370
- state.iv = undefined;
371
- }
372
- return true;
373
- })
374
- .catch(err => {
375
- this.logger.logEvent({ message: 'error on closing stick', error: err.message, port });
376
- return true;
377
- });
378
- }
379
- stillScanning() {
380
- const ports = Object.keys(this.activeScans);
381
- return ports.find(p => this.activeScans[p].isScanning) !== undefined;
382
- }
383
- scanOnStick(stickInfo, props = {}) {
384
- const { stick, port } = stickInfo;
385
- const timeout = props.timeout || DEFAULT_SCAN_TIMEOUT;
386
- const { onDeviceFound, onScanFinished, onUpdate, id } = props;
387
- this.logger.logEvent({ message: 'stick scan request', port, activeScans: this.activeScans });
388
- if (process.env.ANT_DEBUG) {
389
- stick.props = { debug: true };
390
- }
391
- return new Promise((resolve, reject) => {
392
- if (!port)
393
- return reject(new Error('busy'));
394
- if (this.activeScans[port] && this.activeScans[port].isScanning)
395
- return reject(new Error('busy'));
396
- if (!this.activeScans[port]) {
397
- this.activeScans[port] = { isScanning: false, stick };
398
- }
399
- const state = this.activeScans[port];
400
- if (state.isScanning)
401
- return reject(new Error('busy'));
402
- state.isScanning = true;
403
- this.logger.logEvent({ message: 'start scan', port });
404
- state.timeout = Date.now() + timeout;
405
- const onNewDevice = (profile, deviceId) => {
406
- this.logger.logEvent({ message: 'found device', profile, id: deviceId });
407
- const profileInfo = this.profiles.find(i => i.name === profile);
408
- if (profileInfo) {
409
- let device;
410
- try {
411
- device = new profileInfo.Adapter(deviceId, port, stick, this, props);
412
- const existing = this.devices.find(d => (d.getID() === deviceId && d.getProfile() === profile));
413
- if (!existing)
414
- this.devices.push(device);
415
- }
416
- catch (err) {
417
- this.logger.logEvent({ message: 'onNewDevice:ERROR', error: err.message });
418
- }
419
- if (device && onDeviceFound) {
420
- onDeviceFound(device, this);
421
- device.setDetected(true);
422
- }
423
- }
424
- };
425
- const onData = (profile, deviceId, data) => {
426
- const device = this.devices.find(d => d.getID() === deviceId);
427
- if (device) {
428
- const isHrm = device.isHrm();
429
- device.onDeviceData(data);
430
- if (device.isHrm() && !isHrm && onDeviceFound) {
431
- onDeviceFound(device, this);
432
- }
433
- if (onUpdate)
434
- onUpdate(device);
435
- }
436
- };
437
- const hrm = new AntProfile('Heartrate Monitor', this.ant.HeartRateScanner, stick, 'hbData', onNewDevice, onData);
438
- const fe = new AntProfile('Smart Trainer', this.ant.FitnessEquipmentScanner, stick, 'fitnessData', onNewDevice, onData);
439
- const power = new AntProfile('Power Meter', this.ant.BicyclePowerScanner, stick, 'powerData', onNewDevice, onData);
440
- try {
441
- hrm.getScanner().scan();
442
- hrm.getScanner().on('attached', () => {
443
- power.getScanner().scan();
444
- fe.getScanner().scan();
445
- });
446
- }
447
- catch (err) {
448
- this.logger.logEvent({ message: 'scan error', error: err.message });
449
- }
450
- state.iv = setInterval(() => {
451
- if (Date.now() > timeout) {
452
- this.logger.logEvent({ message: 'scan timeout', port });
453
- this.stopScanOnStick(stickInfo).then(() => {
454
- if (onScanFinished)
455
- onScanFinished(id);
456
- resolve(true);
457
- });
458
- }
459
- }, timeout);
460
- });
461
- }
462
- scan(props) {
463
- return __awaiter(this, void 0, void 0, function* () {
464
- this.logger.logEvent({ message: 'scan request', props });
465
- this.scanning = true;
466
- this.logStickInfo();
467
- if (this.sensors && this.sensors.stick && this.sensors.stickOpen) {
468
- try {
469
- yield this.closeStick(this.sensors.stick);
470
- this.sensors = {};
471
- this.devices = [];
472
- }
473
- catch (err) {
474
- this.logger.logEvent({ message: 'error on closing stick', error: err.message });
475
- }
476
- }
477
- try {
478
- const stick = yield this.getFirstStick();
479
- if (!stick) {
480
- this.logger.logEvent({ message: 'no stick found' });
481
- return;
482
- }
483
- this.scanOnStick(stick, props);
484
- }
485
- catch (err) {
486
- this.logger.logEvent({ message: 'scan request error', error: err.message });
487
- }
488
- });
489
- }
490
- stopScan() {
491
- return __awaiter(this, void 0, void 0, function* () {
492
- const activePorts = Object.keys(this.activeScans);
493
- for (let i = 0; i < activePorts.length; i++) {
494
- const port = activePorts[i];
495
- const scanState = this.activeScans[port];
496
- if (scanState.isScanning) {
497
- yield this.stopScanOnStick({ port, stick: scanState.stick });
498
- }
499
- }
500
- this.sensors = {};
501
- this.logger.logEvent({ message: 'scan stopped' });
502
- this.scanning = false;
503
- return true;
504
- });
505
- }
506
- waitForStickOpenedForSensor() {
507
- return new Promise((resolve, reject) => {
508
- const iv = setInterval(() => {
509
- if (!this.sensors.stickOpening && !this.scanning) {
510
- clearInterval(iv);
511
- resolve(true);
512
- }
513
- }, 100);
514
- });
515
- }
516
- attachSensors(d, SensorClass, message) {
517
- return __awaiter(this, void 0, void 0, function* () {
518
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
519
- if (d === undefined) {
520
- resolve(false);
521
- return;
522
- }
523
- const devices = Array.isArray(d) ? d : [d];
524
- if (devices.length === 0) {
525
- return resolve(false);
526
- }
527
- this.logger.logEvent({ message: 'attachSensors', names: Array.isArray(d) ? d.map(dd => dd.getName()) : d.getName(), state: this.sensors });
528
- if (this.sensors.stickOpening || this.scanning) {
529
- yield this.waitForStickOpenedForSensor();
530
- }
531
- this.sensors.stickOpening = true;
532
- let stick;
533
- if (!this.sensors.stick) {
534
- this.logger.logEvent({ message: 'openStick', device: devices[0].getName() });
535
- let retryCnt = 0;
536
- while (!stick && retryCnt < 3) {
537
- try {
538
- const stickInfo = yield this.getFirstStick();
539
- if (stickInfo && stickInfo.stick) {
540
- this.logger.logEvent({ message: 'stick opened', device: devices[0].getName() });
541
- stick = stickInfo.stick;
542
- this.sensors.stick = stick;
543
- this.sensors.stickOpen = true;
544
- this.sensors.stickStarted = true;
545
- this.sensors.stickOpening = false;
546
- }
547
- else {
548
- retryCnt++;
549
- }
550
- }
551
- catch (err) {
552
- retryCnt++;
553
- this.logger.logEvent({ message: 'stick open error', error: err.message, device: devices[0].getName() });
554
- }
555
- }
556
- if (!stick) {
557
- return reject(new Error('could not pen stick'));
558
- }
559
- }
560
- if (this.sensors.stickOpen) {
561
- if (!this.sensors.pending)
562
- this.sensors.pending = [];
563
- devices.forEach(device => {
564
- const sensor = new SensorClass(this.sensors.stick);
565
- device.setSensor(sensor);
566
- device.setStick(stick);
567
- sensor.on(message, (data) => { device.onDeviceData(data); });
568
- sensor.on('eventData', (data) => { device.onDeviceEvent(data); });
569
- sensor.once('attached', () => { device.onAttached(); });
570
- this.sensors.pending.push({ device, sensor, message });
571
- });
572
- }
573
- const attachFromPending = () => {
574
- if (!this.sensors.attached)
575
- this.sensors.attached = [];
576
- const channelsUsed = this.sensors.attached.length;
577
- try {
578
- this.sensors.pending.forEach((i, idx) => {
579
- const channel = channelsUsed + idx;
580
- const { sensor } = i;
581
- i.device.setChannel(channel);
582
- sensor.attach(channel, i.device.getID());
583
- this.sensors.attached.push(i);
584
- });
585
- this.sensors.pending = [];
586
- resolve(true);
587
- }
588
- catch (err) {
589
- this.logger.logEvent({ message: 'error', fn: 'attachFromPending()', error: err.message || err });
590
- reject(err.message ? err : new Error(err));
591
- }
592
- };
593
- if (this.sensors.stickStarted) {
594
- attachFromPending();
595
- }
596
- else {
597
- const sensors = this.sensors;
598
- const stick = this.sensors.stick;
599
- stick.on('error', (err) => {
600
- this.logger.logEvent({ message: 'stick error', error: err.message });
601
- });
602
- stick.once('startup', () => {
603
- sensors.stickStarted = true;
604
- setTimeout(attachFromPending, 1000);
605
- });
606
- }
607
- }));
608
- });
609
- }
610
- detachSensor(adapter) {
611
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
612
- const idx = (this.sensors && this.sensors.attached) ?
613
- this.sensors.attached.findIndex(i => (i.device.getID() === adapter.getID() && i.device.getName() === adapter.getName())) : -1;
614
- if (idx === -1)
615
- return resolve(true);
616
- this.sensors.attached.splice(idx, 1);
617
- if (this.sensors.attached.length > 0)
618
- return resolve(true);
619
- const stick = this.sensors.stick;
620
- if (stick === undefined)
621
- return resolve(false);
622
- try {
623
- yield this.closeStick(stick);
624
- resolve(true);
625
- }
626
- catch (err) {
627
- reject(err);
628
- }
629
- }));
630
- }
631
- closeSensor(device) {
632
- return __awaiter(this, void 0, void 0, function* () {
633
- const stick = this.findStickByPort(device.getPort());
634
- if (stick.inUse) {
635
- try {
636
- stick.close();
637
- }
638
- catch (err) {
639
- this.logger.logEvent({ message: 'closeSensor error', error: err.message, device: device ? device.getName() : 'unknown' });
640
- }
641
- }
642
- });
643
- }
644
- }
645
- exports.AntProtocol = AntProtocol;
646
- let _scanner = undefined;
647
- function AntScanner(antClass) {
648
- const scanner = _scanner || new AntProtocol(antClass);
649
- return scanner;
650
- }
651
- exports.AntScanner = AntScanner;
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
21
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
22
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
23
+ return new (P || (P = Promise))(function (resolve, reject) {
24
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
25
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
26
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
27
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
28
+ });
29
+ };
30
+ var __importDefault = (this && this.__importDefault) || function (mod) {
31
+ return (mod && mod.__esModule) ? mod : { "default": mod };
32
+ };
33
+ Object.defineProperty(exports, "__esModule", { value: true });
34
+ exports.AntScanner = exports.AntProtocol = void 0;
35
+ const gd_eventlog_1 = require("gd-eventlog");
36
+ const protocol_1 = __importStar(require("../protocol"));
37
+ const AntHrmAdapter_1 = __importDefault(require("./anthrm/AntHrmAdapter"));
38
+ const pwr_adapter_1 = __importDefault(require("./antpwr/pwr-adapter"));
39
+ const AntFEAdapter_1 = __importDefault(require("./antfe/AntFEAdapter"));
40
+ const LOGGER_NAME = 'ANT+Scanner';
41
+ const DEFAULT_SCAN_TIMEOUT = 30000;
42
+ const TIMEOUT_STARTUP = 3000;
43
+ const hex = (n, len) => {
44
+ const c = "0";
45
+ let s = n.toString(16);
46
+ if (s.length < len)
47
+ return `0x${c.repeat(len - s.length)}${s}`;
48
+ return `0x${s}`;
49
+ };
50
+ const isStickPresent = (stick, retries) => __awaiter(void 0, void 0, void 0, function* () {
51
+ let n = 0;
52
+ while (n < retries) {
53
+ try {
54
+ return stick.is_present();
55
+ }
56
+ catch (e) {
57
+ n++;
58
+ yield new Promise(resolve => setTimeout(resolve, 1000));
59
+ }
60
+ }
61
+ return false;
62
+ });
63
+ class AntProfile {
64
+ constructor(profile, AntScannerClass, stick, message, onNewDevice, onData) {
65
+ if (process.env.ANT_PROFILE_DEBUG)
66
+ console.log('adding profile', profile, AntScannerClass, message, onNewDevice, onData);
67
+ this.ids = [];
68
+ this.scanner = new AntScannerClass(stick);
69
+ this.scanner.on(message, data => {
70
+ try {
71
+ if (process.env.ANT_PROFILE_DEBUG)
72
+ console.log(data);
73
+ if (data.DeviceID) {
74
+ if (this.ids.find(id => id === data.DeviceID)) {
75
+ if (onData)
76
+ onData(profile, data.DeviceID, data);
77
+ return;
78
+ }
79
+ this.ids.push(data.DeviceID);
80
+ if (onNewDevice)
81
+ onNewDevice(profile, data.DeviceID);
82
+ }
83
+ }
84
+ catch (err) {
85
+ }
86
+ });
87
+ }
88
+ getScanner() {
89
+ return this.scanner;
90
+ }
91
+ getProfile() {
92
+ return this.profile;
93
+ }
94
+ }
95
+ class AntProtocol extends protocol_1.default {
96
+ constructor(antClass) {
97
+ super();
98
+ this.logger = new gd_eventlog_1.EventLogger(LOGGER_NAME);
99
+ this.ant = antClass;
100
+ this.activeScans = {};
101
+ this.sensors = {};
102
+ this.sticks = [];
103
+ this.scanning = false;
104
+ this.profiles = [
105
+ { name: 'Heartrate Monitor', Adapter: AntHrmAdapter_1.default },
106
+ { name: 'Smart Trainer', Adapter: AntFEAdapter_1.default },
107
+ { name: 'Power Meter', Adapter: pwr_adapter_1.default }
108
+ ];
109
+ }
110
+ add(settings) {
111
+ this.logger.logEvent({ message: 'adding device', settings });
112
+ const { profile, deviceID, port } = settings;
113
+ const profileInfo = this.profiles.find(i => i.name === profile);
114
+ if (profileInfo) {
115
+ let device;
116
+ try {
117
+ device = new profileInfo.Adapter(deviceID, port, undefined, this);
118
+ this.devices.push(device);
119
+ return device;
120
+ }
121
+ catch (err) {
122
+ this.logger.logEvent({ message: 'adding device error', error: err.message });
123
+ return;
124
+ }
125
+ }
126
+ this.logger.logEvent({ message: 'adding device: profile not found' });
127
+ }
128
+ getAnt() {
129
+ return this.ant || protocol_1.default.getAnt();
130
+ }
131
+ getName() { return 'Ant'; }
132
+ getInterfaces() { return [protocol_1.INTERFACE.ANT]; }
133
+ isBike() { return true; }
134
+ isHrm() { return true; }
135
+ isPower() { return true; }
136
+ isScanning() { return Object.keys(this.activeScans).length > 0; }
137
+ getSupportedProfiles() {
138
+ return this.profiles.map(i => i.name);
139
+ }
140
+ getUSBDeviceInfo(d) {
141
+ if (!d)
142
+ return;
143
+ return ({
144
+ port: `usb:${d.busNumber}-${d.deviceAddress}`,
145
+ vendor: d.deviceDescriptor.idVendor,
146
+ product: d.deviceDescriptor.idProduct,
147
+ inUse: d.inUse
148
+ });
149
+ }
150
+ getStickInfo(sticks) {
151
+ const isStick = i => {
152
+ return (i && i.vendor === 0x0FCF && (i.product === 0x1008 || i.product === 0x1009));
153
+ };
154
+ const inUse = i => i && i.inUse;
155
+ return sticks
156
+ .map(d => this.getUSBDeviceInfo(d))
157
+ .reduce((r, i) => r + `${r === '' ? '' : ','}[${i.port} ${hex(i.vendor, 4)} ${hex(i.product, 4)}${isStick(i) ? '*' : ''}${inUse(i) ? 'x' : ''}]`, '');
158
+ }
159
+ findStickByPort(port) {
160
+ const info = this.sticks.find(i => i.port === port);
161
+ if (info)
162
+ return info.stick;
163
+ }
164
+ logStickInfo() {
165
+ const sticks = this.ant.getSticks();
166
+ const info = this.getStickInfo(sticks);
167
+ this.logger.logEvent({ message: 'stick info', info });
168
+ }
169
+ getDetailedStickInfo(stick) {
170
+ const devices = stick.getDevices();
171
+ if (devices.length > 0) {
172
+ const device = devices[0];
173
+ try {
174
+ const config = JSON.parse(JSON.stringify(device.configDescriptor));
175
+ const interfaces = config ? config.interfaces : [];
176
+ delete config.interfaces;
177
+ this.logger.logEvent({ message: 'USB DeviceConfig', config, interfaces });
178
+ }
179
+ catch (err) {
180
+ this.logger.logEvent({ message: 'USB Error', error: err.message });
181
+ }
182
+ }
183
+ }
184
+ getStick(onStart, onError) {
185
+ return __awaiter(this, void 0, void 0, function* () {
186
+ if (!this.ant)
187
+ return;
188
+ const startupAttempt = (stick, name) => {
189
+ return new Promise((resolve, reject) => {
190
+ this.logger.logEvent({ message: `${name} startup attempt` });
191
+ if (stick.scanConnected) {
192
+ onStart(this);
193
+ resolve(stick);
194
+ return;
195
+ }
196
+ if (isStickPresent(stick, 2)) {
197
+ stick.on('error', (err) => {
198
+ this.logger.logEvent({ message: `${name} startup error`, error: err.message });
199
+ onError(err.message);
200
+ });
201
+ stick.on('startup', () => {
202
+ if (stick.scanConnected)
203
+ return;
204
+ this.logger.logEvent({ message: `${name} startup completed` });
205
+ stick.scanConnected = true;
206
+ onStart(stick);
207
+ resolve(stick);
208
+ });
209
+ const devices = stick.getDevices();
210
+ if (devices && devices.length > 0) {
211
+ devices.forEach(d => {
212
+ d.closeFn = d.close;
213
+ d.close = () => { };
214
+ });
215
+ }
216
+ else {
217
+ this.logger.logEvent({ message: `${name} startup failed: no devices ` });
218
+ resolve(null);
219
+ }
220
+ this.getDetailedStickInfo(stick);
221
+ let open = false;
222
+ try {
223
+ open = stick.open();
224
+ if (open) {
225
+ this.logger.logEvent({ message: `found ${name}` });
226
+ const timeoutStartup = Date.now() + TIMEOUT_STARTUP;
227
+ const iv = setInterval(() => {
228
+ if (!stick.scanConnected && Date.now() > timeoutStartup) {
229
+ clearInterval(iv);
230
+ this.logger.logEvent({ message: `${name} startup timeout` });
231
+ }
232
+ if (stick.scanConnected)
233
+ clearInterval(iv);
234
+ }, 100);
235
+ return stick;
236
+ }
237
+ }
238
+ catch (openErr) {
239
+ this.logger.logEvent({ message: 'Open Error', error: openErr.message });
240
+ }
241
+ if (devices && devices.length > 0) {
242
+ devices.forEach(d => {
243
+ d.close = d.closeFn;
244
+ });
245
+ }
246
+ if (!open) {
247
+ while (devices.length) {
248
+ let device;
249
+ try {
250
+ device = devices.shift();
251
+ device.open();
252
+ const iface = device.interfaces[0];
253
+ let kernelDriverActive = undefined;
254
+ let claimRequested = false;
255
+ try {
256
+ kernelDriverActive = iface.isKernelDriverActive();
257
+ if (kernelDriverActive) {
258
+ iface.detachKernelDriver();
259
+ }
260
+ claimRequested = true;
261
+ iface.claim();
262
+ }
263
+ catch (kernelErr) {
264
+ this.logger.logEvent({ message: 'Kernel Error', error: kernelErr.message, kernelDriverActive, claimRequested });
265
+ }
266
+ break;
267
+ }
268
+ catch (deviceErr) {
269
+ this.logger.logEvent({ message: 'Device Error', error: deviceErr.message });
270
+ if (device) {
271
+ try {
272
+ device.close();
273
+ }
274
+ catch (_a) { }
275
+ }
276
+ }
277
+ }
278
+ }
279
+ }
280
+ this.logger.logEvent({ message: `${name} startup failed: no stick present` });
281
+ resolve(null);
282
+ });
283
+ };
284
+ let stick = undefined;
285
+ stick = yield startupAttempt(new this.ant.GarminStick2(), 'GarminStick2');
286
+ if (!stick)
287
+ stick = yield startupAttempt(new this.ant.GarminStick3(), 'GarminStick3');
288
+ if (!stick)
289
+ onError('No stick found');
290
+ else
291
+ return stick;
292
+ });
293
+ }
294
+ getFirstStick() {
295
+ return __awaiter(this, void 0, void 0, function* () {
296
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
297
+ if (!this.ant)
298
+ return reject(new Error('Ant not supported'));
299
+ if (this.sticks && this.sticks.length > 0 && this.sticks[0].connected) {
300
+ this.logger.logEvent({ message: 'stick already connected' });
301
+ return resolve(this.sticks[0]);
302
+ }
303
+ try {
304
+ let start = Date.now();
305
+ let timeout = start + 5000;
306
+ let found = false;
307
+ const iv = setInterval(() => {
308
+ if (!found && Date.now() > timeout) {
309
+ clearInterval(iv);
310
+ reject(new Error('timeout'));
311
+ }
312
+ }, 100);
313
+ this.getStick((stick) => {
314
+ clearInterval(iv);
315
+ const port = this.getUSBDeviceInfo(stick.device).port;
316
+ if (!this.sticks.find(i => i.port === port)) {
317
+ this.sticks.push({ port, stick, connected: true });
318
+ }
319
+ resolve({ port, stick });
320
+ }, (reason) => {
321
+ resolve(undefined);
322
+ });
323
+ }
324
+ catch (err) {
325
+ this.logger.logEvent({ message: 'getFirstStick error', error: err.message, stack: err.stack });
326
+ }
327
+ }));
328
+ });
329
+ }
330
+ closeStick(stick) {
331
+ this.logger.logEvent({ message: 'closing stick' });
332
+ return new Promise((resolve, reject) => {
333
+ stick.on('shutdown', () => {
334
+ this.logger.logEvent({ message: 'stick shutdown' });
335
+ stick.removeAllListeners('shutdown');
336
+ const port = this.getUSBDeviceInfo(stick.device).port;
337
+ const idx = this.sticks.findIndex(i => i.port === port);
338
+ if (idx !== -1) {
339
+ this.sticks[idx].connected = false;
340
+ }
341
+ this.sensors = {};
342
+ resolve(true);
343
+ });
344
+ try {
345
+ stick.detach_all();
346
+ setTimeout(() => {
347
+ try {
348
+ stick.close();
349
+ }
350
+ catch (err) { }
351
+ this.logger.logEvent({ message: 'stick closed' });
352
+ stick.scanConnected = false;
353
+ this.sensors = {};
354
+ }, 1000);
355
+ }
356
+ catch (err) {
357
+ reject(err);
358
+ }
359
+ });
360
+ }
361
+ stopScanOnStick(stickInfo) {
362
+ const { stick, port } = stickInfo;
363
+ const state = this.activeScans[port];
364
+ return this.closeStick(stick)
365
+ .then(() => {
366
+ state.isScanning = false;
367
+ this.scanning = this.stillScanning();
368
+ if (state.iv) {
369
+ clearInterval(state.iv);
370
+ state.iv = undefined;
371
+ }
372
+ return true;
373
+ })
374
+ .catch(err => {
375
+ this.logger.logEvent({ message: 'error on closing stick', error: err.message, port });
376
+ return true;
377
+ });
378
+ }
379
+ stillScanning() {
380
+ const ports = Object.keys(this.activeScans);
381
+ return ports.find(p => this.activeScans[p].isScanning) !== undefined;
382
+ }
383
+ scanOnStick(stickInfo, props = {}) {
384
+ const { stick, port } = stickInfo;
385
+ const timeout = props.timeout || DEFAULT_SCAN_TIMEOUT;
386
+ const { onDeviceFound, onScanFinished, onUpdate, id } = props;
387
+ this.logger.logEvent({ message: 'stick scan request', port, activeScans: this.activeScans });
388
+ if (process.env.ANT_DEBUG) {
389
+ stick.props = { debug: true };
390
+ }
391
+ return new Promise((resolve, reject) => {
392
+ if (!port)
393
+ return reject(new Error('busy'));
394
+ if (this.activeScans[port] && this.activeScans[port].isScanning)
395
+ return reject(new Error('busy'));
396
+ if (!this.activeScans[port]) {
397
+ this.activeScans[port] = { isScanning: false, stick };
398
+ }
399
+ const state = this.activeScans[port];
400
+ if (state.isScanning)
401
+ return reject(new Error('busy'));
402
+ state.isScanning = true;
403
+ this.logger.logEvent({ message: 'start scan', port });
404
+ state.timeout = Date.now() + timeout;
405
+ const onNewDevice = (profile, deviceId) => {
406
+ this.logger.logEvent({ message: 'found device', profile, id: deviceId });
407
+ const profileInfo = this.profiles.find(i => i.name === profile);
408
+ if (profileInfo) {
409
+ let device;
410
+ try {
411
+ device = new profileInfo.Adapter(deviceId, port, stick, this, props);
412
+ const existing = this.devices.find(d => (d.getID() === deviceId && d.getProfile() === profile));
413
+ if (!existing)
414
+ this.devices.push(device);
415
+ }
416
+ catch (err) {
417
+ this.logger.logEvent({ message: 'onNewDevice:ERROR', error: err.message });
418
+ }
419
+ if (device && onDeviceFound) {
420
+ onDeviceFound(device, this);
421
+ device.setDetected(true);
422
+ }
423
+ }
424
+ };
425
+ const onData = (profile, deviceId, data) => {
426
+ const device = this.devices.find(d => d.getID() === deviceId);
427
+ if (device) {
428
+ const isHrm = device.isHrm();
429
+ device.onDeviceData(data);
430
+ if (device.isHrm() && !isHrm && onDeviceFound) {
431
+ onDeviceFound(device, this);
432
+ }
433
+ if (onUpdate)
434
+ onUpdate(device);
435
+ }
436
+ };
437
+ const hrm = new AntProfile('Heartrate Monitor', this.ant.HeartRateScanner, stick, 'hbData', onNewDevice, onData);
438
+ const fe = new AntProfile('Smart Trainer', this.ant.FitnessEquipmentScanner, stick, 'fitnessData', onNewDevice, onData);
439
+ const power = new AntProfile('Power Meter', this.ant.BicyclePowerScanner, stick, 'powerData', onNewDevice, onData);
440
+ try {
441
+ hrm.getScanner().scan();
442
+ hrm.getScanner().on('attached', () => {
443
+ power.getScanner().scan();
444
+ fe.getScanner().scan();
445
+ });
446
+ }
447
+ catch (err) {
448
+ this.logger.logEvent({ message: 'scan error', error: err.message });
449
+ }
450
+ state.iv = setInterval(() => {
451
+ if (Date.now() > timeout) {
452
+ this.logger.logEvent({ message: 'scan timeout', port });
453
+ this.stopScanOnStick(stickInfo).then(() => {
454
+ if (onScanFinished)
455
+ onScanFinished(id);
456
+ resolve(true);
457
+ });
458
+ }
459
+ }, timeout);
460
+ });
461
+ }
462
+ scan(props) {
463
+ return __awaiter(this, void 0, void 0, function* () {
464
+ this.logger.logEvent({ message: 'scan request', props });
465
+ this.scanning = true;
466
+ this.logStickInfo();
467
+ if (this.sensors && this.sensors.stick && this.sensors.stickOpen) {
468
+ try {
469
+ yield this.closeStick(this.sensors.stick);
470
+ this.sensors = {};
471
+ this.devices = [];
472
+ }
473
+ catch (err) {
474
+ this.logger.logEvent({ message: 'error on closing stick', error: err.message });
475
+ }
476
+ }
477
+ try {
478
+ const stick = yield this.getFirstStick();
479
+ if (!stick) {
480
+ this.logger.logEvent({ message: 'no stick found' });
481
+ return;
482
+ }
483
+ this.scanOnStick(stick, props);
484
+ }
485
+ catch (err) {
486
+ this.logger.logEvent({ message: 'scan request error', error: err.message });
487
+ }
488
+ });
489
+ }
490
+ stopScan() {
491
+ return __awaiter(this, void 0, void 0, function* () {
492
+ const activePorts = Object.keys(this.activeScans);
493
+ for (let i = 0; i < activePorts.length; i++) {
494
+ const port = activePorts[i];
495
+ const scanState = this.activeScans[port];
496
+ if (scanState.isScanning) {
497
+ yield this.stopScanOnStick({ port, stick: scanState.stick });
498
+ }
499
+ }
500
+ this.sensors = {};
501
+ this.logger.logEvent({ message: 'scan stopped' });
502
+ this.scanning = false;
503
+ return true;
504
+ });
505
+ }
506
+ waitForStickOpenedForSensor() {
507
+ return new Promise((resolve, reject) => {
508
+ const iv = setInterval(() => {
509
+ if (!this.sensors.stickOpening && !this.scanning) {
510
+ clearInterval(iv);
511
+ resolve(true);
512
+ }
513
+ }, 100);
514
+ });
515
+ }
516
+ attachSensors(d, SensorClass, message) {
517
+ return __awaiter(this, void 0, void 0, function* () {
518
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
519
+ if (d === undefined) {
520
+ resolve(false);
521
+ return;
522
+ }
523
+ const devices = Array.isArray(d) ? d : [d];
524
+ if (devices.length === 0) {
525
+ return resolve(false);
526
+ }
527
+ this.logger.logEvent({ message: 'attachSensors', names: Array.isArray(d) ? d.map(dd => dd.getName()) : d.getName(), state: this.sensors });
528
+ if (this.sensors.stickOpening || this.scanning) {
529
+ yield this.waitForStickOpenedForSensor();
530
+ }
531
+ this.sensors.stickOpening = true;
532
+ let stick;
533
+ if (!this.sensors.stick) {
534
+ this.logger.logEvent({ message: 'openStick', device: devices[0].getName() });
535
+ let retryCnt = 0;
536
+ while (!stick && retryCnt < 3) {
537
+ try {
538
+ const stickInfo = yield this.getFirstStick();
539
+ if (stickInfo && stickInfo.stick) {
540
+ this.logger.logEvent({ message: 'stick opened', device: devices[0].getName() });
541
+ stick = stickInfo.stick;
542
+ this.sensors.stick = stick;
543
+ this.sensors.stickOpen = true;
544
+ this.sensors.stickStarted = true;
545
+ this.sensors.stickOpening = false;
546
+ }
547
+ else {
548
+ retryCnt++;
549
+ }
550
+ }
551
+ catch (err) {
552
+ retryCnt++;
553
+ this.logger.logEvent({ message: 'stick open error', error: err.message, device: devices[0].getName() });
554
+ }
555
+ }
556
+ if (!stick) {
557
+ return reject(new Error('could not pen stick'));
558
+ }
559
+ }
560
+ if (this.sensors.stickOpen) {
561
+ if (!this.sensors.pending)
562
+ this.sensors.pending = [];
563
+ devices.forEach(device => {
564
+ const sensor = new SensorClass(this.sensors.stick);
565
+ device.setSensor(sensor);
566
+ device.setStick(stick);
567
+ sensor.on(message, (data) => { device.onDeviceData(data); });
568
+ sensor.on('eventData', (data) => { device.onDeviceEvent(data); });
569
+ sensor.once('attached', () => { device.onAttached(); });
570
+ this.sensors.pending.push({ device, sensor, message });
571
+ });
572
+ }
573
+ const attachFromPending = () => {
574
+ if (!this.sensors.attached)
575
+ this.sensors.attached = [];
576
+ const channelsUsed = this.sensors.attached.length;
577
+ try {
578
+ this.sensors.pending.forEach((i, idx) => {
579
+ const channel = channelsUsed + idx;
580
+ const { sensor } = i;
581
+ i.device.setChannel(channel);
582
+ sensor.attach(channel, i.device.getID());
583
+ this.sensors.attached.push(i);
584
+ });
585
+ this.sensors.pending = [];
586
+ resolve(true);
587
+ }
588
+ catch (err) {
589
+ this.logger.logEvent({ message: 'error', fn: 'attachFromPending()', error: err.message || err });
590
+ reject(err.message ? err : new Error(err));
591
+ }
592
+ };
593
+ if (this.sensors.stickStarted) {
594
+ attachFromPending();
595
+ }
596
+ else {
597
+ const sensors = this.sensors;
598
+ const stick = this.sensors.stick;
599
+ stick.on('error', (err) => {
600
+ this.logger.logEvent({ message: 'stick error', error: err.message });
601
+ });
602
+ stick.once('startup', () => {
603
+ sensors.stickStarted = true;
604
+ setTimeout(attachFromPending, 1000);
605
+ });
606
+ }
607
+ }));
608
+ });
609
+ }
610
+ detachSensor(adapter) {
611
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
612
+ const idx = (this.sensors && this.sensors.attached) ?
613
+ this.sensors.attached.findIndex(i => (i.device.getID() === adapter.getID() && i.device.getName() === adapter.getName())) : -1;
614
+ if (idx === -1)
615
+ return resolve(true);
616
+ this.sensors.attached.splice(idx, 1);
617
+ if (this.sensors.attached.length > 0)
618
+ return resolve(true);
619
+ const stick = this.sensors.stick;
620
+ if (stick === undefined)
621
+ return resolve(false);
622
+ try {
623
+ yield this.closeStick(stick);
624
+ resolve(true);
625
+ }
626
+ catch (err) {
627
+ reject(err);
628
+ }
629
+ }));
630
+ }
631
+ closeSensor(device) {
632
+ return __awaiter(this, void 0, void 0, function* () {
633
+ const stick = this.findStickByPort(device.getPort());
634
+ if (stick.inUse) {
635
+ try {
636
+ stick.close();
637
+ }
638
+ catch (err) {
639
+ this.logger.logEvent({ message: 'closeSensor error', error: err.message, device: device ? device.getName() : 'unknown' });
640
+ }
641
+ }
642
+ });
643
+ }
644
+ }
645
+ exports.AntProtocol = AntProtocol;
646
+ let _scanner = undefined;
647
+ function AntScanner(antClass) {
648
+ const scanner = _scanner || new AntProtocol(antClass);
649
+ return scanner;
650
+ }
651
+ exports.AntScanner = AntScanner;