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,894 +1,904 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.Daum8iSerial = exports.Daum8iTcp = void 0;
16
- const constants_1 = require("../constants");
17
- const tcpserial_1 = __importDefault(require("./tcpserial"));
18
- const utils_1 = require("./utils");
19
- const gd_eventlog_1 = require("gd-eventlog");
20
- const nop = () => { };
21
- const MAX_RETRIES = 5;
22
- const DEFAULT_TIMEOUT = 10000;
23
- const DEFAULT_SEND_DELAY = 1000;
24
- const TIMEOUT_START = 15000;
25
- const OPEN_TIMEOUT = 1000;
26
- const DAUM_PREMIUM_DEFAULT_PORT = 51955;
27
- const DAUM_PREMIUM_DEFAULT_HOST = '127.0.0.1';
28
- const MAX_DATA_BLOCK_SIZE = 512;
29
- const DS_BITS_OFF = 0;
30
- const DS_BITS_ENDLESS_RACE = 2;
31
- var __SerialPort = undefined;
32
- var net = undefined;
33
- const DEBUG_LOGGER = {
34
- log: (e, ...args) => console.log(e, ...args),
35
- logEvent: (event) => console.log(JSON.stringify(event))
36
- };
37
- class Daum8i {
38
- constructor(props) {
39
- this.props = props || {};
40
- this.logger = process.env.DEBUG ? DEBUG_LOGGER : new gd_eventlog_1.EventLogger('DaumPremium');
41
- this.logger.logEvent({ message: 'new DaumPremium object', props: this.props });
42
- if (this.props.interface === 'tcpip') {
43
- const port = this.props.port || DAUM_PREMIUM_DEFAULT_PORT;
44
- const host = this.props.host || DAUM_PREMIUM_DEFAULT_HOST;
45
- this.portName = `${host}:51955`;
46
- this.tcpip = true;
47
- this.serial = false;
48
- this.tcpipConnection = { host, port };
49
- }
50
- else {
51
- this.portName = this.props.port || process.env.COM_PORT;
52
- this.tcpip = false;
53
- this.serial = true;
54
- this.port = this.portName;
55
- }
56
- this.settings = this.props.settings || {};
57
- this.settings.logger = this.logger;
58
- this.sendRetryDelay = DEFAULT_SEND_DELAY;
59
- this.sp = undefined;
60
- this.connected = false;
61
- this.blocked = false;
62
- this.state = {
63
- ack: { wait: false, startWait: undefined },
64
- commandsInQueue: {},
65
- };
66
- this.bikeData = {
67
- userWeight: 75,
68
- bikeWeight: 10,
69
- maxPower: 800
70
- };
71
- }
72
- static getClassName() {
73
- return "Daum8i";
74
- }
75
- getType() {
76
- return "Daum8i";
77
- }
78
- static setSerialPort(spClass) {
79
- __SerialPort = spClass;
80
- }
81
- static setNetImpl(netClass) {
82
- net = netClass;
83
- }
84
- static getSupportedInterfaces() {
85
- return [constants_1.BIKE_INTERFACE.SERIAL, constants_1.BIKE_INTERFACE.TCPIP];
86
- }
87
- getPort() {
88
- return this.portName;
89
- }
90
- isConnected() {
91
- return this.connected;
92
- }
93
- setUser(user, callback) {
94
- this.logger.logEvent({ message: "setUser()", user, port: this.portName });
95
- this.settings.user = user || {};
96
- var cb = callback || nop;
97
- cb(200, user);
98
- }
99
- getUserWeight() {
100
- if (!this.settings || !this.settings.user || !this.settings.user.weight)
101
- return 75;
102
- return this.settings.user.weight;
103
- }
104
- getBikeWeight() {
105
- return 10;
106
- }
107
- unblock() {
108
- this.blocked = false;
109
- }
110
- connect() {
111
- this.logger.logEvent({ message: "connect()", sp: (this.sp !== undefined), connected: this.connected, blocked: this.blocked, port: this.portName, settings: this.settings });
112
- if (this.connected || this.blocked) {
113
- return;
114
- }
115
- this.state.busy = true;
116
- this.state.commandsInQueue = {};
117
- try {
118
- if (this.sp !== undefined) {
119
- try {
120
- this.sp.removeAllListeners();
121
- this.sp.close();
122
- }
123
- catch (err) {
124
- }
125
- this.sp = undefined;
126
- }
127
- if (this.sp === undefined) {
128
- if (this.tcpip) {
129
- const { host, port } = this.tcpipConnection;
130
- const { logger } = this.props;
131
- this.logger.logEvent({ message: "creating TCPSocketPort", host, port });
132
- this.sp = new tcpserial_1.default({ host, port, net, timeout: OPEN_TIMEOUT, logger });
133
- }
134
- else {
135
- const settings = this.settings.port || {};
136
- settings.autoOpen = false;
137
- this.logger.logEvent({ message: "creating SerialPort", port: this.port, settings });
138
- this.sp = new __SerialPort(this.port, settings);
139
- }
140
- this.sp.on('open', this.onPortOpen.bind(this));
141
- this.sp.on('close', this.onPortClose.bind(this));
142
- this.sp.on('error', (error) => { this.onPortError(error); });
143
- this.sp.on('data', (data) => { this.onData(data); });
144
- }
145
- const start = Date.now();
146
- this.state.connecting = true;
147
- this.state.opening = { start, timeout: start + this.getTimeoutValue() };
148
- this.logger.logEvent({ message: "opening port ..." });
149
- this.sp.open();
150
- }
151
- catch (err) {
152
- this.logger.logEvent({ message: "scan:error:", error: err.message, stack: err.stack });
153
- this.state.busy = false;
154
- }
155
- }
156
- reconnect() {
157
- return __awaiter(this, void 0, void 0, function* () {
158
- yield this.saveClose();
159
- yield this.saveConnect();
160
- });
161
- }
162
- saveConnect() {
163
- return new Promise((resolve, reject) => {
164
- if (this.isConnected()) {
165
- this.state.connecting = false;
166
- return resolve(true);
167
- }
168
- this.connect();
169
- const tTimeout = Date.now() + TIMEOUT_START;
170
- const iv = setInterval(() => {
171
- if (this.state.error !== undefined) {
172
- clearInterval(iv);
173
- this.forceClose();
174
- reject(this.state.error);
175
- this.state = { opened: false, closed: true, busy: false };
176
- }
177
- else if (this.isConnected()) {
178
- this.state.connecting = false;
179
- resolve(true);
180
- clearInterval(iv);
181
- }
182
- else {
183
- if (Date.now() > tTimeout) {
184
- this.state.connecting = false;
185
- this.forceClose();
186
- clearInterval(iv);
187
- reject(new Error('timeout'));
188
- }
189
- }
190
- }, 100);
191
- });
192
- }
193
- onPortOpen() {
194
- this.error = undefined;
195
- this.connected = true;
196
- this.state.opening = undefined;
197
- this.state.opened = true;
198
- this.state.busy = false;
199
- this.logger.logEvent({ message: "port opened", port: this.portName });
200
- }
201
- onPortClose() {
202
- this.logger.logEvent({ message: "port closed", port: this.portName });
203
- this.error = undefined;
204
- this.connected = false;
205
- if (this.state.opening) {
206
- this.state.opened = false;
207
- this.state.closed = true;
208
- }
209
- else {
210
- this.state = { opened: false, closed: true, busy: false };
211
- }
212
- this.sp.removeAllListeners();
213
- this.sp = undefined;
214
- if (this.queue !== undefined)
215
- this.queue.clear();
216
- }
217
- getLogState() {
218
- let s = undefined;
219
- const { sending, busy, opening, connecting, writeBusy, waitingForStart, waitingForAck, waitingForEnd, retry } = this.state;
220
- if (sending) {
221
- s = {};
222
- s.command = sending.command;
223
- s.payload = sending.payload;
224
- }
225
- return { sending: s, busy, writeBusy, opening, connecting, waitingForStart, waitingForEnd, waitingForAck, retry };
226
- }
227
- onPortError(error) {
228
- this.logger.logEvent({ message: "port error:", port: this.portName, error: error.message, connected: this.connected, state: this.getLogState() });
229
- this.error = error;
230
- if (this.blocked) {
231
- if (!this.state.closed) {
232
- if (this.sp) {
233
- this.sp.removeAllListeners();
234
- this.sp.close();
235
- this.sp = undefined;
236
- }
237
- this.state = { opened: false, closed: true, busy: false };
238
- }
239
- return;
240
- }
241
- if (this.state.closing) {
242
- if (error.message === 'Port is not open') {
243
- this.state = { opened: false, closed: true, busy: false };
244
- return;
245
- }
246
- else {
247
- this.forceClose();
248
- }
249
- }
250
- else if (this.state.opening) {
251
- if (this.state.connecting) {
252
- this.state.error = error;
253
- }
254
- else {
255
- this.onPortOpen();
256
- }
257
- }
258
- else if (this.state.sending) {
259
- this.state.error = error;
260
- this.forceClose(false);
261
- return;
262
- }
263
- this.state.busy = false;
264
- }
265
- errorHandler() {
266
- throw new Error("Error");
267
- }
268
- saveClose(force) {
269
- return new Promise((resolve, reject) => {
270
- if (force)
271
- this.blocked = true;
272
- this.close();
273
- const start = Date.now();
274
- const iv = setInterval(() => {
275
- if (this.state.closed || (Date.now() - start > DEFAULT_TIMEOUT)) {
276
- clearInterval(iv);
277
- resolve(true);
278
- return;
279
- }
280
- }, 50);
281
- });
282
- }
283
- forceClose(updateState = false) {
284
- const sp = this.sp;
285
- if (!this.sp)
286
- return;
287
- this.sp.removeAllListeners();
288
- try {
289
- sp.unpipe();
290
- sp.flush();
291
- }
292
- catch (_a) { }
293
- sp.close();
294
- this.connected = false;
295
- if (updateState)
296
- this.state = { opened: false, closed: true, busy: false };
297
- }
298
- close() {
299
- this.logger.logEvent({ message: 'close request', port: this.portName });
300
- var sp = this.sp;
301
- let connected = this.connected;
302
- try {
303
- if (connected) {
304
- if (sp) {
305
- sp.unpipe();
306
- sp.flush();
307
- sp.close();
308
- }
309
- if (this.queue !== undefined) {
310
- this.queue.clear();
311
- this.queue = undefined;
312
- }
313
- }
314
- else {
315
- if (sp)
316
- sp.close();
317
- }
318
- }
319
- catch (err) {
320
- this.logger.logEvent({ message: 'close: Exception', port: this.portName, error: err.message });
321
- }
322
- this.connected = false;
323
- const start = Date.now();
324
- if (this.state.closing === undefined)
325
- this.state.closing = { start, timeout: start + this.getTimeoutValue(), retry: 0, maxRetries: MAX_RETRIES };
326
- else {
327
- this.state.closing.start = start;
328
- this.state.closing.timeout = start + this.getTimeoutValue();
329
- this.state.retry = this.state.retry + 1;
330
- }
331
- this.state.busy = false;
332
- }
333
- sendTimeout(message) {
334
- this.logger.logEvent({ message: `sendCommand:${message || 'timeout'}`, port: this.portName, cmd: this.cmdCurrent });
335
- delete this.state.commandsInQueue[this.cmdCurrent.command];
336
- if (this.cmdCurrent.callbackErr !== undefined) {
337
- let cb = this.cmdCurrent.callbackErr;
338
- this.state.busy = false;
339
- this.cmdCurrent = undefined;
340
- this.cmdStart = undefined;
341
- cb(408, { message: message || "timeout" });
342
- }
343
- }
344
- checkForResponse() {
345
- const d = Date.now();
346
- const s = this.state.sending;
347
- if (s === undefined)
348
- return false;
349
- const rejectFn = s.reject;
350
- const reject = (err) => {
351
- if (rejectFn && typeof rejectFn === 'function') {
352
- rejectFn(err);
353
- }
354
- };
355
- const error = this.state.error;
356
- if (error !== undefined) {
357
- reject(error);
358
- return false;
359
- }
360
- try {
361
- if (this.state.waitingForACK) {
362
- const timeoutACK = this.state.ack ? this.state.ack.timeout : this.state.sending.timeout;
363
- if (d < timeoutACK)
364
- return true;
365
- reject(new Error('ACK timeout'));
366
- return false;
367
- }
368
- if (d < this.state.sending.timeout)
369
- return true;
370
- reject(new Error('RESP timeout'));
371
- return false;
372
- }
373
- catch (err) {
374
- this.logger.logEvent({ message: 'checkForResponse: Exception', port: this.portName, error: err.message, stack: err.stack });
375
- }
376
- return true;
377
- }
378
- getTimeoutValue(cmd) {
379
- let timeout = DEFAULT_TIMEOUT;
380
- if (this.settings && this.settings.tcpip && this.settings.tcpip.timeout)
381
- timeout = this.settings.tcpip.timeout;
382
- if (this.settings && this.settings.serial && this.settings.serial.timeout)
383
- timeout = this.settings.serial.timeout;
384
- if (cmd !== undefined && cmd.options !== undefined && cmd.options.timeout !== undefined) {
385
- timeout = cmd.options.timeout;
386
- }
387
- return timeout;
388
- }
389
- onData(data) {
390
- let cmd = '';
391
- if (this.state.waitingForEnd) {
392
- cmd = this.state.partialCmd;
393
- }
394
- const bufferData = Buffer.isBuffer(data) ? data : Buffer.from(data, 'latin1');
395
- const s = this.state.sending;
396
- if (s === undefined) {
397
- if (this.state.input === undefined)
398
- this.state.input = bufferData;
399
- return;
400
- }
401
- const { portName, resolve } = this.state.sending;
402
- let incoming;
403
- if (this.state.input !== undefined) {
404
- const arr = [this.state.input, bufferData];
405
- incoming = Buffer.concat(arr);
406
- }
407
- else {
408
- incoming = bufferData;
409
- }
410
- const response = [...incoming];
411
- this.logger.logEvent({ message: 'sendCommand:RECV', data: (0, utils_1.hexstr)(response) });
412
- for (let i = 0; i < incoming.length; i++) {
413
- const getRemaining = () => {
414
- let remaining = '';
415
- const done = i === (incoming.length - 1);
416
- if (!done) {
417
- for (let j = i + 1; j < incoming.length; j++)
418
- remaining += String.fromCharCode(incoming.readUInt8(j));
419
- }
420
- return remaining;
421
- };
422
- const c = incoming.readUInt8(i);
423
- if (c === 0x06) {
424
- this.logger.logEvent({ message: "sendCommand:ACK received:", port: portName });
425
- this.state.waitingForStart = true;
426
- this.state.waitingForACK = false;
427
- const remaining = getRemaining();
428
- if (remaining && remaining !== '')
429
- return this.onData(remaining);
430
- }
431
- else if (c === 0x15) {
432
- this.state.waitingForStart = true;
433
- this.state.waitingForACK = false;
434
- this.logger.logEvent({ message: "sendCommand:NAK received:", port: portName });
435
- const remaining = getRemaining();
436
- if (remaining && remaining !== '')
437
- return this.onData(remaining);
438
- }
439
- else if (c === 0x01) {
440
- this.state.waitingForEnd = true;
441
- }
442
- else if (c === 0x17) {
443
- const remaining = getRemaining();
444
- 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) });
445
- this.state.waitingForEnd = false;
446
- const cmdStr = cmd.substring(0, cmd.length - 2);
447
- const checksumExtracted = cmd.slice(-2);
448
- const checksumCalculated = (0, utils_1.checkSum)((0, utils_1.getAsciiArrayFromStr)(cmdStr), []);
449
- if (checksumExtracted === checksumCalculated) {
450
- this.sendACK();
451
- if (this.state.sending && this.state.sending.responseCheckIv) {
452
- clearInterval(this.state.sending.responseCheckIv);
453
- }
454
- this.state = {
455
- sending: undefined,
456
- busy: false,
457
- writeBusy: false,
458
- waitingForStart: false,
459
- waitingForEnd: false,
460
- waitingForACK: false,
461
- };
462
- const payload = cmd.substring(3, cmd.length - 2);
463
- resolve(payload);
464
- }
465
- else {
466
- this.sendNAK();
467
- }
468
- cmd = '';
469
- if (remaining)
470
- return this.onData(remaining);
471
- }
472
- else {
473
- if (this.state.waitingForEnd)
474
- cmd += String.fromCharCode(c);
475
- }
476
- }
477
- if (this.state.waitingForEnd) {
478
- this.state.partialCmd = cmd;
479
- }
480
- }
481
- sendDaum8iCommand(command, queryType, payload) {
482
- const tsRequest = Date.now();
483
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
484
- if (this.blocked)
485
- return reject(new Error('blocked'));
486
- if (!this.state.busy) {
487
- this.state.busy = true;
488
- }
489
- else {
490
- const message = (0, utils_1.buildMessage)(command, payload);
491
- this.logger.logEvent({ message: 'sendCommand:waiting', port: this.portName, cmd: command, hex: (0, utils_1.hexstr)(message) });
492
- const busyWait = () => {
493
- return new Promise((done) => {
494
- let start = Date.now();
495
- let timeout = start + 5000;
496
- const iv = setInterval(() => {
497
- if (this.state.busy) {
498
- if (Date.now() > timeout) {
499
- clearInterval(iv);
500
- done(false);
501
- }
502
- }
503
- else {
504
- clearInterval(iv);
505
- done(true);
506
- }
507
- }, 10);
508
- });
509
- };
510
- const res = yield busyWait();
511
- if (!res) {
512
- this.logger.logEvent({ message: 'sendCommand:busy timeout', port: this.portName, cmd: command, hex: (0, utils_1.hexstr)(message), duration: Date.now() - tsRequest });
513
- return reject(new Error('BUSY timeout'));
514
- }
515
- this.state.busy = true;
516
- }
517
- const writeDone = () => {
518
- this.state.sending = undefined;
519
- this.state.writeBusy = false;
520
- this.state.busy = false;
521
- this.state.sending = undefined;
522
- this.state.waitingForStart = false;
523
- this.state.waitingForEnd = false;
524
- this.state.waitingForACK = false;
525
- };
526
- const port = this.sp;
527
- const portName = this.portName;
528
- this.state.received = [];
529
- try {
530
- const message = (0, utils_1.buildMessage)(command, payload);
531
- const start = Date.now();
532
- const timeout = start + this.getTimeoutValue();
533
- this.logger.logEvent({ message: "sendCommand:sending:", port: this.portName, cmd: command, hex: (0, utils_1.hexstr)(message) });
534
- this.state.writeBusy = true;
535
- if (!this.connected || port === undefined) {
536
- this.logger.logEvent({ message: "sendCommand:error: not connected", port: this.portName });
537
- writeDone();
538
- return reject(new Error('not connected'));
539
- }
540
- port.write(message);
541
- this.state.waitingForACK = true;
542
- this.state.writeBusy = false;
543
- this.state.retry = 0;
544
- this.state.ack = { start, timeout };
545
- this.state.sending = { command, payload, start, timeout, port, portName, tsRequest, resolve, reject };
546
- const iv = this.state.sending.responseCheckIv = setInterval(() => {
547
- const stillWaiting = this.checkForResponse();
548
- if (!stillWaiting) {
549
- clearInterval(iv);
550
- writeDone();
551
- }
552
- }, 10);
553
- }
554
- catch (err) {
555
- this.logger.logEvent({ message: "sendCommand:error:", port: portName, error: err.message, stack: err.stack });
556
- writeDone();
557
- reject(err);
558
- }
559
- }));
560
- }
561
- sendACK() {
562
- const port = this.portName;
563
- this.state.writeBusy = true;
564
- try {
565
- this.sp.write([0x06]);
566
- }
567
- catch (err) { }
568
- this.state.writeBusy = false;
569
- this.logger.logEvent({ message: "sendCommand:sending ACK", port, queue: this.state.commandsInQueue });
570
- }
571
- sendNAK() {
572
- const port = this.portName;
573
- try {
574
- this.sp.write([0x15]);
575
- }
576
- catch (err) { }
577
- this.logger.logEvent({ message: "sendCommand:sending NAK", port });
578
- }
579
- sendReservedDaum8iCommand(command, cmdType, data) {
580
- let buffer;
581
- if (data !== undefined && data.length > 0) {
582
- buffer = Buffer.alloc(data.length + 4);
583
- buffer.writeInt16LE(command, 0);
584
- buffer.writeUInt16LE(data.length, 2);
585
- data.copy(buffer, 4);
586
- }
587
- else {
588
- buffer = Buffer.alloc(4);
589
- buffer.writeInt16LE(command, 0);
590
- buffer.writeUInt16LE(0, 2);
591
- }
592
- const cmdData = Uint8Array.from(buffer);
593
- return this.sendDaum8iCommand('M70', cmdType, (0, utils_1.bin2esc)(cmdData))
594
- .then((res) => {
595
- const resData = Uint8Array.from(res, x => x.charCodeAt(0));
596
- const cmd = (0, utils_1.esc2bin)(resData);
597
- return cmd;
598
- });
599
- }
600
- getProtocolVersion() {
601
- return this.sendDaum8iCommand('V00', 'AF', [])
602
- .then((data) => {
603
- const version = data.substring(0, 1) + '.' + data.substring(1);
604
- return (version);
605
- });
606
- }
607
- getDashboardVersion() {
608
- return this.sendDaum8iCommand('V70', 'AF', []);
609
- }
610
- getDeviceType() {
611
- return this.sendDaum8iCommand('Y00', 'AF', [])
612
- .then((str) => {
613
- let deviceType;
614
- if (str === '0')
615
- deviceType = 'run';
616
- else if (str === '2')
617
- deviceType = 'bike';
618
- else if (str === '7')
619
- deviceType = 'lyps';
620
- else
621
- throw (new Error(`unknown device type ${typeof str === 'string' ? (0, utils_1.ascii)(str.charAt(0)) : str}`));
622
- return deviceType;
623
- });
624
- }
625
- getActualBikeType() {
626
- return this.sendDaum8iCommand('M72', 'AF', [])
627
- .then((str) => {
628
- let deviceType;
629
- if (str === '0')
630
- deviceType = constants_1.ACTUAL_BIKE_TYPE.ALLROUND;
631
- else if (str === '1')
632
- deviceType = constants_1.ACTUAL_BIKE_TYPE.RACE;
633
- else if (str === '2')
634
- deviceType = constants_1.ACTUAL_BIKE_TYPE.MOUNTAIN;
635
- else {
636
- throw (new Error(`unknown actual device type ${typeof str === 'string' ? (0, utils_1.ascii)(str.charAt(0)) : str}`));
637
- }
638
- this.state.actualBikeType = deviceType;
639
- return deviceType;
640
- });
641
- }
642
- setActualBikeType(actualBikeType) {
643
- let bikeType;
644
- switch (actualBikeType) {
645
- case constants_1.ACTUAL_BIKE_TYPE.ALLROUND:
646
- bikeType = '0';
647
- break;
648
- case constants_1.ACTUAL_BIKE_TYPE.RACE:
649
- bikeType = '1';
650
- break;
651
- case constants_1.ACTUAL_BIKE_TYPE.TRIATHLON:
652
- bikeType = '1';
653
- break;
654
- case constants_1.ACTUAL_BIKE_TYPE.MOUNTAIN:
655
- bikeType = '2';
656
- break;
657
- default:
658
- bikeType = undefined;
659
- }
660
- return this.sendDaum8iCommand(`M72${bikeType}`, 'BF', [])
661
- .then((str) => {
662
- let deviceType;
663
- if (str === '0')
664
- deviceType = constants_1.ACTUAL_BIKE_TYPE.ALLROUND;
665
- else if (str === '1')
666
- deviceType = constants_1.ACTUAL_BIKE_TYPE.RACE;
667
- else if (str === '2')
668
- deviceType = constants_1.ACTUAL_BIKE_TYPE.MOUNTAIN;
669
- else
670
- throw (new Error('unknown actual device type'));
671
- this.state.actualBikeType = deviceType;
672
- return deviceType;
673
- });
674
- }
675
- getTrainingData() {
676
- return this.sendDaum8iCommand('X70', 'AF', [])
677
- .then((data) => {
678
- const td = (0, utils_1.parseTrainingData)(data);
679
- return td;
680
- });
681
- }
682
- setLoadControl(enabled) {
683
- const val = enabled ? (0, utils_1.ascii)('1') : (0, utils_1.ascii)('0');
684
- return this.sendDaum8iCommand('S20', 'BF', [val])
685
- .then((data) => {
686
- const res = data === '1';
687
- return res;
688
- });
689
- }
690
- getLoadControl() {
691
- return this.sendDaum8iCommand('S20', 'AF', [])
692
- .then((data) => {
693
- const res = data === '1';
694
- return res;
695
- });
696
- }
697
- setSlope(slope) {
698
- this.logger.logEvent({ message: 'setSlope not implemted' });
699
- return;
700
- }
701
- setPower(power) {
702
- const powerStr = Number.parseFloat(power).toFixed(2);
703
- return this.sendDaum8iCommand(`S23${powerStr}`, 'BF', [])
704
- .then((str) => {
705
- return parseInt(str);
706
- });
707
- }
708
- getPower(power) {
709
- return this.sendDaum8iCommand('S23', 'AF', [])
710
- .then((str) => {
711
- return parseInt(str);
712
- });
713
- }
714
- setPerson(person) {
715
- const { sex, age, length, weight } = person;
716
- this.logger.logEvent({ message: 'setPerson() request', sex, age, length, weight });
717
- return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PERSON_SET, 'BF', (0, utils_1.getPersonData)(person))
718
- .then((res) => {
719
- const buffer = Buffer.from(res);
720
- const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PERSON_SET;
721
- this.logger.logEvent({ message: 'setPerson() response', success, buffer });
722
- if (!success)
723
- throw new Error('Illegal Response');
724
- return true;
725
- });
726
- }
727
- programUploadInit() {
728
- this.logger.logEvent({ message: 'programUploadInit() request' });
729
- return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_BEGIN, 'BF')
730
- .then((res) => {
731
- const buffer = Buffer.from(res);
732
- const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_BEGIN;
733
- this.logger.logEvent({ message: 'programUploadInit() response', success, buffer });
734
- if (!success)
735
- throw new Error('Illegal Response');
736
- return true;
737
- });
738
- }
739
- programUploadStart(bikeType, route) {
740
- const payload = Buffer.alloc(40);
741
- const epp = route ? (0, utils_1.routeToEpp)(route) : undefined;
742
- const eppLength = epp ? epp.length : 0;
743
- const bikeTypeVal = (0, utils_1.getBikeType)(bikeType);
744
- const wBits = route.lapMode ? DS_BITS_ENDLESS_RACE : DS_BITS_OFF;
745
- payload.writeInt32LE(0, 0);
746
- payload.writeInt8(bikeTypeVal, 4);
747
- payload.writeInt8(0, 5);
748
- payload.writeInt16LE(0, 6);
749
- payload.writeInt32LE(0, 8);
750
- payload.writeInt32LE(0, 12);
751
- payload.writeFloatLE(0, 16);
752
- payload.writeFloatLE(0, 20);
753
- payload.writeInt16LE(0, 24);
754
- payload.writeInt16LE(0, 26);
755
- payload.writeInt16LE(0, 28);
756
- payload.writeInt16LE(wBits, 30);
757
- payload.writeInt32LE(7, 32);
758
- payload.writeInt32LE(eppLength, 36);
759
- this.logger.logEvent({ message: 'programUploadStart() request', bikeType, length: eppLength });
760
- return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_NEW_PROGRAM, 'BF', payload)
761
- .then((res) => {
762
- const buffer = Buffer.from(res);
763
- if (buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_NEW_PROGRAM) {
764
- this.logger.logEvent({ message: 'programUploadStart() response', success: true });
765
- return epp;
766
- }
767
- this.logger.logEvent({ message: 'programUploadStart() response', success: false });
768
- throw new Error('Illegal Response');
769
- });
770
- }
771
- programUploadSendBlock(epp, offset) {
772
- const remaining = epp.length - offset;
773
- if (remaining <= 0)
774
- return Promise.resolve(true);
775
- const size = remaining > MAX_DATA_BLOCK_SIZE ? MAX_DATA_BLOCK_SIZE : remaining;
776
- const payload = Buffer.alloc(size + 8);
777
- payload.writeInt32LE(size, 0);
778
- payload.writeInt32LE(offset, 4);
779
- const chunk = Buffer.from(epp.slice(offset, offset + size));
780
- chunk.copy(payload, 8);
781
- this.logger.logEvent({ message: 'programUploadSendBlock() request', offset, size });
782
- return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_CONTINUE_PROGRAM, 'BF', payload)
783
- .then((res) => {
784
- const buffer = Buffer.from(res);
785
- let success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_CONTINUE_PROGRAM;
786
- success = success && (buffer.readInt16LE(2) === 1);
787
- success = success && (buffer.readInt8(4) === 1);
788
- this.logger.logEvent({ message: 'programUploadSendBlock() response' });
789
- if (!success)
790
- throw new Error('Illegal Response');
791
- return true;
792
- ;
793
- });
794
- }
795
- programUploadDone() {
796
- this.logger.logEvent({ message: 'programUploadDone() request' });
797
- return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_END, 'BF')
798
- .then((res) => {
799
- const buffer = Buffer.from(res);
800
- const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_END;
801
- this.logger.logEvent({ message: 'programUploadDone() response', success });
802
- if (!success)
803
- throw new Error('Illegal Response');
804
- return true;
805
- ;
806
- });
807
- }
808
- programUpload(bikeType, route, onStatusUpdate) {
809
- return __awaiter(this, void 0, void 0, function* () {
810
- try {
811
- yield this.programUploadInit();
812
- const epp = yield this.programUploadStart(bikeType, route);
813
- if (epp) {
814
- let success = true;
815
- let done = false;
816
- let offset = 0;
817
- if (onStatusUpdate)
818
- onStatusUpdate(0, epp.length);
819
- while (success && !done) {
820
- success = yield this.programUploadSendBlock(epp, offset);
821
- offset += MAX_DATA_BLOCK_SIZE;
822
- done = offset >= epp.length;
823
- if (onStatusUpdate)
824
- onStatusUpdate(done ? epp.length : offset, epp.length);
825
- }
826
- if (done) {
827
- return yield this.programUploadDone();
828
- }
829
- }
830
- else {
831
- return yield this.programUploadDone();
832
- }
833
- }
834
- catch (err) {
835
- console.log('~~~ err', err);
836
- }
837
- return false;
838
- });
839
- }
840
- startProgram(programId = 1) {
841
- const payload = Buffer.alloc(2);
842
- payload.writeInt16LE(programId, 0);
843
- this.logger.logEvent({ message: 'startProgram() request', programId });
844
- return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_START, 'BF', payload)
845
- .then((res) => {
846
- const buffer = Buffer.from(res);
847
- const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_START;
848
- this.logger.logEvent({ message: 'startProgram() request', programId, success });
849
- if (!success)
850
- throw new Error('Illegal Response');
851
- return true;
852
- ;
853
- });
854
- }
855
- setGear(gear) {
856
- return this.sendDaum8iCommand('M71', 'BF', `${gear}`)
857
- .then((str) => {
858
- const gearVal = parseInt(str);
859
- return gearVal > 0 ? gearVal - 1 : undefined;
860
- });
861
- }
862
- getGear() {
863
- return this.sendDaum8iCommand('M71', 'AF', '')
864
- .then((str) => {
865
- return parseInt(str);
866
- });
867
- }
868
- }
869
- class Daum8iTcp extends Daum8i {
870
- static getClassName() { return "Daum8i"; }
871
- getType() { return "Daum8iTcp"; }
872
- static setSerialPort(spClass) { }
873
- getInterface() { return constants_1.BIKE_INTERFACE.TCPIP; }
874
- static setNetImpl(netClass) {
875
- net = netClass;
876
- }
877
- static getSupportedInterfaces() {
878
- return [constants_1.BIKE_INTERFACE.TCPIP];
879
- }
880
- }
881
- exports.Daum8iTcp = Daum8iTcp;
882
- class Daum8iSerial extends Daum8i {
883
- static getClassName() { return "Daum8i"; }
884
- getType() { return "Daum8iSerial"; }
885
- getInterface() { return constants_1.BIKE_INTERFACE.SERIAL; }
886
- static setSerialPort(spClass) {
887
- __SerialPort = spClass;
888
- }
889
- static setNetImpl(netClass) { }
890
- static getSupportedInterfaces() {
891
- return [constants_1.BIKE_INTERFACE.SERIAL];
892
- }
893
- }
894
- exports.Daum8iSerial = Daum8iSerial;
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.Daum8iSerial = exports.Daum8iTcp = void 0;
16
+ const constants_1 = require("../constants");
17
+ const tcpserial_1 = __importDefault(require("./tcpserial"));
18
+ const utils_1 = require("./utils");
19
+ const gd_eventlog_1 = require("gd-eventlog");
20
+ const nop = () => { };
21
+ const MAX_RETRIES = 5;
22
+ const DEFAULT_TIMEOUT = 10000;
23
+ const DEFAULT_SEND_DELAY = 1000;
24
+ const TIMEOUT_START = 15000;
25
+ const OPEN_TIMEOUT = 1000;
26
+ const DAUM_PREMIUM_DEFAULT_PORT = 51955;
27
+ const DAUM_PREMIUM_DEFAULT_HOST = '127.0.0.1';
28
+ const MAX_DATA_BLOCK_SIZE = 512;
29
+ const DS_BITS_OFF = 0;
30
+ const DS_BITS_ENDLESS_RACE = 2;
31
+ var __SerialPort = undefined;
32
+ var net = undefined;
33
+ const DEBUG_LOGGER = {
34
+ log: (e, ...args) => console.log(e, ...args),
35
+ logEvent: (event) => console.log(JSON.stringify(event))
36
+ };
37
+ class Daum8i {
38
+ constructor(props) {
39
+ this.props = props || {};
40
+ this.logger = process.env.DEBUG ? DEBUG_LOGGER : new gd_eventlog_1.EventLogger('DaumPremium');
41
+ if (this.props.interface === 'tcpip') {
42
+ const port = this.props.port || DAUM_PREMIUM_DEFAULT_PORT;
43
+ const host = this.props.host || DAUM_PREMIUM_DEFAULT_HOST;
44
+ this.portName = `${host}:51955`;
45
+ this.tcpip = true;
46
+ this.serial = false;
47
+ this.tcpipConnection = { host, port };
48
+ }
49
+ else {
50
+ this.portName = this.props.port || process.env.COM_PORT;
51
+ this.tcpip = false;
52
+ this.serial = true;
53
+ this.port = this.portName;
54
+ }
55
+ this.settings = this.props.settings || {};
56
+ this.settings.logger = this.logger;
57
+ this.isLoggingPaused = false;
58
+ this.sendRetryDelay = DEFAULT_SEND_DELAY;
59
+ this.sp = undefined;
60
+ this.connected = false;
61
+ this.blocked = false;
62
+ this.state = {
63
+ ack: { wait: false, startWait: undefined },
64
+ commandsInQueue: {},
65
+ };
66
+ this.bikeData = {
67
+ userWeight: 75,
68
+ bikeWeight: 10,
69
+ maxPower: 800
70
+ };
71
+ }
72
+ static getClassName() {
73
+ return "Daum8i";
74
+ }
75
+ getType() {
76
+ return "Daum8i";
77
+ }
78
+ static setSerialPort(spClass) {
79
+ __SerialPort = spClass;
80
+ }
81
+ static setNetImpl(netClass) {
82
+ net = netClass;
83
+ }
84
+ static getSupportedInterfaces() {
85
+ return [constants_1.BIKE_INTERFACE.SERIAL, constants_1.BIKE_INTERFACE.TCPIP];
86
+ }
87
+ getPort() {
88
+ return this.portName;
89
+ }
90
+ isConnected() {
91
+ return this.connected;
92
+ }
93
+ pauseLogging() {
94
+ this.isLoggingPaused = true;
95
+ }
96
+ resumLogging() {
97
+ this.isLoggingPaused = false;
98
+ }
99
+ logEvent(e) {
100
+ if (!this.isLoggingPaused)
101
+ this.logger.logEvent(e);
102
+ }
103
+ setUser(user, callback) {
104
+ this.logEvent({ message: "setUser()", user, port: this.portName });
105
+ this.settings.user = user || {};
106
+ var cb = callback || nop;
107
+ cb(200, user);
108
+ }
109
+ getUserWeight() {
110
+ if (!this.settings || !this.settings.user || !this.settings.user.weight)
111
+ return 75;
112
+ return this.settings.user.weight;
113
+ }
114
+ getBikeWeight() {
115
+ return 10;
116
+ }
117
+ unblock() {
118
+ this.blocked = false;
119
+ }
120
+ connect() {
121
+ this.logEvent({ message: "connect()", sp: (this.sp !== undefined), connected: this.connected, blocked: this.blocked, port: this.portName, settings: this.settings });
122
+ if (this.connected || this.blocked) {
123
+ return;
124
+ }
125
+ this.state.busy = true;
126
+ this.state.commandsInQueue = {};
127
+ try {
128
+ if (this.sp !== undefined) {
129
+ try {
130
+ this.sp.removeAllListeners();
131
+ this.sp.close();
132
+ }
133
+ catch (err) {
134
+ }
135
+ this.sp = undefined;
136
+ }
137
+ if (this.sp === undefined) {
138
+ if (this.tcpip) {
139
+ const { host, port } = this.tcpipConnection;
140
+ const { logger } = this.props;
141
+ this.logEvent({ message: "creating TCPSocketPort", host, port });
142
+ this.sp = new tcpserial_1.default({ host, port, net, timeout: OPEN_TIMEOUT, logger });
143
+ }
144
+ else {
145
+ const settings = this.settings.port || {};
146
+ settings.autoOpen = false;
147
+ this.logEvent({ message: "creating SerialPort", port: this.port, settings });
148
+ this.sp = new __SerialPort(this.port, settings);
149
+ }
150
+ this.sp.on('open', this.onPortOpen.bind(this));
151
+ this.sp.on('close', this.onPortClose.bind(this));
152
+ this.sp.on('error', (error) => { this.onPortError(error); });
153
+ this.sp.on('data', (data) => { this.onData(data); });
154
+ }
155
+ const start = Date.now();
156
+ this.state.connecting = true;
157
+ this.state.opening = { start, timeout: start + this.getTimeoutValue() };
158
+ this.logEvent({ message: "opening port ..." });
159
+ this.sp.open();
160
+ }
161
+ catch (err) {
162
+ this.logEvent({ message: "scan:error:", error: err.message, stack: err.stack });
163
+ this.state.busy = false;
164
+ }
165
+ }
166
+ reconnect() {
167
+ return __awaiter(this, void 0, void 0, function* () {
168
+ yield this.saveClose();
169
+ yield this.saveConnect();
170
+ });
171
+ }
172
+ saveConnect() {
173
+ return new Promise((resolve, reject) => {
174
+ if (this.isConnected()) {
175
+ this.state.connecting = false;
176
+ return resolve(true);
177
+ }
178
+ this.connect();
179
+ const tTimeout = Date.now() + TIMEOUT_START;
180
+ const iv = setInterval(() => {
181
+ if (this.state.error !== undefined) {
182
+ clearInterval(iv);
183
+ this.forceClose();
184
+ reject(this.state.error);
185
+ this.state = { opened: false, closed: true, busy: false };
186
+ }
187
+ else if (this.isConnected()) {
188
+ this.state.connecting = false;
189
+ resolve(true);
190
+ clearInterval(iv);
191
+ }
192
+ else {
193
+ if (Date.now() > tTimeout) {
194
+ this.state.connecting = false;
195
+ this.forceClose();
196
+ clearInterval(iv);
197
+ reject(new Error('timeout'));
198
+ }
199
+ }
200
+ }, 100);
201
+ });
202
+ }
203
+ onPortOpen() {
204
+ this.error = undefined;
205
+ this.connected = true;
206
+ this.state.opening = undefined;
207
+ this.state.opened = true;
208
+ this.state.busy = false;
209
+ this.logEvent({ message: "port opened", port: this.portName });
210
+ }
211
+ onPortClose() {
212
+ this.logEvent({ message: "port closed", port: this.portName });
213
+ this.error = undefined;
214
+ this.connected = false;
215
+ if (this.state.opening) {
216
+ this.state.opened = false;
217
+ this.state.closed = true;
218
+ }
219
+ else {
220
+ this.state = { opened: false, closed: true, busy: false };
221
+ }
222
+ this.sp.removeAllListeners();
223
+ this.sp = undefined;
224
+ if (this.queue !== undefined)
225
+ this.queue.clear();
226
+ }
227
+ getLogState() {
228
+ let s = undefined;
229
+ const { sending, busy, opening, connecting, writeBusy, waitingForStart, waitingForAck, waitingForEnd, retry } = this.state;
230
+ if (sending) {
231
+ s = {};
232
+ s.command = sending.command;
233
+ s.payload = sending.payload;
234
+ }
235
+ return { sending: s, busy, writeBusy, opening, connecting, waitingForStart, waitingForEnd, waitingForAck, retry };
236
+ }
237
+ onPortError(error) {
238
+ this.logEvent({ message: "port error:", port: this.portName, error: error.message, connected: this.connected, state: this.getLogState() });
239
+ this.error = error;
240
+ if (this.blocked) {
241
+ if (!this.state.closed) {
242
+ if (this.sp) {
243
+ this.sp.removeAllListeners();
244
+ this.sp.close();
245
+ this.sp = undefined;
246
+ }
247
+ this.state = { opened: false, closed: true, busy: false };
248
+ }
249
+ return;
250
+ }
251
+ if (this.state.closing) {
252
+ if (error.message === 'Port is not open') {
253
+ this.state = { opened: false, closed: true, busy: false };
254
+ return;
255
+ }
256
+ else {
257
+ this.forceClose();
258
+ }
259
+ }
260
+ else if (this.state.opening) {
261
+ if (this.state.connecting) {
262
+ this.state.error = error;
263
+ }
264
+ else {
265
+ this.onPortOpen();
266
+ }
267
+ }
268
+ else if (this.state.sending) {
269
+ this.state.error = error;
270
+ this.forceClose(false);
271
+ return;
272
+ }
273
+ this.state.busy = false;
274
+ }
275
+ errorHandler() {
276
+ throw new Error("Error");
277
+ }
278
+ saveClose(force) {
279
+ return new Promise((resolve, reject) => {
280
+ if (force)
281
+ this.blocked = true;
282
+ this.close();
283
+ const start = Date.now();
284
+ const iv = setInterval(() => {
285
+ if (this.state.closed || (Date.now() - start > DEFAULT_TIMEOUT)) {
286
+ clearInterval(iv);
287
+ resolve(true);
288
+ return;
289
+ }
290
+ }, 50);
291
+ });
292
+ }
293
+ forceClose(updateState = false) {
294
+ const sp = this.sp;
295
+ if (!this.sp)
296
+ return;
297
+ this.sp.removeAllListeners();
298
+ try {
299
+ sp.unpipe();
300
+ sp.flush();
301
+ }
302
+ catch (_a) { }
303
+ sp.close();
304
+ this.connected = false;
305
+ if (updateState)
306
+ this.state = { opened: false, closed: true, busy: false };
307
+ }
308
+ close() {
309
+ this.logEvent({ message: 'close request', port: this.portName });
310
+ var sp = this.sp;
311
+ let connected = this.connected;
312
+ try {
313
+ if (connected) {
314
+ if (sp) {
315
+ sp.unpipe();
316
+ sp.flush();
317
+ sp.close();
318
+ }
319
+ if (this.queue !== undefined) {
320
+ this.queue.clear();
321
+ this.queue = undefined;
322
+ }
323
+ }
324
+ else {
325
+ if (sp)
326
+ sp.close();
327
+ }
328
+ }
329
+ catch (err) {
330
+ this.logEvent({ message: 'close: Exception', port: this.portName, error: err.message });
331
+ }
332
+ this.connected = false;
333
+ const start = Date.now();
334
+ if (this.state.closing === undefined)
335
+ this.state.closing = { start, timeout: start + this.getTimeoutValue(), retry: 0, maxRetries: MAX_RETRIES };
336
+ else {
337
+ this.state.closing.start = start;
338
+ this.state.closing.timeout = start + this.getTimeoutValue();
339
+ this.state.retry = this.state.retry + 1;
340
+ }
341
+ this.state.busy = false;
342
+ }
343
+ sendTimeout(message) {
344
+ this.logEvent({ message: `sendCommand:${message || 'timeout'}`, port: this.portName, cmd: this.cmdCurrent });
345
+ delete this.state.commandsInQueue[this.cmdCurrent.command];
346
+ if (this.cmdCurrent.callbackErr !== undefined) {
347
+ let cb = this.cmdCurrent.callbackErr;
348
+ this.state.busy = false;
349
+ this.cmdCurrent = undefined;
350
+ this.cmdStart = undefined;
351
+ cb(408, { message: message || "timeout" });
352
+ }
353
+ }
354
+ checkForResponse() {
355
+ const d = Date.now();
356
+ const s = this.state.sending;
357
+ if (s === undefined)
358
+ return false;
359
+ const rejectFn = s.reject;
360
+ const reject = (err) => {
361
+ if (rejectFn && typeof rejectFn === 'function') {
362
+ rejectFn(err);
363
+ }
364
+ };
365
+ const error = this.state.error;
366
+ if (error !== undefined) {
367
+ reject(error);
368
+ return false;
369
+ }
370
+ try {
371
+ if (this.state.waitingForACK) {
372
+ const timeoutACK = this.state.ack ? this.state.ack.timeout : this.state.sending.timeout;
373
+ if (d < timeoutACK)
374
+ return true;
375
+ reject(new Error('ACK timeout'));
376
+ return false;
377
+ }
378
+ if (d < this.state.sending.timeout)
379
+ return true;
380
+ reject(new Error('RESP timeout'));
381
+ return false;
382
+ }
383
+ catch (err) {
384
+ this.logEvent({ message: 'checkForResponse: Exception', port: this.portName, error: err.message, stack: err.stack });
385
+ }
386
+ return true;
387
+ }
388
+ getTimeoutValue(cmd) {
389
+ let timeout = DEFAULT_TIMEOUT;
390
+ if (this.settings && this.settings.tcpip && this.settings.tcpip.timeout)
391
+ timeout = this.settings.tcpip.timeout;
392
+ if (this.settings && this.settings.serial && this.settings.serial.timeout)
393
+ timeout = this.settings.serial.timeout;
394
+ if (cmd !== undefined && cmd.options !== undefined && cmd.options.timeout !== undefined) {
395
+ timeout = cmd.options.timeout;
396
+ }
397
+ return timeout;
398
+ }
399
+ onData(data) {
400
+ let cmd = '';
401
+ if (this.state.waitingForEnd) {
402
+ cmd = this.state.partialCmd;
403
+ }
404
+ const bufferData = Buffer.isBuffer(data) ? data : Buffer.from(data, 'latin1');
405
+ const s = this.state.sending;
406
+ if (s === undefined) {
407
+ if (this.state.input === undefined)
408
+ this.state.input = bufferData;
409
+ return;
410
+ }
411
+ const { portName, resolve } = this.state.sending;
412
+ let incoming;
413
+ if (this.state.input !== undefined) {
414
+ const arr = [this.state.input, bufferData];
415
+ incoming = Buffer.concat(arr);
416
+ }
417
+ else {
418
+ incoming = bufferData;
419
+ }
420
+ const response = [...incoming];
421
+ this.logEvent({ message: 'sendCommand:RECV', data: (0, utils_1.hexstr)(response) });
422
+ for (let i = 0; i < incoming.length; i++) {
423
+ const getRemaining = () => {
424
+ let remaining = '';
425
+ const done = i === (incoming.length - 1);
426
+ if (!done) {
427
+ for (let j = i + 1; j < incoming.length; j++)
428
+ remaining += String.fromCharCode(incoming.readUInt8(j));
429
+ }
430
+ return remaining;
431
+ };
432
+ const c = incoming.readUInt8(i);
433
+ if (c === 0x06) {
434
+ this.logEvent({ message: "sendCommand:ACK received:", port: portName });
435
+ this.state.waitingForStart = true;
436
+ this.state.waitingForACK = false;
437
+ const remaining = getRemaining();
438
+ if (remaining && remaining !== '')
439
+ return this.onData(remaining);
440
+ }
441
+ else if (c === 0x15) {
442
+ this.state.waitingForStart = true;
443
+ this.state.waitingForACK = false;
444
+ this.logEvent({ message: "sendCommand:NAK received:", port: portName });
445
+ const remaining = getRemaining();
446
+ if (remaining && remaining !== '')
447
+ return this.onData(remaining);
448
+ }
449
+ else if (c === 0x01) {
450
+ this.state.waitingForEnd = true;
451
+ }
452
+ else if (c === 0x17) {
453
+ const remaining = getRemaining();
454
+ this.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) });
455
+ this.state.waitingForEnd = false;
456
+ const cmdStr = cmd.substring(0, cmd.length - 2);
457
+ const checksumExtracted = cmd.slice(-2);
458
+ const checksumCalculated = (0, utils_1.checkSum)((0, utils_1.getAsciiArrayFromStr)(cmdStr), []);
459
+ if (checksumExtracted === checksumCalculated) {
460
+ this.sendACK();
461
+ if (this.state.sending && this.state.sending.responseCheckIv) {
462
+ clearInterval(this.state.sending.responseCheckIv);
463
+ }
464
+ this.state = {
465
+ sending: undefined,
466
+ busy: false,
467
+ writeBusy: false,
468
+ waitingForStart: false,
469
+ waitingForEnd: false,
470
+ waitingForACK: false,
471
+ };
472
+ const payload = cmd.substring(3, cmd.length - 2);
473
+ resolve(payload);
474
+ }
475
+ else {
476
+ this.sendNAK();
477
+ }
478
+ cmd = '';
479
+ if (remaining)
480
+ return this.onData(remaining);
481
+ }
482
+ else {
483
+ if (this.state.waitingForEnd)
484
+ cmd += String.fromCharCode(c);
485
+ }
486
+ }
487
+ if (this.state.waitingForEnd) {
488
+ this.state.partialCmd = cmd;
489
+ }
490
+ }
491
+ sendDaum8iCommand(command, queryType, payload) {
492
+ const tsRequest = Date.now();
493
+ return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
494
+ if (this.blocked)
495
+ return reject(new Error('blocked'));
496
+ if (!this.state.busy) {
497
+ this.state.busy = true;
498
+ }
499
+ else {
500
+ const message = (0, utils_1.buildMessage)(command, payload);
501
+ this.logEvent({ message: 'sendCommand:waiting', port: this.portName, cmd: command, hex: (0, utils_1.hexstr)(message) });
502
+ const busyWait = () => {
503
+ return new Promise((done) => {
504
+ let start = Date.now();
505
+ let timeout = start + 5000;
506
+ const iv = setInterval(() => {
507
+ if (this.state.busy) {
508
+ if (Date.now() > timeout) {
509
+ clearInterval(iv);
510
+ done(false);
511
+ }
512
+ }
513
+ else {
514
+ clearInterval(iv);
515
+ done(true);
516
+ }
517
+ }, 10);
518
+ });
519
+ };
520
+ const res = yield busyWait();
521
+ if (!res) {
522
+ this.logEvent({ message: 'sendCommand:busy timeout', port: this.portName, cmd: command, hex: (0, utils_1.hexstr)(message), duration: Date.now() - tsRequest });
523
+ return reject(new Error('BUSY timeout'));
524
+ }
525
+ this.state.busy = true;
526
+ }
527
+ const writeDone = () => {
528
+ this.state.sending = undefined;
529
+ this.state.writeBusy = false;
530
+ this.state.busy = false;
531
+ this.state.sending = undefined;
532
+ this.state.waitingForStart = false;
533
+ this.state.waitingForEnd = false;
534
+ this.state.waitingForACK = false;
535
+ };
536
+ const port = this.sp;
537
+ const portName = this.portName;
538
+ this.state.received = [];
539
+ try {
540
+ const message = (0, utils_1.buildMessage)(command, payload);
541
+ const start = Date.now();
542
+ const timeout = start + this.getTimeoutValue();
543
+ this.logEvent({ message: "sendCommand:sending:", port: this.portName, cmd: command, hex: (0, utils_1.hexstr)(message) });
544
+ this.state.writeBusy = true;
545
+ if (!this.connected || port === undefined) {
546
+ this.logEvent({ message: "sendCommand:error: not connected", port: this.portName });
547
+ writeDone();
548
+ return reject(new Error('not connected'));
549
+ }
550
+ port.write(message);
551
+ this.state.waitingForACK = true;
552
+ this.state.writeBusy = false;
553
+ this.state.retry = 0;
554
+ this.state.ack = { start, timeout };
555
+ this.state.sending = { command, payload, start, timeout, port, portName, tsRequest, resolve, reject };
556
+ const iv = this.state.sending.responseCheckIv = setInterval(() => {
557
+ const stillWaiting = this.checkForResponse();
558
+ if (!stillWaiting) {
559
+ clearInterval(iv);
560
+ writeDone();
561
+ }
562
+ }, 10);
563
+ }
564
+ catch (err) {
565
+ this.logEvent({ message: "sendCommand:error:", port: portName, error: err.message, stack: err.stack });
566
+ writeDone();
567
+ reject(err);
568
+ }
569
+ }));
570
+ }
571
+ sendACK() {
572
+ const port = this.portName;
573
+ this.state.writeBusy = true;
574
+ try {
575
+ this.sp.write([0x06]);
576
+ }
577
+ catch (err) { }
578
+ this.state.writeBusy = false;
579
+ this.logEvent({ message: "sendCommand:sending ACK", port, queue: this.state.commandsInQueue });
580
+ }
581
+ sendNAK() {
582
+ const port = this.portName;
583
+ try {
584
+ this.sp.write([0x15]);
585
+ }
586
+ catch (err) { }
587
+ this.logEvent({ message: "sendCommand:sending NAK", port });
588
+ }
589
+ sendReservedDaum8iCommand(command, cmdType, data) {
590
+ let buffer;
591
+ if (data !== undefined && data.length > 0) {
592
+ buffer = Buffer.alloc(data.length + 4);
593
+ buffer.writeInt16LE(command, 0);
594
+ buffer.writeUInt16LE(data.length, 2);
595
+ data.copy(buffer, 4);
596
+ }
597
+ else {
598
+ buffer = Buffer.alloc(4);
599
+ buffer.writeInt16LE(command, 0);
600
+ buffer.writeUInt16LE(0, 2);
601
+ }
602
+ const cmdData = Uint8Array.from(buffer);
603
+ return this.sendDaum8iCommand('M70', cmdType, (0, utils_1.bin2esc)(cmdData))
604
+ .then((res) => {
605
+ const resData = Uint8Array.from(res, x => x.charCodeAt(0));
606
+ const cmd = (0, utils_1.esc2bin)(resData);
607
+ return cmd;
608
+ });
609
+ }
610
+ getProtocolVersion() {
611
+ return this.sendDaum8iCommand('V00', 'AF', [])
612
+ .then((data) => {
613
+ const version = data.substring(0, 1) + '.' + data.substring(1);
614
+ return (version);
615
+ });
616
+ }
617
+ getDashboardVersion() {
618
+ return this.sendDaum8iCommand('V70', 'AF', []);
619
+ }
620
+ getDeviceType() {
621
+ return this.sendDaum8iCommand('Y00', 'AF', [])
622
+ .then((str) => {
623
+ let deviceType;
624
+ if (str === '0')
625
+ deviceType = 'run';
626
+ else if (str === '2')
627
+ deviceType = 'bike';
628
+ else if (str === '7')
629
+ deviceType = 'lyps';
630
+ else
631
+ throw (new Error(`unknown device type ${typeof str === 'string' ? (0, utils_1.ascii)(str.charAt(0)) : str}`));
632
+ return deviceType;
633
+ });
634
+ }
635
+ getActualBikeType() {
636
+ return this.sendDaum8iCommand('M72', 'AF', [])
637
+ .then((str) => {
638
+ let deviceType;
639
+ if (str === '0')
640
+ deviceType = constants_1.ACTUAL_BIKE_TYPE.ALLROUND;
641
+ else if (str === '1')
642
+ deviceType = constants_1.ACTUAL_BIKE_TYPE.RACE;
643
+ else if (str === '2')
644
+ deviceType = constants_1.ACTUAL_BIKE_TYPE.MOUNTAIN;
645
+ else {
646
+ throw (new Error(`unknown actual device type ${typeof str === 'string' ? (0, utils_1.ascii)(str.charAt(0)) : str}`));
647
+ }
648
+ this.state.actualBikeType = deviceType;
649
+ return deviceType;
650
+ });
651
+ }
652
+ setActualBikeType(actualBikeType) {
653
+ let bikeType;
654
+ switch (actualBikeType) {
655
+ case constants_1.ACTUAL_BIKE_TYPE.ALLROUND:
656
+ bikeType = '0';
657
+ break;
658
+ case constants_1.ACTUAL_BIKE_TYPE.RACE:
659
+ bikeType = '1';
660
+ break;
661
+ case constants_1.ACTUAL_BIKE_TYPE.TRIATHLON:
662
+ bikeType = '1';
663
+ break;
664
+ case constants_1.ACTUAL_BIKE_TYPE.MOUNTAIN:
665
+ bikeType = '2';
666
+ break;
667
+ default:
668
+ bikeType = undefined;
669
+ }
670
+ return this.sendDaum8iCommand(`M72${bikeType}`, 'BF', [])
671
+ .then((str) => {
672
+ let deviceType;
673
+ if (str === '0')
674
+ deviceType = constants_1.ACTUAL_BIKE_TYPE.ALLROUND;
675
+ else if (str === '1')
676
+ deviceType = constants_1.ACTUAL_BIKE_TYPE.RACE;
677
+ else if (str === '2')
678
+ deviceType = constants_1.ACTUAL_BIKE_TYPE.MOUNTAIN;
679
+ else
680
+ throw (new Error('unknown actual device type'));
681
+ this.state.actualBikeType = deviceType;
682
+ return deviceType;
683
+ });
684
+ }
685
+ getTrainingData() {
686
+ return this.sendDaum8iCommand('X70', 'AF', [])
687
+ .then((data) => {
688
+ const td = (0, utils_1.parseTrainingData)(data);
689
+ return td;
690
+ });
691
+ }
692
+ setLoadControl(enabled) {
693
+ const val = enabled ? (0, utils_1.ascii)('1') : (0, utils_1.ascii)('0');
694
+ return this.sendDaum8iCommand('S20', 'BF', [val])
695
+ .then((data) => {
696
+ const res = data === '1';
697
+ return res;
698
+ });
699
+ }
700
+ getLoadControl() {
701
+ return this.sendDaum8iCommand('S20', 'AF', [])
702
+ .then((data) => {
703
+ const res = data === '1';
704
+ return res;
705
+ });
706
+ }
707
+ setSlope(slope) {
708
+ this.logEvent({ message: 'setSlope not implemted' });
709
+ return;
710
+ }
711
+ setPower(power) {
712
+ const powerStr = Number.parseFloat(power).toFixed(2);
713
+ return this.sendDaum8iCommand(`S23${powerStr}`, 'BF', [])
714
+ .then((str) => {
715
+ return parseInt(str);
716
+ });
717
+ }
718
+ getPower(power) {
719
+ return this.sendDaum8iCommand('S23', 'AF', [])
720
+ .then((str) => {
721
+ return parseInt(str);
722
+ });
723
+ }
724
+ setPerson(person) {
725
+ const { sex, age, length, weight } = person;
726
+ this.logEvent({ message: 'setPerson() request', sex, age, length, weight });
727
+ return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PERSON_SET, 'BF', (0, utils_1.getPersonData)(person))
728
+ .then((res) => {
729
+ const buffer = Buffer.from(res);
730
+ const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PERSON_SET;
731
+ this.logEvent({ message: 'setPerson() response', success, buffer });
732
+ if (!success)
733
+ throw new Error('Illegal Response');
734
+ return true;
735
+ });
736
+ }
737
+ programUploadInit() {
738
+ this.logEvent({ message: 'programUploadInit() request' });
739
+ return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_BEGIN, 'BF')
740
+ .then((res) => {
741
+ const buffer = Buffer.from(res);
742
+ const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_BEGIN;
743
+ this.logEvent({ message: 'programUploadInit() response', success, buffer });
744
+ if (!success)
745
+ throw new Error('Illegal Response');
746
+ return true;
747
+ });
748
+ }
749
+ programUploadStart(bikeType, route) {
750
+ const payload = Buffer.alloc(40);
751
+ const epp = route ? (0, utils_1.routeToEpp)(route) : undefined;
752
+ const eppLength = epp ? epp.length : 0;
753
+ const bikeTypeVal = (0, utils_1.getBikeType)(bikeType);
754
+ const wBits = route.lapMode ? DS_BITS_ENDLESS_RACE : DS_BITS_OFF;
755
+ payload.writeInt32LE(0, 0);
756
+ payload.writeInt8(bikeTypeVal, 4);
757
+ payload.writeInt8(0, 5);
758
+ payload.writeInt16LE(0, 6);
759
+ payload.writeInt32LE(0, 8);
760
+ payload.writeInt32LE(0, 12);
761
+ payload.writeFloatLE(0, 16);
762
+ payload.writeFloatLE(0, 20);
763
+ payload.writeInt16LE(0, 24);
764
+ payload.writeInt16LE(0, 26);
765
+ payload.writeInt16LE(0, 28);
766
+ payload.writeInt16LE(wBits, 30);
767
+ payload.writeInt32LE(7, 32);
768
+ payload.writeInt32LE(eppLength, 36);
769
+ this.logEvent({ message: 'programUploadStart() request', bikeType, length: eppLength });
770
+ return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_NEW_PROGRAM, 'BF', payload)
771
+ .then((res) => {
772
+ const buffer = Buffer.from(res);
773
+ if (buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_NEW_PROGRAM) {
774
+ this.logEvent({ message: 'programUploadStart() response', success: true });
775
+ return epp;
776
+ }
777
+ this.logEvent({ message: 'programUploadStart() response', success: false });
778
+ throw new Error('Illegal Response');
779
+ });
780
+ }
781
+ programUploadSendBlock(epp, offset) {
782
+ const remaining = epp.length - offset;
783
+ if (remaining <= 0)
784
+ return Promise.resolve(true);
785
+ const size = remaining > MAX_DATA_BLOCK_SIZE ? MAX_DATA_BLOCK_SIZE : remaining;
786
+ const payload = Buffer.alloc(size + 8);
787
+ payload.writeInt32LE(size, 0);
788
+ payload.writeInt32LE(offset, 4);
789
+ const chunk = Buffer.from(epp.slice(offset, offset + size));
790
+ chunk.copy(payload, 8);
791
+ this.logEvent({ message: 'programUploadSendBlock() request', offset, size });
792
+ return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_CONTINUE_PROGRAM, 'BF', payload)
793
+ .then((res) => {
794
+ const buffer = Buffer.from(res);
795
+ let success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_CONTINUE_PROGRAM;
796
+ success = success && (buffer.readInt16LE(2) === 1);
797
+ success = success && (buffer.readInt8(4) === 1);
798
+ this.logEvent({ message: 'programUploadSendBlock() response' });
799
+ if (!success)
800
+ throw new Error('Illegal Response');
801
+ return true;
802
+ ;
803
+ });
804
+ }
805
+ programUploadDone() {
806
+ this.logEvent({ message: 'programUploadDone() request' });
807
+ return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_END, 'BF')
808
+ .then((res) => {
809
+ const buffer = Buffer.from(res);
810
+ const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_END;
811
+ this.logEvent({ message: 'programUploadDone() response', success });
812
+ if (!success)
813
+ throw new Error('Illegal Response');
814
+ return true;
815
+ ;
816
+ });
817
+ }
818
+ programUpload(bikeType, route, onStatusUpdate) {
819
+ return __awaiter(this, void 0, void 0, function* () {
820
+ try {
821
+ yield this.programUploadInit();
822
+ const epp = yield this.programUploadStart(bikeType, route);
823
+ if (epp) {
824
+ let success = true;
825
+ let done = false;
826
+ let offset = 0;
827
+ if (onStatusUpdate)
828
+ onStatusUpdate(0, epp.length);
829
+ while (success && !done) {
830
+ success = yield this.programUploadSendBlock(epp, offset);
831
+ offset += MAX_DATA_BLOCK_SIZE;
832
+ done = offset >= epp.length;
833
+ if (onStatusUpdate)
834
+ onStatusUpdate(done ? epp.length : offset, epp.length);
835
+ }
836
+ if (done) {
837
+ return yield this.programUploadDone();
838
+ }
839
+ }
840
+ else {
841
+ return yield this.programUploadDone();
842
+ }
843
+ }
844
+ catch (err) {
845
+ console.log('~~~ err', err);
846
+ }
847
+ return false;
848
+ });
849
+ }
850
+ startProgram(programId = 1) {
851
+ const payload = Buffer.alloc(2);
852
+ payload.writeInt16LE(programId, 0);
853
+ this.logEvent({ message: 'startProgram() request', programId });
854
+ return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_START, 'BF', payload)
855
+ .then((res) => {
856
+ const buffer = Buffer.from(res);
857
+ const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_START;
858
+ this.logEvent({ message: 'startProgram() request', programId, success });
859
+ if (!success)
860
+ throw new Error('Illegal Response');
861
+ return true;
862
+ ;
863
+ });
864
+ }
865
+ setGear(gear) {
866
+ return this.sendDaum8iCommand('M71', 'BF', `${gear}`)
867
+ .then((str) => {
868
+ const gearVal = parseInt(str);
869
+ return gearVal > 0 ? gearVal - 1 : undefined;
870
+ });
871
+ }
872
+ getGear() {
873
+ return this.sendDaum8iCommand('M71', 'AF', '')
874
+ .then((str) => {
875
+ return parseInt(str);
876
+ });
877
+ }
878
+ }
879
+ class Daum8iTcp extends Daum8i {
880
+ static getClassName() { return "Daum8i"; }
881
+ getType() { return "Daum8iTcp"; }
882
+ static setSerialPort(spClass) { }
883
+ getInterface() { return constants_1.BIKE_INTERFACE.TCPIP; }
884
+ static setNetImpl(netClass) {
885
+ net = netClass;
886
+ }
887
+ static getSupportedInterfaces() {
888
+ return [constants_1.BIKE_INTERFACE.TCPIP];
889
+ }
890
+ }
891
+ exports.Daum8iTcp = Daum8iTcp;
892
+ class Daum8iSerial extends Daum8i {
893
+ static getClassName() { return "Daum8i"; }
894
+ getType() { return "Daum8iSerial"; }
895
+ getInterface() { return constants_1.BIKE_INTERFACE.SERIAL; }
896
+ static setSerialPort(spClass) {
897
+ __SerialPort = spClass;
898
+ }
899
+ static setNetImpl(netClass) { }
900
+ static getSupportedInterfaces() {
901
+ return [constants_1.BIKE_INTERFACE.SERIAL];
902
+ }
903
+ }
904
+ exports.Daum8iSerial = Daum8iSerial;