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
@@ -8,46 +8,50 @@ 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
  exports.Daum8iSerial = exports.Daum8iTcp = void 0;
13
- const indoorbike_js_1 = require("../indoorbike.js");
14
- const constants_js_1 = require("../constants.js");
15
- const tcpserial_1 = require("./tcpserial");
16
+ const constants_1 = require("../constants");
17
+ const tcpserial_1 = __importDefault(require("./tcpserial"));
16
18
  const utils_1 = require("./utils");
17
- const utils_2 = require("../../utils");
18
19
  const gd_eventlog_1 = require("gd-eventlog");
19
20
  const nop = () => { };
20
21
  const MAX_RETRIES = 5;
21
22
  const DEFAULT_TIMEOUT = 10000;
22
23
  const DEFAULT_SEND_DELAY = 1000;
23
- const OPEN_RETRY_DELAY = 3000;
24
- const CLOSE_RETRY_TIMEOUT = 5000;
25
24
  const TIMEOUT_START = 15000;
25
+ const OPEN_TIMEOUT = 1000;
26
26
  const DAUM_PREMIUM_DEFAULT_PORT = 51955;
27
27
  const DAUM_PREMIUM_DEFAULT_HOST = '127.0.0.1';
28
28
  var __SerialPort = undefined;
29
29
  var net = undefined;
30
+ const DEBUG_LOGGER = {
31
+ log: (e, ...args) => console.log(e, ...args),
32
+ logEvent: (event) => console.log(JSON.stringify(event))
33
+ };
30
34
  class Daum8i {
31
35
  constructor(props) {
32
- const opts = props || {};
33
- this.LOG = new gd_eventlog_1.EventLogger('DaumPremium');
34
- this.LOG.logEvent({ message: 'new DaumPremium object', opts });
35
- if (opts.interface === 'tcpip') {
36
- const port = opts.port || DAUM_PREMIUM_DEFAULT_PORT;
37
- const host = opts.host || DAUM_PREMIUM_DEFAULT_HOST;
38
- this.portName = `${host}:${port}`;
36
+ this.props = props || {};
37
+ this.logger = process.env.DEBUG ? DEBUG_LOGGER : new gd_eventlog_1.EventLogger('DaumPremium');
38
+ this.logger.logEvent({ message: 'new DaumPremium object', props: this.props });
39
+ if (this.props.interface === 'tcpip') {
40
+ const port = this.props.port || DAUM_PREMIUM_DEFAULT_PORT;
41
+ const host = this.props.host || DAUM_PREMIUM_DEFAULT_HOST;
42
+ this.portName = `${host}:51955`;
39
43
  this.tcpip = true;
40
44
  this.serial = false;
41
45
  this.tcpipConnection = { host, port };
42
46
  }
43
47
  else {
44
- this.portName = opts.port || process.env.COM_PORT;
48
+ this.portName = this.props.port || process.env.COM_PORT;
45
49
  this.tcpip = false;
46
50
  this.serial = true;
47
51
  this.port = this.portName;
48
52
  }
49
- this.settings = opts.settings || {};
50
- this.settings.logger = this.LOG;
53
+ this.settings = this.props.settings || {};
54
+ this.settings.logger = this.logger;
51
55
  this.sendRetryDelay = DEFAULT_SEND_DELAY;
52
56
  this.sp = undefined;
53
57
  this.connected = false;
@@ -61,7 +65,6 @@ class Daum8i {
61
65
  bikeWeight: 10,
62
66
  maxPower: 800
63
67
  };
64
- this.processor = new indoorbike_js_1.default(this);
65
68
  }
66
69
  static getClassName() {
67
70
  return "Daum8i";
@@ -76,7 +79,7 @@ class Daum8i {
76
79
  net = netClass;
77
80
  }
78
81
  static getSupportedInterfaces() {
79
- return [constants_js_1.BIKE_INTERFACE.SERIAL, constants_js_1.BIKE_INTERFACE.TCPIP];
82
+ return [constants_1.BIKE_INTERFACE.SERIAL, constants_1.BIKE_INTERFACE.TCPIP];
80
83
  }
81
84
  getPort() {
82
85
  return this.portName;
@@ -85,7 +88,7 @@ class Daum8i {
85
88
  return this.connected;
86
89
  }
87
90
  setUser(user, callback) {
88
- this.LOG.logEvent({ message: "setUser()", user, port: this.portName });
91
+ this.logger.logEvent({ message: "setUser()", user, port: this.portName });
89
92
  this.settings.user = user || {};
90
93
  var cb = callback || nop;
91
94
  cb(200, user);
@@ -101,43 +104,49 @@ class Daum8i {
101
104
  unblock() {
102
105
  this.blocked = false;
103
106
  }
104
- connect(retry) {
105
- this.LOG.logEvent({ message: "connect()", sp: (this.sp !== undefined), port: this.portName, retry, settings: this.settings, scanMode: this.scanMode });
107
+ connect() {
108
+ this.logger.logEvent({ message: "connect()", sp: (this.sp !== undefined), connected: this.connected, blocked: this.blocked, port: this.portName, settings: this.settings });
106
109
  if (this.connected || this.blocked) {
107
110
  return;
108
111
  }
109
112
  this.state.busy = true;
110
113
  this.state.commandsInQueue = {};
111
114
  try {
115
+ if (this.sp !== undefined) {
116
+ try {
117
+ this.sp.removeAllListeners();
118
+ this.sp.close();
119
+ }
120
+ catch (err) {
121
+ }
122
+ this.sp = undefined;
123
+ }
112
124
  if (this.sp === undefined) {
113
125
  if (this.tcpip) {
114
126
  const { host, port } = this.tcpipConnection;
115
- this.sp = new tcpserial_1.default({ host, port, net });
127
+ const { logger } = this.props;
128
+ this.logger.logEvent({ message: "creating TCPSocketPort", host, port });
129
+ this.sp = new tcpserial_1.default({ host, port, net, timeout: OPEN_TIMEOUT, logger });
116
130
  }
117
131
  else {
118
132
  const settings = this.settings.port || {};
119
133
  settings.autoOpen = false;
134
+ this.logger.logEvent({ message: "creating SerialPort", port: this.port, settings });
120
135
  this.sp = new __SerialPort(this.port, settings);
121
136
  }
122
137
  this.sp.on('open', this.onPortOpen.bind(this));
123
138
  this.sp.on('close', this.onPortClose.bind(this));
124
139
  this.sp.on('error', (error) => { this.onPortError(error); });
125
140
  this.sp.on('data', (data) => { this.onData(data); });
126
- this.firstOpen = true;
127
141
  }
128
142
  const start = Date.now();
129
143
  this.state.connecting = true;
130
- if (!this.state.opening)
131
- this.state.opening = { start, timeout: start + this.getTimeoutValue(), retry: 0, maxRetries: MAX_RETRIES };
132
- else {
133
- this.state.opening.start = start;
134
- this.state.opening.timeout = start + this.getTimeoutValue();
135
- this.state.opening.retry = this.state.opening.retry + 1;
136
- }
144
+ this.state.opening = { start, timeout: start + this.getTimeoutValue() };
145
+ this.logger.logEvent({ message: "opening port ..." });
137
146
  this.sp.open();
138
147
  }
139
148
  catch (err) {
140
- this.LOG.logEvent({ message: "scan:error:", error: err.message, stack: err.stack });
149
+ this.logger.logEvent({ message: "scan:error:", error: err.message, stack: err.stack });
141
150
  this.state.busy = false;
142
151
  }
143
152
  }
@@ -156,7 +165,13 @@ class Daum8i {
156
165
  this.connect();
157
166
  const tTimeout = Date.now() + TIMEOUT_START;
158
167
  const iv = setInterval(() => {
159
- if (this.isConnected()) {
168
+ if (this.state.error !== undefined) {
169
+ clearInterval(iv);
170
+ this.forceClose();
171
+ reject(this.state.error);
172
+ this.state = { opened: false, closed: true, busy: false };
173
+ }
174
+ else if (this.isConnected()) {
160
175
  this.state.connecting = false;
161
176
  resolve(true);
162
177
  clearInterval(iv);
@@ -164,8 +179,9 @@ class Daum8i {
164
179
  else {
165
180
  if (Date.now() > tTimeout) {
166
181
  this.state.connecting = false;
167
- reject(new Error('timeout'));
182
+ this.forceClose();
168
183
  clearInterval(iv);
184
+ reject(new Error('timeout'));
169
185
  }
170
186
  }
171
187
  }, 100);
@@ -177,10 +193,10 @@ class Daum8i {
177
193
  this.state.opening = undefined;
178
194
  this.state.opened = true;
179
195
  this.state.busy = false;
180
- this.LOG.logEvent({ message: "port opened", port: this.portName });
196
+ this.logger.logEvent({ message: "port opened", port: this.portName });
181
197
  }
182
198
  onPortClose() {
183
- this.LOG.logEvent({ message: "port closed", port: this.portName });
199
+ this.logger.logEvent({ message: "port closed", port: this.portName });
184
200
  this.error = undefined;
185
201
  this.connected = false;
186
202
  if (this.state.opening) {
@@ -190,81 +206,56 @@ class Daum8i {
190
206
  else {
191
207
  this.state = { opened: false, closed: true, busy: false };
192
208
  }
209
+ this.sp.removeAllListeners();
193
210
  this.sp = undefined;
194
211
  if (this.queue !== undefined)
195
212
  this.queue.clear();
196
213
  }
214
+ getLogState() {
215
+ let s = undefined;
216
+ const { sending, busy, opening, connecting, writeBusy, waitingForStart, waitingForAck, waitingForEnd, retry } = this.state;
217
+ if (sending) {
218
+ s = {};
219
+ s.command = sending.command;
220
+ s.payload = sending.payload;
221
+ }
222
+ return { sending: s, busy, writeBusy, opening, connecting, waitingForStart, waitingForEnd, waitingForAck, retry };
223
+ }
197
224
  onPortError(error) {
198
- this.LOG.logEvent({ message: "port error:", port: this.portName, error: error.message, connected: this.connected, state: this.state });
225
+ this.logger.logEvent({ message: "port error:", port: this.portName, error: error.message, connected: this.connected, state: this.getLogState() });
199
226
  this.error = error;
200
227
  if (this.blocked) {
201
228
  if (!this.state.closed) {
202
- if (this.sp)
229
+ if (this.sp) {
230
+ this.sp.removeAllListeners();
203
231
  this.sp.close();
232
+ this.sp = undefined;
233
+ }
204
234
  this.state = { opened: false, closed: true, busy: false };
205
235
  }
206
236
  return;
207
237
  }
208
- const reconnect = () => {
209
- if (this.state.opening && !this.state.closing) {
210
- this.LOG.logEvent({ message: "retry connection:", portName: this.port, connected: this.connected, scanMode: this.scanMode });
211
- this.connect(true);
212
- }
213
- };
214
238
  if (this.state.closing) {
215
239
  if (error.message === 'Port is not open') {
216
240
  this.state = { opened: false, closed: true, busy: false };
217
241
  return;
218
242
  }
219
243
  else {
220
- const { retry, maxRetries } = this.state.closing;
221
- if ((retry + 1 < maxRetries)) {
222
- this.state.closing.retry = retry + 1;
223
- return setTimeout(() => { this.close(); }, CLOSE_RETRY_TIMEOUT);
224
- }
225
- else {
226
- this.LOG.logEvent({ message: "close request failed - giving up", port: this.portName });
227
- this.state.closing = undefined;
228
- }
244
+ this.forceClose();
229
245
  }
230
246
  }
231
247
  else if (this.state.opening) {
232
- if (!this.state.connect) {
233
- const { retry, maxRetries } = this.state.opening;
234
- try {
235
- if (this.sp)
236
- this.sp.close();
237
- }
238
- catch (err) {
239
- console.log(err);
240
- }
241
- if ((retry + 1) < maxRetries) {
242
- this.state.opening.retry = retry + 1;
243
- setTimeout(() => {
244
- if (!this.state.busy)
245
- reconnect();
246
- else {
247
- const iv = setInterval(() => {
248
- if (!this.state.busy) {
249
- clearInterval(iv);
250
- reconnect();
251
- }
252
- }, 50);
253
- }
254
- }, OPEN_RETRY_DELAY);
255
- }
256
- else {
257
- this.state.opening = undefined;
258
- }
248
+ if (this.state.connecting) {
249
+ this.state.error = error;
259
250
  }
260
251
  else {
261
252
  this.onPortOpen();
262
253
  }
263
254
  }
264
255
  else if (this.state.sending) {
265
- this.LOG.logEvent({ message: "closing port", port: this.portName });
266
- this.sp.close();
267
- this.state = { opened: true, closed: false, busy: true };
256
+ this.state.error = error;
257
+ this.forceClose(false);
258
+ return;
268
259
  }
269
260
  this.state.busy = false;
270
261
  }
@@ -286,36 +277,46 @@ class Daum8i {
286
277
  }, 50);
287
278
  });
288
279
  }
289
- close() {
290
- this.LOG.logEvent({ message: 'close request', port: this.portName });
291
- var port = this.sp;
292
- if (this.bikeCmdWorker !== undefined) {
293
- this.LOG.logEvent({ message: "stopping worker", port: this.portName });
294
- clearInterval(this.bikeCmdWorker);
295
- this.bikeCmdWorker = undefined;
280
+ forceClose(updateState = false) {
281
+ const sp = this.sp;
282
+ if (!this.sp)
283
+ return;
284
+ this.sp.removeAllListeners();
285
+ try {
286
+ sp.unpipe();
287
+ sp.flush();
296
288
  }
289
+ catch (_a) { }
290
+ sp.close();
291
+ this.connected = false;
292
+ if (updateState)
293
+ this.state = { opened: false, closed: true, busy: false };
294
+ }
295
+ close() {
296
+ this.logger.logEvent({ message: 'close request', port: this.portName });
297
+ var sp = this.sp;
297
298
  let connected = this.connected;
298
299
  try {
299
300
  if (connected) {
300
- if (port) {
301
- port.unpipe();
302
- port.flush();
303
- port.close();
301
+ if (sp) {
302
+ sp.unpipe();
303
+ sp.flush();
304
+ sp.close();
304
305
  }
305
- this.connected = false;
306
306
  if (this.queue !== undefined) {
307
307
  this.queue.clear();
308
308
  this.queue = undefined;
309
309
  }
310
310
  }
311
311
  else {
312
- if (port)
313
- port.close();
312
+ if (sp)
313
+ sp.close();
314
314
  }
315
315
  }
316
316
  catch (err) {
317
- this.LOG.logEvent({ message: 'close: Exception', port: this.portName, error: err.message });
317
+ this.logger.logEvent({ message: 'close: Exception', port: this.portName, error: err.message });
318
318
  }
319
+ this.connected = false;
319
320
  const start = Date.now();
320
321
  if (this.state.closing === undefined)
321
322
  this.state.closing = { start, timeout: start + this.getTimeoutValue(), retry: 0, maxRetries: MAX_RETRIES };
@@ -327,7 +328,7 @@ class Daum8i {
327
328
  this.state.busy = false;
328
329
  }
329
330
  sendTimeout(message) {
330
- this.LOG.logEvent({ message: `sendCommand:${message || 'timeout'}`, port: this.portName, cmd: this.cmdCurrent });
331
+ this.logger.logEvent({ message: `sendCommand:${message || 'timeout'}`, port: this.portName, cmd: this.cmdCurrent });
331
332
  delete this.state.commandsInQueue[this.cmdCurrent.command];
332
333
  if (this.cmdCurrent.callbackErr !== undefined) {
333
334
  let cb = this.cmdCurrent.callbackErr;
@@ -337,29 +338,39 @@ class Daum8i {
337
338
  cb(408, { message: message || "timeout" });
338
339
  }
339
340
  }
340
- checkForTimeout(reject) {
341
+ checkForResponse() {
341
342
  const d = Date.now();
342
343
  const s = this.state.sending;
343
344
  if (s === undefined)
344
- return;
345
+ return false;
346
+ const rejectFn = s.reject;
347
+ const reject = (err) => {
348
+ if (rejectFn && typeof rejectFn === 'function') {
349
+ rejectFn(err);
350
+ }
351
+ };
352
+ const error = this.state.error;
353
+ if (error !== undefined) {
354
+ reject(error);
355
+ return false;
356
+ }
345
357
  try {
346
- if (!this.state.sending)
347
- return;
348
358
  if (this.state.waitingForACK) {
349
359
  const timeoutACK = this.state.ack ? this.state.ack.timeout : this.state.sending.timeout;
350
360
  if (d < timeoutACK)
351
- return;
361
+ return true;
352
362
  reject(new Error('ACK timeout'));
353
- return;
363
+ return false;
354
364
  }
355
365
  if (d < this.state.sending.timeout)
356
- return;
357
- reject(new Error('timeout'));
358
- return;
366
+ return true;
367
+ reject(new Error('RESP timeout'));
368
+ return false;
359
369
  }
360
370
  catch (err) {
361
- this.LOG.logEvent({ message: 'checkForTimeout: Exception', port: this.portName, error: err.message, stack: err.stack });
371
+ this.logger.logEvent({ message: 'checkForResponse: Exception', port: this.portName, error: err.message, stack: err.stack });
362
372
  }
373
+ return true;
363
374
  }
364
375
  getTimeoutValue(cmd) {
365
376
  let timeout = DEFAULT_TIMEOUT;
@@ -374,103 +385,153 @@ class Daum8i {
374
385
  }
375
386
  onData(data) {
376
387
  let cmd = '';
377
- if (!Buffer.isBuffer(data)) {
378
- data = Buffer.from(data, 'latin1');
388
+ if (this.state.waitingForEnd) {
389
+ cmd = this.state.partialCmd;
379
390
  }
391
+ const bufferData = Buffer.isBuffer(data) ? data : Buffer.from(data, 'latin1');
380
392
  const s = this.state.sending;
381
393
  if (s === undefined) {
382
394
  if (this.state.input === undefined)
383
- this.state.input = Buffer.from(data);
395
+ this.state.input = bufferData;
384
396
  return;
385
397
  }
386
398
  const { portName, resolve } = this.state.sending;
387
399
  let incoming;
388
400
  if (this.state.input !== undefined) {
389
- const arr = [this.state.input, data];
401
+ const arr = [this.state.input, bufferData];
390
402
  incoming = Buffer.concat(arr);
391
403
  }
392
404
  else {
393
- incoming = data;
405
+ incoming = bufferData;
394
406
  }
407
+ const response = [...incoming];
408
+ this.logger.logEvent({ message: 'sendCommand:RECV', data: (0, utils_1.hexstr)(response) });
395
409
  for (let i = 0; i < incoming.length; i++) {
410
+ const getRemaining = () => {
411
+ let remaining = '';
412
+ const done = i === (incoming.length - 1);
413
+ if (!done) {
414
+ for (let j = i + 1; j < incoming.length; j++)
415
+ remaining += String.fromCharCode(incoming.readUInt8(j));
416
+ }
417
+ return remaining;
418
+ };
396
419
  const c = incoming.readUInt8(i);
397
420
  if (c === 0x06) {
398
- this.LOG.logEvent({ message: "sendCommand:ACK received:", port: portName });
421
+ this.logger.logEvent({ message: "sendCommand:ACK received:", port: portName });
399
422
  this.state.waitingForStart = true;
400
423
  this.state.waitingForACK = false;
424
+ const remaining = getRemaining();
425
+ if (remaining && remaining !== '')
426
+ return this.onData(remaining);
401
427
  }
402
428
  else if (c === 0x15) {
403
429
  this.state.waitingForStart = true;
404
430
  this.state.waitingForACK = false;
405
- this.LOG.logEvent({ message: "sendCommand:NAK received:", port: portName });
431
+ this.logger.logEvent({ message: "sendCommand:NAK received:", port: portName });
432
+ const remaining = getRemaining();
433
+ if (remaining && remaining !== '')
434
+ return this.onData(remaining);
406
435
  }
407
436
  else if (c === 0x01) {
408
437
  this.state.waitingForEnd = true;
409
438
  }
410
439
  else if (c === 0x17) {
411
- this.LOG.logEvent({ message: "sendCommand:received:", port: portName, cmd: `${cmd} [${utils_1.hexstr(cmd)}]` });
412
- if (this.state.sending.timeoutCheckIv)
413
- clearInterval(this.state.sending.timeoutCheckIv);
414
- this.state = {
415
- sending: undefined,
416
- busy: false,
417
- writeBusy: false,
418
- waitingForStart: false,
419
- waitingForEnd: false,
420
- waitingForACK: false,
421
- };
422
- this.sendACK();
423
- const payload = cmd.substring(3, cmd.length - 2);
424
- resolve(payload);
440
+ const remaining = getRemaining();
441
+ this.logger.logEvent({ message: "sendCommand:received:", duration: Date.now() - this.state.sending.tsRequest, port: portName, cmd: `${cmd} [${(0, utils_1.hexstr)(cmd)}]`, remaining: (0, utils_1.hexstr)(remaining) });
442
+ this.state.waitingForEnd = false;
443
+ const cmdStr = cmd.substring(0, cmd.length - 2);
444
+ const checksumExtracted = cmd.slice(-2);
445
+ const checksumCalculated = (0, utils_1.checkSum)((0, utils_1.getAsciiArrayFromStr)(cmdStr), []);
446
+ if (checksumExtracted === checksumCalculated) {
447
+ this.sendACK();
448
+ if (this.state.sending && this.state.sending.responseCheckIv) {
449
+ clearInterval(this.state.sending.responseCheckIv);
450
+ }
451
+ this.state = {
452
+ sending: undefined,
453
+ busy: false,
454
+ writeBusy: false,
455
+ waitingForStart: false,
456
+ waitingForEnd: false,
457
+ waitingForACK: false,
458
+ };
459
+ const payload = cmd.substring(3, cmd.length - 2);
460
+ resolve(payload);
461
+ }
462
+ else {
463
+ this.sendNAK();
464
+ }
425
465
  cmd = '';
466
+ if (remaining)
467
+ return this.onData(remaining);
426
468
  }
427
469
  else {
428
470
  if (this.state.waitingForEnd)
429
471
  cmd += String.fromCharCode(c);
430
472
  }
431
473
  }
474
+ if (this.state.waitingForEnd) {
475
+ this.state.partialCmd = cmd;
476
+ }
432
477
  }
433
- sendDaum8iCommand(command, queryType, payload, cb) {
478
+ sendDaum8iCommand(command, queryType, payload) {
479
+ const tsRequest = Date.now();
434
480
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
435
481
  if (this.blocked)
436
- reject(new Error('blocked'));
482
+ return reject(new Error('blocked'));
437
483
  if (!this.state.busy) {
438
484
  this.state.busy = true;
439
- if (!this.connected) {
440
- reject(new Error('not connected'));
441
- if (!this.state.connecting) {
442
- this.saveConnect(true)
443
- .then(() => { this.state.busy = false; })
444
- .catch((reason) => { this.state.busy = reason === 'busy'; });
445
- }
446
- return;
447
- }
448
485
  }
449
486
  else {
450
- let start = Date.now();
451
- while (this.state.busy && Date.now() - start < 5000) {
452
- yield utils_2.sleep(500);
453
- }
454
- if (this.state.busy) {
455
- reject(new Error('timeout'));
456
- return;
487
+ const message = (0, utils_1.buildMessage)(command, payload);
488
+ this.logger.logEvent({ message: 'sendCommand:waiting', port: this.portName, cmd: command, hex: (0, utils_1.hexstr)(message) });
489
+ const busyWait = () => {
490
+ return new Promise((done) => {
491
+ let start = Date.now();
492
+ let timeout = start + 5000;
493
+ const iv = setInterval(() => {
494
+ if (this.state.busy) {
495
+ if (Date.now() > timeout) {
496
+ clearInterval(iv);
497
+ done(false);
498
+ }
499
+ }
500
+ else {
501
+ clearInterval(iv);
502
+ done(true);
503
+ }
504
+ }, 10);
505
+ });
506
+ };
507
+ const res = yield busyWait();
508
+ if (!res) {
509
+ this.logger.logEvent({ message: 'sendCommand:busy timeout', port: this.portName, cmd: command, hex: (0, utils_1.hexstr)(message), duration: Date.now() - tsRequest });
510
+ return reject(new Error('BUSY timeout'));
457
511
  }
458
512
  this.state.busy = true;
459
513
  }
514
+ const writeDone = () => {
515
+ this.state.sending = undefined;
516
+ this.state.writeBusy = false;
517
+ this.state.busy = false;
518
+ this.state.sending = undefined;
519
+ this.state.waitingForStart = false;
520
+ this.state.waitingForEnd = false;
521
+ this.state.waitingForACK = false;
522
+ };
460
523
  const port = this.sp;
461
524
  const portName = this.portName;
462
525
  this.state.received = [];
463
526
  try {
464
- const message = utils_1.buildMessage(command, payload);
527
+ const message = (0, utils_1.buildMessage)(command, payload);
465
528
  const start = Date.now();
466
529
  const timeout = start + this.getTimeoutValue();
467
- this.LOG.logEvent({ message: "sendCommand:sending:", port: this.portName, cmd: command, hex: utils_1.hexstr(message) });
530
+ this.logger.logEvent({ message: "sendCommand:sending:", port: this.portName, cmd: command, hex: (0, utils_1.hexstr)(message) });
468
531
  this.state.writeBusy = true;
469
- if (!this.connected) {
470
- this.LOG.logEvent({ message: "sendCommand:error: not connected", port: this.portName });
471
- this.state.writeBusy = false;
472
- this.state.busy = false;
473
- this.state.sending = undefined;
532
+ if (!this.connected || port === undefined) {
533
+ this.logger.logEvent({ message: "sendCommand:error: not connected", port: this.portName });
534
+ writeDone();
474
535
  return reject(new Error('not connected'));
475
536
  }
476
537
  port.write(message);
@@ -478,34 +539,18 @@ class Daum8i {
478
539
  this.state.writeBusy = false;
479
540
  this.state.retry = 0;
480
541
  this.state.ack = { start, timeout };
481
- this.state.sending = { command, payload, start, timeout, port, portName, resolve, reject };
482
- this.state.sending.timeoutCheckIv = setInterval(() => {
483
- this.checkForTimeout((err) => {
484
- console.log(err.message, this.state.retry, this.state.retryBusy);
485
- if (this.state.retry > 2) {
486
- clearInterval(this.state.sending.timeoutCheckIv);
487
- this.state.sending.timeoutCheckIv = undefined;
488
- return reject(err);
489
- }
490
- if (this.state.retryBusy)
491
- return;
492
- this.state.retryBusy = true;
493
- this.state.retry++;
494
- setTimeout(() => {
495
- const restart = Date.now();
496
- this.state.ack = { start: restart, timeout: restart + this.getTimeoutValue() };
497
- this.LOG.logEvent({ message: "sendCommand:retry:", port: this.portName, cmd: command, hex: utils_1.hexstr(message) });
498
- port.write(message);
499
- this.state.retryBusy = false;
500
- }, this.sendRetryDelay);
501
- });
502
- });
542
+ this.state.sending = { command, payload, start, timeout, port, portName, tsRequest, resolve, reject };
543
+ const iv = this.state.sending.responseCheckIv = setInterval(() => {
544
+ const stillWaiting = this.checkForResponse();
545
+ if (!stillWaiting) {
546
+ clearInterval(iv);
547
+ writeDone();
548
+ }
549
+ }, 10);
503
550
  }
504
551
  catch (err) {
505
- this.LOG.logEvent({ message: "sendCommand:error:", port: portName, error: err.message, stack: err.stack });
506
- this.state.writeBusy = false;
507
- this.state.busy = false;
508
- this.state.sending = undefined;
552
+ this.logger.logEvent({ message: "sendCommand:error:", port: portName, error: err.message, stack: err.stack });
553
+ writeDone();
509
554
  reject(err);
510
555
  }
511
556
  }));
@@ -518,7 +563,7 @@ class Daum8i {
518
563
  }
519
564
  catch (err) { }
520
565
  this.state.writeBusy = false;
521
- this.LOG.logEvent({ message: "sendCommand:sending ACK", port, queue: this.state.commandsInQueue });
566
+ this.logger.logEvent({ message: "sendCommand:sending ACK", port, queue: this.state.commandsInQueue });
522
567
  }
523
568
  sendNAK() {
524
569
  const port = this.portName;
@@ -526,22 +571,22 @@ class Daum8i {
526
571
  this.sp.write([0x15]);
527
572
  }
528
573
  catch (err) { }
529
- this.LOG.logEvent({ message: "sendCommand:sending NAK", port });
574
+ this.logger.logEvent({ message: "sendCommand:sending NAK", port });
530
575
  }
531
- sendReservedDaum8iCommand(command, cmdType, data, onData, onError) {
576
+ sendReservedDaum8iCommand(command, cmdType, data) {
532
577
  let cmdData = [];
533
- const key = utils_1.getReservedCommandKey(command);
534
- utils_1.append(cmdData, utils_1.Int16ToIntArray(key));
578
+ const key = (0, utils_1.getReservedCommandKey)(command);
579
+ (0, utils_1.append)(cmdData, (0, utils_1.Int16ToIntArray)(key));
535
580
  if (data !== undefined && data.length > 0) {
536
- utils_1.append(cmdData, utils_1.Int16ToIntArray(data.length));
537
- utils_1.append(cmdData, data);
581
+ (0, utils_1.append)(cmdData, (0, utils_1.Int16ToIntArray)(data.length));
582
+ (0, utils_1.append)(cmdData, data);
538
583
  }
539
584
  else {
540
- utils_1.append(cmdData, utils_1.Int16ToIntArray(0));
585
+ (0, utils_1.append)(cmdData, (0, utils_1.Int16ToIntArray)(0));
541
586
  }
542
- return this.sendDaum8iCommand('M70', cmdType, utils_1.bin2esc(cmdData))
587
+ return this.sendDaum8iCommand('M70', cmdType, (0, utils_1.bin2esc)(cmdData))
543
588
  .then((resData) => {
544
- const cmd = utils_1.esc2bin(resData);
589
+ const cmd = (0, utils_1.esc2bin)(resData);
545
590
  cmd.splice(0, 4);
546
591
  return cmd;
547
592
  });
@@ -567,7 +612,7 @@ class Daum8i {
567
612
  else if (str === '7')
568
613
  deviceType = 'lyps';
569
614
  else
570
- throw (new Error(`unknown device type ${typeof str === 'string' ? utils_1.ascii(str.charAt(0)) : str}`));
615
+ throw (new Error(`unknown device type ${typeof str === 'string' ? (0, utils_1.ascii)(str.charAt(0)) : str}`));
571
616
  return deviceType;
572
617
  });
573
618
  }
@@ -576,13 +621,13 @@ class Daum8i {
576
621
  .then((str) => {
577
622
  let deviceType;
578
623
  if (str === '0')
579
- deviceType = constants_js_1.ACTUAL_BIKE_TYPE.ALLROUND;
624
+ deviceType = constants_1.ACTUAL_BIKE_TYPE.ALLROUND;
580
625
  else if (str === '1')
581
- deviceType = constants_js_1.ACTUAL_BIKE_TYPE.RACE;
626
+ deviceType = constants_1.ACTUAL_BIKE_TYPE.RACE;
582
627
  else if (str === '2')
583
- deviceType = constants_js_1.ACTUAL_BIKE_TYPE.MOUNTAIN;
628
+ deviceType = constants_1.ACTUAL_BIKE_TYPE.MOUNTAIN;
584
629
  else {
585
- throw (new Error(`unknown actual device type ${typeof str === 'string' ? utils_1.ascii(str.charAt(0)) : str}`));
630
+ throw (new Error(`unknown actual device type ${typeof str === 'string' ? (0, utils_1.ascii)(str.charAt(0)) : str}`));
586
631
  }
587
632
  this.state.actualBikeType = deviceType;
588
633
  return deviceType;
@@ -591,16 +636,16 @@ class Daum8i {
591
636
  setActualBikeType(actualBikeType) {
592
637
  let bikeType;
593
638
  switch (actualBikeType) {
594
- case constants_js_1.ACTUAL_BIKE_TYPE.ALLROUND:
639
+ case constants_1.ACTUAL_BIKE_TYPE.ALLROUND:
595
640
  bikeType = '0';
596
641
  break;
597
- case constants_js_1.ACTUAL_BIKE_TYPE.RACE:
642
+ case constants_1.ACTUAL_BIKE_TYPE.RACE:
598
643
  bikeType = '1';
599
644
  break;
600
- case constants_js_1.ACTUAL_BIKE_TYPE.TRIATHLON:
645
+ case constants_1.ACTUAL_BIKE_TYPE.TRIATHLON:
601
646
  bikeType = '1';
602
647
  break;
603
- case constants_js_1.ACTUAL_BIKE_TYPE.MOUNTAIN:
648
+ case constants_1.ACTUAL_BIKE_TYPE.MOUNTAIN:
604
649
  bikeType = '2';
605
650
  break;
606
651
  default:
@@ -610,11 +655,11 @@ class Daum8i {
610
655
  .then((str) => {
611
656
  let deviceType;
612
657
  if (str === '0')
613
- deviceType = constants_js_1.ACTUAL_BIKE_TYPE.ALLROUND;
658
+ deviceType = constants_1.ACTUAL_BIKE_TYPE.ALLROUND;
614
659
  else if (str === '1')
615
- deviceType = constants_js_1.ACTUAL_BIKE_TYPE.RACE;
660
+ deviceType = constants_1.ACTUAL_BIKE_TYPE.RACE;
616
661
  else if (str === '2')
617
- deviceType = constants_js_1.ACTUAL_BIKE_TYPE.MOUNTAIN;
662
+ deviceType = constants_1.ACTUAL_BIKE_TYPE.MOUNTAIN;
618
663
  else
619
664
  throw (new Error('unknown actual device type'));
620
665
  this.state.actualBikeType = deviceType;
@@ -624,12 +669,12 @@ class Daum8i {
624
669
  getTrainingData() {
625
670
  return this.sendDaum8iCommand('X70', 'AF', [])
626
671
  .then((data) => {
627
- const td = utils_1.parseTrainingData(data);
672
+ const td = (0, utils_1.parseTrainingData)(data);
628
673
  return td;
629
674
  });
630
675
  }
631
676
  setLoadControl(enabled) {
632
- const val = enabled ? utils_1.ascii('1') : utils_1.ascii('0');
677
+ const val = enabled ? (0, utils_1.ascii)('1') : (0, utils_1.ascii)('0');
633
678
  return this.sendDaum8iCommand('S20', 'BF', [val])
634
679
  .then((data) => {
635
680
  const res = data === '1';
@@ -644,7 +689,7 @@ class Daum8i {
644
689
  });
645
690
  }
646
691
  setSlope(slope) {
647
- this.LOG.logEvent({ message: 'setSlope not implemted' });
692
+ this.logger.logEvent({ message: 'setSlope not implemted' });
648
693
  return;
649
694
  }
650
695
  setPower(power) {
@@ -681,23 +726,25 @@ class Daum8iTcp extends Daum8i {
681
726
  static getClassName() { return "Daum8i"; }
682
727
  getType() { return "Daum8iTcp"; }
683
728
  static setSerialPort(spClass) { }
729
+ getInterface() { return constants_1.BIKE_INTERFACE.TCPIP; }
684
730
  static setNetImpl(netClass) {
685
731
  net = netClass;
686
732
  }
687
733
  static getSupportedInterfaces() {
688
- return [constants_js_1.BIKE_INTERFACE.TCPIP];
734
+ return [constants_1.BIKE_INTERFACE.TCPIP];
689
735
  }
690
736
  }
691
737
  exports.Daum8iTcp = Daum8iTcp;
692
738
  class Daum8iSerial extends Daum8i {
693
739
  static getClassName() { return "Daum8i"; }
694
740
  getType() { return "Daum8iSerial"; }
741
+ getInterface() { return constants_1.BIKE_INTERFACE.SERIAL; }
695
742
  static setSerialPort(spClass) {
696
743
  __SerialPort = spClass;
697
744
  }
698
745
  static setNetImpl(netClass) { }
699
746
  static getSupportedInterfaces() {
700
- return [constants_js_1.BIKE_INTERFACE.SERIAL];
747
+ return [constants_1.BIKE_INTERFACE.SERIAL];
701
748
  }
702
749
  }
703
750
  exports.Daum8iSerial = Daum8iSerial;