incyclist-devices 2.0.35 → 2.0.37

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 (54) hide show
  1. package/lib/antv2/modes/ant-fe-adv-st-mode.d.ts +2 -2
  2. package/lib/antv2/modes/ant-fe-erg-mode.d.ts +2 -2
  3. package/lib/antv2/modes/ant-fe-st-mode.d.ts +2 -2
  4. package/lib/base/adpater.d.ts +2 -1
  5. package/lib/base/adpater.js +7 -6
  6. package/lib/interfaces.d.ts +1 -1
  7. package/lib/modes/ble-erg-mode.d.ts +2 -2
  8. package/lib/modes/ble-st-mode.d.ts +2 -2
  9. package/lib/modes/cycling-mode.d.ts +7 -7
  10. package/lib/modes/power-base.d.ts +3 -3
  11. package/lib/modes/power-base.js +3 -2
  12. package/lib/modes/power-meter.d.ts +2 -2
  13. package/lib/serial/comms.d.ts +62 -0
  14. package/lib/serial/comms.js +280 -0
  15. package/lib/serial/daum/DaumAdapter.d.ts +13 -8
  16. package/lib/serial/daum/DaumAdapter.js +49 -12
  17. package/lib/serial/daum/ERGCyclingMode.d.ts +2 -2
  18. package/lib/serial/daum/ERGCyclingMode.js +1 -1
  19. package/lib/serial/daum/SmartTrainerCyclingMode.d.ts +3 -2
  20. package/lib/serial/daum/SmartTrainerCyclingMode.js +10 -5
  21. package/lib/serial/daum/classic/adapter.d.ts +4 -6
  22. package/lib/serial/daum/classic/adapter.js +5 -23
  23. package/lib/serial/daum/classic/comms.d.ts +33 -65
  24. package/lib/serial/daum/classic/comms.js +148 -332
  25. package/lib/serial/daum/classic/mock.js +5 -3
  26. package/lib/serial/daum/classic/modes/daum-classic.d.ts +2 -2
  27. package/lib/serial/daum/classic/modes/daum-classic.js +1 -1
  28. package/lib/serial/daum/classic/types.d.ts +59 -0
  29. package/lib/serial/daum/classic/types.js +2 -0
  30. package/lib/serial/daum/classic/utils.d.ts +11 -10
  31. package/lib/serial/daum/classic/utils.js +33 -68
  32. package/lib/serial/daum/premium/adapter.d.ts +4 -7
  33. package/lib/serial/daum/premium/adapter.js +7 -30
  34. package/lib/serial/daum/premium/comms.d.ts +28 -105
  35. package/lib/serial/daum/premium/comms.js +262 -466
  36. package/lib/serial/daum/premium/consts.d.ts +6 -0
  37. package/lib/serial/daum/premium/consts.js +9 -0
  38. package/lib/serial/daum/premium/mock.d.ts +32 -1
  39. package/lib/serial/daum/premium/mock.js +131 -8
  40. package/lib/serial/daum/premium/modes/daum-classic.d.ts +2 -2
  41. package/lib/serial/daum/premium/modes/daum-classic.js +1 -1
  42. package/lib/serial/daum/premium/types.d.ts +35 -1
  43. package/lib/serial/daum/premium/types.js +29 -0
  44. package/lib/serial/daum/premium/utils.d.ts +12 -18
  45. package/lib/serial/daum/premium/utils.js +34 -19
  46. package/lib/serial/serial-interface.js +3 -2
  47. package/lib/types/adapter.d.ts +2 -0
  48. package/lib/types/device.d.ts +11 -0
  49. package/lib/types/route.d.ts +0 -5
  50. package/lib/types/route.js +0 -7
  51. package/lib/utils/calculations.js +1 -5
  52. package/lib/utils/utils.d.ts +2 -1
  53. package/lib/utils/utils.js +39 -3
  54. package/package.json +3 -2
@@ -8,252 +8,55 @@ 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
- exports.ResponseTimeout = exports.BusyTimeout = exports.ACKTimeout = exports.CheckSumError = void 0;
13
15
  const constants_1 = require("../constants");
14
16
  const utils_1 = require("./utils");
15
- const gd_eventlog_1 = require("gd-eventlog");
17
+ const types_1 = require("./types");
16
18
  const utils_2 = require("../../../utils/utils");
17
- const DEFAULT_TIMEOUT = 10000;
18
- const MAX_DATA_BLOCK_SIZE = 512;
19
- const DS_BITS_OFF = 0;
20
- const DS_BITS_ENDLESS_RACE = 2;
21
- const DEBUG_LOGGER = {
22
- log: (e, ...args) => console.log(e, ...args),
23
- logEvent: (event) => console.log(JSON.stringify(event))
24
- };
25
- const validateHost = (host) => {
26
- const ipParts = host.split('.');
27
- if (ipParts.length > 1)
28
- return ipParts.map(p => Number(p)).join('.');
29
- return host;
30
- };
31
- const validatePath = (path) => {
32
- const parts = path.split(':');
33
- if (parts.length < 2)
34
- return path;
35
- const host = validateHost(parts[0]);
36
- const port = parts[1];
37
- return `${host}:${port}`;
38
- };
39
- class CheckSumError extends Error {
40
- constructor() {
41
- super();
42
- this.message = 'checksum incorrect';
19
+ const comms_1 = __importDefault(require("../../comms"));
20
+ const consts_1 = require("./consts");
21
+ class Daum8i extends comms_1.default {
22
+ validatePath(path) {
23
+ return (0, utils_1.validatePath)(path);
43
24
  }
44
- }
45
- exports.CheckSumError = CheckSumError;
46
- class ACKTimeout extends Error {
47
- constructor() {
48
- super();
49
- this.message = 'ACK timeout';
25
+ getDefaultLoggerName() {
26
+ return 'DaumPremium';
50
27
  }
51
- }
52
- exports.ACKTimeout = ACKTimeout;
53
- class BusyTimeout extends Error {
54
- constructor() {
55
- super();
56
- this.message = 'BUSY timeout';
28
+ getAckTimeoutValue() {
29
+ return consts_1.DEFAULT_ACK_TIMEOUT;
57
30
  }
58
- }
59
- exports.BusyTimeout = BusyTimeout;
60
- class ResponseTimeout extends Error {
61
- constructor() {
62
- super();
63
- this.message = 'RESP timeout';
64
- }
65
- }
66
- exports.ResponseTimeout = ResponseTimeout;
67
- class Daum8i {
68
- constructor(props) {
69
- this.onNAK = () => {
70
- };
71
- this.props = props || {};
72
- const { logger, serial, path } = props;
73
- this.serial = serial;
74
- this.path = validatePath(path);
75
- const w = global.window;
76
- this.logger = logger || ((w === null || w === void 0 ? void 0 : w.DEVICE_DEBUG) || process.env.DEBUG ? DEBUG_LOGGER : new gd_eventlog_1.EventLogger('DaumPremium'));
77
- this.isLoggingPaused = false;
78
- this.connectState = 'Disconnected';
79
- this.connectPromise = null;
80
- this.recvState = { data: new utils_2.Queue() };
81
- this.settings = {};
82
- this.bikeData = {
83
- userWeight: 75,
84
- bikeWeight: 10,
85
- maxPower: 800
86
- };
87
- }
88
- getInterface() {
89
- var _a;
90
- return (_a = this.serial) === null || _a === void 0 ? void 0 : _a.ifaceName;
91
- }
92
- getPort() {
93
- return this.path;
94
- }
95
- isConnected() {
96
- return this.connectState === 'Connected' || this.connectState === 'Disconnecting';
97
- }
98
- pauseLogging() {
99
- this.isLoggingPaused = true;
100
- }
101
- resumeLogging() {
102
- this.isLoggingPaused = false;
103
- }
104
- logEvent(e) {
105
- if (this.isLoggingPaused)
106
- return;
107
- this.logger.logEvent(e);
108
- const w = global.window;
109
- if (w === null || w === void 0 ? void 0 : w.DEVICE_DEBUG) {
110
- console.log('~~~ DaumPremium', e);
111
- }
112
- }
113
- connect() {
114
- return __awaiter(this, void 0, void 0, function* () {
115
- if (this.isConnected() && this.sp) {
116
- return true;
117
- }
118
- if (this.connectState === 'Connecting') {
119
- if (this.connectPromise) {
120
- try {
121
- yield this.connectPromise;
122
- }
123
- catch (_a) {
124
- }
125
- }
126
- return this.isConnected();
127
- }
128
- try {
129
- this.connectState = 'Connecting';
130
- this.connectPromise = this.serial.openPort(this.path);
131
- const port = yield this.connectPromise;
132
- this.connectPromise = null;
133
- if (port !== null) {
134
- this.connectState = 'Connected';
135
- this.sp = port;
136
- this.sp.on('close', this.onPortClose.bind(this));
137
- this.sp.on('error', this.onPortError.bind(this));
138
- this.sp.on('data', this.onData.bind(this));
139
- return true;
140
- }
141
- else {
142
- this.connectState = 'Disconnected';
143
- return false;
144
- }
145
- }
146
- catch (_b) {
147
- this.connectState = 'Disconnected';
148
- return false;
149
- }
150
- });
31
+ getTimeoutValue() {
32
+ return consts_1.DEFAULT_TIMEOUT;
151
33
  }
152
- closePort() {
153
- return __awaiter(this, void 0, void 0, function* () {
154
- if (!this.sp)
155
- return true;
156
- try {
157
- yield this.flush();
158
- yield this.serial.closePort(this.path);
159
- return true;
160
- }
161
- catch (err) {
162
- this.logEvent({ message: 'could not close ', reason: err.message });
163
- return false;
164
- }
165
- });
34
+ onConnected() {
35
+ this.sp.on('data', this.onData.bind(this));
166
36
  }
167
- cleanupPort() {
168
- if (this.sp) {
169
- this.sp.removeAllListeners();
170
- }
171
- this.sp = null;
172
- this.recvState.data.clear();
37
+ getInitialCommsState() {
38
+ const state = super.getInitialCommsState();
39
+ state.waitingForACK = false;
40
+ state.waitingForStart = false;
41
+ state.waitingForEnd = false;
42
+ return state;
173
43
  }
174
- close() {
175
- return __awaiter(this, void 0, void 0, function* () {
176
- let isDisconnected = false;
177
- if (this.disconnectPromise) {
178
- try {
179
- isDisconnected = yield this.disconnectPromise;
180
- }
181
- catch (_a) {
182
- }
183
- return isDisconnected;
184
- }
185
- if (this.connectState === 'Disconnected') {
186
- this.cleanupPort();
187
- return true;
188
- }
189
- else if (this.connectState === 'Disconnecting' || this.connectState === 'Connected' || this.connectState === 'Connecting') {
190
- this.connectState = 'Disconnecting';
191
- this.disconnectPromise = this.closePort();
192
- isDisconnected = yield this.disconnectPromise;
193
- this.connectPromise = null;
194
- this.disconnectPromise = null;
195
- if (isDisconnected)
196
- this.connectState = 'Disconnected';
197
- this.cleanupPort();
198
- }
199
- return isDisconnected;
200
- });
201
- }
202
- flush() {
203
- return __awaiter(this, void 0, void 0, function* () {
204
- if (this.writePromise) {
205
- yield this.waitWithTimeout(this.writePromise, 1000);
206
- this.writePromise = null;
207
- }
208
- });
209
- }
210
- onPortClose() {
211
- return __awaiter(this, void 0, void 0, function* () {
212
- if (this.connectState !== 'Disconnected' && this.connectState !== 'Disconnecting')
213
- this.logEvent({ message: "port closed:", port: this.path });
214
- this.connectState = 'Disconnected';
215
- this.cleanupPort();
216
- });
217
- }
218
- onPortError(error) {
219
- return __awaiter(this, void 0, void 0, function* () {
220
- if (this.connectState === 'Disconnecting' || this.connectState === 'Disconnected') {
221
- return;
222
- }
223
- this.logEvent({ message: "port error:", port: this.path, error: error.message, connected: this.isConnected(), state: this.connectState });
224
- if (this.isSending()) {
225
- this.rejectCurrent(error);
226
- }
227
- if (this.connectState === 'Connected')
228
- this.close();
229
- });
230
- }
231
- isSending() {
232
- return (this.writePromise !== undefined && this.writePromise !== null) || (this.sendCmdPromise !== null && this.sendCmdPromise !== undefined);
233
- }
234
- rejectCurrent(error) {
235
- this.recvState.data.enqueue({ type: 'Error', error });
236
- }
237
- getTimeoutValue(cmd) {
238
- let timeout = DEFAULT_TIMEOUT;
239
- if (this.settings && this.settings.timeout)
240
- timeout = this.settings.timeout;
241
- if (cmd !== undefined && cmd.options !== undefined && cmd.options.timeout !== undefined) {
242
- timeout = cmd.options.timeout;
243
- }
244
- return timeout;
44
+ setState(ack, start, end) {
45
+ this.recvState.waitingForACK = ack;
46
+ this.recvState.waitingForStart = start;
47
+ this.recvState.waitingForEnd = end;
245
48
  }
246
49
  onData(data, depth = 0) {
247
50
  return __awaiter(this, void 0, void 0, function* () {
248
51
  let cmd = '';
249
52
  const MAX_DEPTH = 5;
250
- if (this.recvState.waitingForEnd) {
53
+ if (this.recvState.waitingForEnd && this.recvState.partialCmd) {
251
54
  cmd = this.recvState.partialCmd;
252
55
  }
253
56
  const bufferData = Buffer.isBuffer(data) ? data : Buffer.from(data, 'latin1');
254
57
  let incoming = bufferData;
255
58
  if (depth === 0)
256
- this.logEvent({ message: 'sendCommand:RECV', data: (0, utils_1.hexstr)(incoming), state: this.recvState });
59
+ this.logEvent({ message: 'sendCommand:RECV', data: Buffer.from(incoming).toString('hex') });
257
60
  for (let i = 0; i < incoming.length; i++) {
258
61
  const getRemaining = () => {
259
62
  let remaining = '';
@@ -265,7 +68,7 @@ class Daum8i {
265
68
  return remaining;
266
69
  };
267
70
  const c = incoming.readUInt8(i);
268
- if (c === 0x06) {
71
+ if (c === 0x06 && this.recvState.waitingForACK) {
269
72
  this.recvState.waitingForStart = true;
270
73
  this.recvState.waitingForACK = false;
271
74
  const remaining = getRemaining();
@@ -273,7 +76,7 @@ class Daum8i {
273
76
  if (remaining && remaining !== '' && depth < MAX_DEPTH)
274
77
  return this.onData(remaining, depth + 1);
275
78
  }
276
- else if (c === 0x15) {
79
+ else if (c === 0x15 && this.recvState.waitingForACK) {
277
80
  this.recvState.waitingForStart = true;
278
81
  this.recvState.waitingForACK = false;
279
82
  const remaining = getRemaining();
@@ -281,33 +84,38 @@ class Daum8i {
281
84
  if (remaining && remaining !== '' && depth < MAX_DEPTH)
282
85
  return this.onData(remaining, depth + 1);
283
86
  }
284
- else if (c === 0x01) {
87
+ else if (c === 0x01 && this.recvState.waitingForStart) {
285
88
  this.recvState.waitingForStart = false;
286
89
  this.recvState.waitingForEnd = true;
287
90
  }
288
- else if (c === 0x17) {
91
+ else if (c === 0x17 && this.recvState.waitingForEnd) {
289
92
  const remaining = getRemaining();
290
93
  this.recvState.waitingForEnd = false;
291
- const cmdStr = cmd.substring(0, cmd.length - 2);
292
- const checksumExtracted = cmd.slice(-2);
293
- const checksumCalculated = (0, utils_1.checkSum)((0, utils_1.getAsciiArrayFromStr)(cmdStr), []);
294
- if (checksumExtracted === checksumCalculated) {
295
- const payload = cmd.substring(3, cmd.length - 2);
296
- this.recvState.data.enqueue({ type: 'Response', data: payload });
94
+ if (cmd.length < 5) {
95
+ this.recvState.data.enqueue({ type: 'Error', error: new Error('illegal data'), data: cmd });
297
96
  }
298
97
  else {
299
- const error = new CheckSumError();
300
- this.recvState.data.enqueue({ type: 'Error', error, data: cmd });
301
- this.recvState.waitingForACK = false;
302
- this.recvState.waitingForStart = true;
303
- this.recvState.waitingForEnd = false;
98
+ const cmdStr = cmd.substring(0, cmd.length - 2);
99
+ const checksumExtracted = cmd.slice(-2);
100
+ const checksumCalculated = (0, utils_1.checkSum)((0, utils_1.getAsciiArrayFromStr)(cmdStr), []);
101
+ if (checksumExtracted === checksumCalculated) {
102
+ const payload = cmd.substring(3, cmd.length - 2);
103
+ this.recvState.data.enqueue({ type: 'Response', cmd: cmd.substring(0, 3), data: payload });
104
+ }
105
+ else {
106
+ const error = new types_1.CheckSumError();
107
+ this.recvState.data.enqueue({ type: 'Error', error, data: cmd });
108
+ this.recvState.waitingForACK = false;
109
+ this.recvState.waitingForStart = true;
110
+ this.recvState.waitingForEnd = false;
111
+ }
112
+ cmd = '';
113
+ if (remaining && depth < 5)
114
+ return this.onData(remaining, depth + 1);
304
115
  }
305
- cmd = '';
306
- if (remaining && depth < 5)
307
- return this.onData(remaining, depth + 1);
308
116
  }
309
117
  else {
310
- if (this.recvState.waitingForEnd)
118
+ if (this.recvState.waitingForEnd && c !== 0x01 && c !== 0x06 && c !== 0x15)
311
119
  cmd += String.fromCharCode(c);
312
120
  }
313
121
  }
@@ -316,62 +124,74 @@ class Daum8i {
316
124
  }
317
125
  });
318
126
  }
319
- waitWithTimeout(promise, timeout, onTimeout) {
320
- return __awaiter(this, void 0, void 0, function* () {
321
- let to;
322
- const toPromise = (ms) => {
323
- return new Promise(resolve => { to = setTimeout(resolve, ms); });
324
- };
325
- let res;
326
- try {
327
- res = yield Promise.race([promise, toPromise(timeout).then(() => { if (onTimeout)
328
- onTimeout(); })]);
329
- }
330
- catch (_a) {
331
- }
332
- clearTimeout(to);
333
- return res;
334
- });
335
- }
336
- sendDaum8iCommand(command, payload = '') {
127
+ send(request) {
337
128
  return __awaiter(this, void 0, void 0, function* () {
129
+ const { command, payload = '' } = request;
338
130
  const message = (0, utils_1.buildMessage)(command, payload);
339
- const tsRequest = Date.now();
340
- if (this.sendCmdPromise) {
341
- this.logEvent({ message: 'sendCommand:waiting', port: this.path, cmd: command, hex: (0, utils_1.hexstr)(message) });
342
- const onTimeout = () => {
343
- this.logEvent({ message: 'sendCommand:busy timeout', port: this.path, cmd: command, hex: (0, utils_1.hexstr)(message), duration: Date.now() - tsRequest });
344
- throw new Error('BUSY timeout');
131
+ let logPayload;
132
+ if (request.isBinary) {
133
+ logPayload = {
134
+ port: this.path,
135
+ cmd: request.logString || 'BinaryCommand',
345
136
  };
346
- this.waitWithTimeout(this.sendCmdPromise, 5000, onTimeout);
347
- this.sendCmdPromise = null;
348
137
  }
138
+ else {
139
+ logPayload = {
140
+ port: this.path,
141
+ cmd: `${request.logString} (${command})` || command
142
+ };
143
+ }
144
+ yield this.ensurePrevCmdFinish(logPayload);
349
145
  this.sendCmdPromise = new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
350
146
  try {
351
- this.logEvent({ message: "sendCommand:sending:", port: this.path, cmd: command, hex: (0, utils_1.hexstr)(message) });
352
- if (!this.isConnected()) {
353
- const connected = yield this.connect();
354
- if (!connected) {
355
- reject(new Error('not connected'));
356
- return;
357
- }
358
- }
147
+ this.logEvent(Object.assign(Object.assign({ message: "sendCommand:sending:" }, logPayload), { hex: Buffer.from(message).toString('hex') }));
148
+ yield this.ensureConnection();
359
149
  let retryCnt = 0;
360
150
  let ok = false;
361
151
  do {
152
+ if (retryCnt > 0)
153
+ this.logEvent(Object.assign(Object.assign({ message: "sendCommand:resending:" }, logPayload), { hex: Buffer.from(message).toString('hex') }));
362
154
  yield this.write(Buffer.from(message));
363
155
  ok = yield this.waitForACK();
156
+ this.logEvent(Object.assign({ message: `sendCommand:${ok ? 'ACK' : 'NAK'} received:` }, logPayload));
364
157
  if (!ok) {
365
- yield (0, utils_2.sleep)(1000);
158
+ yield (0, utils_2.sleep)(100);
366
159
  retryCnt++;
367
160
  }
368
161
  } while (!ok && retryCnt < 5);
369
- const res = yield this.waitForResponse();
162
+ if (!ok) {
163
+ this.sendCmdPromise = null;
164
+ throw new Error('ACK Error');
165
+ }
166
+ let checksumFailure = false;
167
+ let retry = 0;
168
+ let response;
169
+ do {
170
+ response = yield this.waitForResponse();
171
+ if (response.type === 'Response') {
172
+ this.logEvent(Object.assign(Object.assign({ message: `sendCommand:received:` }, logPayload), { response: request.isBinary ? Buffer.from(response.data).toString('hex') : (0, utils_1.responseLog)(response.data) }));
173
+ yield this.sendACK(logPayload);
174
+ this.sendCmdPromise = null;
175
+ return resolve(response);
176
+ }
177
+ if (response.type === 'Error') {
178
+ this.logEvent(Object.assign(Object.assign({ message: `sendCommand:received:ERROR` }, logPayload), { error: response.error.message }));
179
+ if (response.error instanceof types_1.CheckSumError && retry < 5) {
180
+ checksumFailure = true;
181
+ yield this.sendNAK(logPayload);
182
+ retry++;
183
+ }
184
+ else {
185
+ this.sendCmdPromise = null;
186
+ throw response.error;
187
+ }
188
+ }
189
+ } while (checksumFailure && retry < 5);
370
190
  this.sendCmdPromise = null;
371
- resolve(res);
191
+ return response;
372
192
  }
373
193
  catch (err) {
374
- this.logEvent({ message: "sendCommand:error:", port: this.path, error: err.message, stack: err.stack });
194
+ this.logEvent(Object.assign(Object.assign({ message: "sendCommand:error:" }, logPayload), { error: err.message, stack: err.stack }));
375
195
  this.sendCmdPromise = null;
376
196
  reject(err);
377
197
  }
@@ -379,15 +199,22 @@ class Daum8i {
379
199
  return this.sendCmdPromise;
380
200
  });
381
201
  }
382
- onIgnored(payload) {
383
- this.logEvent({ message: 'onData:IGNORED', port: this.path, data: payload });
202
+ sendStrCommand(logString, command, payload = '') {
203
+ return __awaiter(this, void 0, void 0, function* () {
204
+ const response = yield this.send({ logString, command, payload, isBinary: false });
205
+ return response.data;
206
+ });
384
207
  }
385
- onACK() {
208
+ sendBinaryCommand(logString, command, payload = '') {
209
+ return __awaiter(this, void 0, void 0, function* () {
210
+ const response = yield this.send({ logString, command, payload, isBinary: true });
211
+ return response.data;
212
+ });
386
213
  }
387
214
  waitForACK() {
388
215
  return __awaiter(this, void 0, void 0, function* () {
389
- this.recvState.waitingForACK = true;
390
- const timeout = this.getTimeoutValue();
216
+ this.setState(true, false, false);
217
+ const timeout = this.getAckTimeoutValue();
391
218
  let waitingForACK = true;
392
219
  let start = Date.now();
393
220
  let tsTimeout = start + timeout;
@@ -398,13 +225,12 @@ class Daum8i {
398
225
  }
399
226
  else {
400
227
  if (response.type === 'ACK' || response.type === 'NAK') {
401
- this.logEvent({ message: `sendCommand:${response.type} received:`, port: this.path });
402
228
  waitingForACK = false;
403
229
  return (response.type === 'ACK');
404
230
  }
405
231
  }
406
232
  }
407
- throw new ACKTimeout();
233
+ throw new types_1.ACKTimeout();
408
234
  });
409
235
  }
410
236
  waitForResponse() {
@@ -413,46 +239,16 @@ class Daum8i {
413
239
  let waitingForResponse = true;
414
240
  let start = Date.now();
415
241
  let tsTimeout = start + timeout;
416
- let retry = 0;
417
- while (waitingForResponse && Date.now() < tsTimeout && retry < 5) {
242
+ while (waitingForResponse && Date.now() < tsTimeout) {
418
243
  const response = this.recvState.data.dequeue();
419
244
  if (!response) {
420
245
  yield (0, utils_2.sleep)(5);
421
246
  }
422
247
  else {
423
- if (response.type === 'Response') {
424
- this.logEvent({ message: `sendCommand:received:`, port: this.path, cmd: response.data });
425
- yield this.sendACK();
426
- waitingForResponse = false;
427
- return response.data;
428
- }
429
- if (response.type === 'Error') {
430
- this.logEvent({ message: `sendCommand:received:ERROR`, port: this.path, error: response.error.message });
431
- if (response.error instanceof CheckSumError && retry < 5) {
432
- yield this.sendNAK();
433
- retry++;
434
- }
435
- else {
436
- throw response.error;
437
- }
438
- }
248
+ return response;
439
249
  }
440
250
  }
441
- throw new ResponseTimeout();
442
- });
443
- }
444
- portWrite(buffer) {
445
- return __awaiter(this, void 0, void 0, function* () {
446
- if (!this.sp) {
447
- this.logEvent({ message: 'write failed', error: 'port is not opened' });
448
- return;
449
- }
450
- try {
451
- yield this.sp.write(buffer);
452
- }
453
- catch (err) {
454
- this.logEvent({ message: 'write failed', error: err.message });
455
- }
251
+ throw new types_1.ResponseTimeout();
456
252
  });
457
253
  }
458
254
  write(buffer, ackExpected = true) {
@@ -472,52 +268,33 @@ class Daum8i {
472
268
  this.writePromise = null;
473
269
  });
474
270
  }
475
- sendACK() {
271
+ sendACK(logPayload) {
476
272
  return __awaiter(this, void 0, void 0, function* () {
477
- this.logEvent({ message: "sendCommand:sending ACK", port: this.path });
273
+ this.logEvent(Object.assign({ message: "sendCommand:sending ACK" }, logPayload));
478
274
  yield this.write(Buffer.from([0x06]), false);
479
275
  });
480
276
  }
481
- sendNAK() {
277
+ sendNAK(logPayload) {
482
278
  return __awaiter(this, void 0, void 0, function* () {
483
- this.logEvent({ message: "sendCommand:sending NAK", port: this.path });
279
+ this.logEvent(Object.assign({ message: "sendCommand:sending NAK" }, logPayload));
484
280
  yield this.write(Buffer.from([0x15]), false);
485
281
  });
486
282
  }
487
- sendReservedDaum8iCommand(command, data) {
488
- let buffer;
489
- if (data !== undefined && data.length > 0) {
490
- buffer = Buffer.alloc(data.length + 4);
491
- buffer.writeInt16LE(command, 0);
492
- buffer.writeUInt16LE(data.length, 2);
493
- data.copy(buffer, 4);
494
- }
495
- else {
496
- buffer = Buffer.alloc(4);
497
- buffer.writeInt16LE(command, 0);
498
- buffer.writeUInt16LE(0, 2);
499
- }
500
- const cmdData = Uint8Array.from(buffer);
501
- return this.sendDaum8iCommand('M70', (0, utils_1.bin2esc)(cmdData))
502
- .then((res) => {
503
- const resData = Uint8Array.from(res, x => x.charCodeAt(0));
504
- const cmd = (0, utils_1.esc2bin)(resData);
505
- return cmd;
506
- });
507
- }
508
283
  getProtocolVersion() {
509
- return this.sendDaum8iCommand('V00')
510
- .then((data) => {
284
+ return __awaiter(this, void 0, void 0, function* () {
285
+ const data = yield this.sendStrCommand('getProtocolVersion', 'V00');
511
286
  const version = data.substring(0, 1) + '.' + data.substring(1);
512
287
  return (version);
513
288
  });
514
289
  }
515
290
  getDashboardVersion() {
516
- return this.sendDaum8iCommand('V70');
291
+ return __awaiter(this, void 0, void 0, function* () {
292
+ return this.sendStrCommand('getDashboardVersion', 'V70');
293
+ });
517
294
  }
518
295
  getDeviceType() {
519
- return this.sendDaum8iCommand('Y00')
520
- .then((str) => {
296
+ return __awaiter(this, void 0, void 0, function* () {
297
+ const str = yield this.sendStrCommand('getDeviceType', 'Y00');
521
298
  let deviceType;
522
299
  if (str === '0')
523
300
  deviceType = 'run';
@@ -531,8 +308,8 @@ class Daum8i {
531
308
  });
532
309
  }
533
310
  getActualBikeType() {
534
- return this.sendDaum8iCommand('M72')
535
- .then((str) => {
311
+ return __awaiter(this, void 0, void 0, function* () {
312
+ const str = yield this.sendStrCommand('getActualBikeType', 'M72');
536
313
  let deviceType;
537
314
  if (str === '0')
538
315
  deviceType = constants_1.ACTUAL_BIKE_TYPE.ALLROUND;
@@ -548,25 +325,25 @@ class Daum8i {
548
325
  });
549
326
  }
550
327
  setActualBikeType(actualBikeType) {
551
- let bikeType;
552
- switch (actualBikeType) {
553
- case constants_1.ACTUAL_BIKE_TYPE.ALLROUND:
554
- bikeType = '0';
555
- break;
556
- case constants_1.ACTUAL_BIKE_TYPE.RACE:
557
- bikeType = '1';
558
- break;
559
- case constants_1.ACTUAL_BIKE_TYPE.TRIATHLON:
560
- bikeType = '1';
561
- break;
562
- case constants_1.ACTUAL_BIKE_TYPE.MOUNTAIN:
563
- bikeType = '2';
564
- break;
565
- default:
566
- bikeType = undefined;
567
- }
568
- return this.sendDaum8iCommand(`M72${bikeType}`)
569
- .then((str) => {
328
+ return __awaiter(this, void 0, void 0, function* () {
329
+ let bikeType;
330
+ switch (actualBikeType) {
331
+ case constants_1.ACTUAL_BIKE_TYPE.ALLROUND:
332
+ bikeType = '0';
333
+ break;
334
+ case constants_1.ACTUAL_BIKE_TYPE.RACE:
335
+ bikeType = '1';
336
+ break;
337
+ case constants_1.ACTUAL_BIKE_TYPE.TRIATHLON:
338
+ bikeType = '1';
339
+ break;
340
+ case constants_1.ACTUAL_BIKE_TYPE.MOUNTAIN:
341
+ bikeType = '2';
342
+ break;
343
+ default:
344
+ bikeType = undefined;
345
+ }
346
+ const str = yield this.sendStrCommand('setActualBikeType', `M72${bikeType}`);
570
347
  let deviceType;
571
348
  if (str === '0')
572
349
  deviceType = constants_1.ACTUAL_BIKE_TYPE.ALLROUND;
@@ -581,88 +358,118 @@ class Daum8i {
581
358
  });
582
359
  }
583
360
  getTrainingData() {
584
- return this.sendDaum8iCommand('X70')
585
- .then((data) => {
586
- const td = (0, utils_1.parseTrainingData)(data);
587
- return td;
361
+ return __awaiter(this, void 0, void 0, function* () {
362
+ const data = yield this.sendStrCommand('getTrainingData', 'X70');
363
+ return (0, utils_1.parseTrainingData)(data);
588
364
  });
589
365
  }
590
366
  setLoadControl(enabled) {
591
- const val = enabled ? (0, utils_1.ascii)('1') : (0, utils_1.ascii)('0');
592
- return this.sendDaum8iCommand('S20', [val])
593
- .then((data) => {
367
+ return __awaiter(this, void 0, void 0, function* () {
368
+ const val = enabled ? (0, utils_1.ascii)('1') : (0, utils_1.ascii)('0');
369
+ const data = yield this.sendStrCommand('setLoadControl', 'S20', new Uint8Array([val]));
594
370
  const res = data === '1';
595
371
  return res;
596
372
  });
597
373
  }
598
374
  getLoadControl() {
599
- return this.sendDaum8iCommand('S20')
600
- .then((data) => {
375
+ return __awaiter(this, void 0, void 0, function* () {
376
+ const data = yield this.sendStrCommand('getLoadControl', 'S20');
601
377
  const res = data === '1';
602
378
  return res;
603
379
  });
604
380
  }
605
381
  setPower(power) {
606
- const powerStr = Number.parseFloat(power).toFixed(2);
607
- return this.sendDaum8iCommand(`S23${powerStr}`)
608
- .then((str) => {
382
+ return __awaiter(this, void 0, void 0, function* () {
383
+ const powerStr = typeof power === 'string' ? Number.parseFloat(power).toFixed(2) : power.toFixed(2);
384
+ const str = yield this.sendStrCommand('setPower', `S23${powerStr}`);
385
+ return parseInt(str);
386
+ });
387
+ }
388
+ getPower() {
389
+ return __awaiter(this, void 0, void 0, function* () {
390
+ const str = yield this.sendStrCommand('getPower', 'S23');
391
+ return parseInt(str);
392
+ });
393
+ }
394
+ setGear(gear) {
395
+ return __awaiter(this, void 0, void 0, function* () {
396
+ const str = yield this.sendStrCommand('setGear', `M71${gear}`);
609
397
  return parseInt(str);
610
398
  });
611
399
  }
612
- getPower(power) {
613
- return this.sendDaum8iCommand('S23')
614
- .then((str) => {
400
+ getGear() {
401
+ return __awaiter(this, void 0, void 0, function* () {
402
+ const str = yield this.sendStrCommand('getGear', 'M71');
615
403
  return parseInt(str);
616
404
  });
617
405
  }
406
+ sendReservedDaum8iCommand(logString, command, data) {
407
+ return __awaiter(this, void 0, void 0, function* () {
408
+ let buffer;
409
+ if (data !== undefined && data.length > 0) {
410
+ buffer = Buffer.alloc(data.length + 4);
411
+ buffer.writeInt16LE(command, 0);
412
+ buffer.writeUInt16LE(data.length, 2);
413
+ data.copy(buffer, 4);
414
+ }
415
+ else {
416
+ buffer = Buffer.alloc(4);
417
+ buffer.writeInt16LE(command, 0);
418
+ buffer.writeUInt16LE(0, 2);
419
+ }
420
+ const cmdData = Uint8Array.from(buffer);
421
+ const res = yield this.sendBinaryCommand(logString || 'ReservedCommand', 'M70', (0, utils_1.bin2esc)(cmdData));
422
+ const resData = Uint8Array.from(res, x => x.charCodeAt(0));
423
+ const cmd = (0, utils_1.esc2bin)(resData);
424
+ return cmd;
425
+ });
426
+ }
618
427
  setPerson(person) {
619
- const { sex, age, length, weight } = person;
620
- this.logEvent({ message: 'setPerson() request', sex, age, length, weight });
621
- return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PERSON_SET, (0, utils_1.getPersonData)(person))
622
- .then((res) => {
428
+ return __awaiter(this, void 0, void 0, function* () {
429
+ const { sex, age, length, weight } = person;
430
+ const logStr = `setPerson(${sex === undefined ? '' : sex},${age === undefined ? '' : age},${length === undefined ? '' : length},${weight === undefined ? '' : length})`;
431
+ const res = yield this.sendReservedDaum8iCommand(logStr, utils_1.ReservedCommands.PERSON_SET, (0, utils_1.getPersonData)(person));
623
432
  const buffer = Buffer.from(res);
624
433
  const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PERSON_SET;
625
- this.logEvent({ message: 'setPerson() response', success, buffer });
434
+ this.logEvent({ message: `${logStr} response`, success });
626
435
  if (!success)
627
436
  throw new Error('Illegal Response');
628
437
  return true;
629
438
  });
630
439
  }
631
440
  programUploadInit() {
632
- this.logEvent({ message: 'programUploadInit() request' });
633
- return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_BEGIN)
634
- .then((res) => {
441
+ return __awaiter(this, void 0, void 0, function* () {
442
+ const res = yield this.sendReservedDaum8iCommand('programUploadInit()', utils_1.ReservedCommands.PROGRAM_LIST_BEGIN);
635
443
  const buffer = Buffer.from(res);
636
444
  const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_BEGIN;
637
- this.logEvent({ message: 'programUploadInit() response', success, buffer });
445
+ this.logEvent({ message: 'programUploadInit() response', success });
638
446
  if (!success)
639
447
  throw new Error('Illegal Response');
640
448
  return true;
641
449
  });
642
450
  }
643
451
  programUploadStart(bikeType, route) {
644
- const payload = Buffer.alloc(40);
645
- const epp = route ? (0, utils_1.routeToEpp)(route) : undefined;
646
- const eppLength = epp ? epp.length : 0;
647
- const bikeTypeVal = (0, utils_1.getBikeType)(bikeType);
648
- const wBits = route.lapMode ? DS_BITS_ENDLESS_RACE : DS_BITS_OFF;
649
- payload.writeInt32LE(0, 0);
650
- payload.writeInt8(bikeTypeVal, 4);
651
- payload.writeInt8(0, 5);
652
- payload.writeInt16LE(0, 6);
653
- payload.writeInt32LE(0, 8);
654
- payload.writeInt32LE(0, 12);
655
- payload.writeFloatLE(0, 16);
656
- payload.writeFloatLE(0, 20);
657
- payload.writeInt16LE(0, 24);
658
- payload.writeInt16LE(0, 26);
659
- payload.writeInt16LE(0, 28);
660
- payload.writeInt16LE(wBits, 30);
661
- payload.writeInt32LE(7, 32);
662
- payload.writeInt32LE(eppLength, 36);
663
- this.logEvent({ message: 'programUploadStart() request', bikeType, length: eppLength });
664
- return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_NEW_PROGRAM, payload)
665
- .then((res) => {
452
+ return __awaiter(this, void 0, void 0, function* () {
453
+ const payload = Buffer.alloc(40);
454
+ const epp = route ? (0, utils_1.routeToEpp)(route) : undefined;
455
+ const eppLength = epp ? epp.length : 0;
456
+ const bikeTypeVal = (0, utils_1.getBikeType)(bikeType);
457
+ const wBits = route.lapMode ? consts_1.DS_BITS_ENDLESS_RACE : consts_1.DS_BITS_OFF;
458
+ payload.writeInt32LE(0, 0);
459
+ payload.writeInt8(bikeTypeVal, 4);
460
+ payload.writeInt8(0, 5);
461
+ payload.writeInt16LE(0, 6);
462
+ payload.writeInt32LE(0, 8);
463
+ payload.writeInt32LE(0, 12);
464
+ payload.writeFloatLE(0, 16);
465
+ payload.writeFloatLE(0, 20);
466
+ payload.writeInt16LE(0, 24);
467
+ payload.writeInt16LE(0, 26);
468
+ payload.writeInt16LE(0, 28);
469
+ payload.writeInt16LE(wBits, 30);
470
+ payload.writeInt32LE(7, 32);
471
+ payload.writeInt32LE(eppLength, 36);
472
+ const res = yield this.sendReservedDaum8iCommand('programUploadStart()', utils_1.ReservedCommands.PROGRAM_LIST_NEW_PROGRAM, payload);
666
473
  const buffer = Buffer.from(res);
667
474
  if (buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_NEW_PROGRAM) {
668
475
  this.logEvent({ message: 'programUploadStart() response', success: true });
@@ -673,23 +480,23 @@ class Daum8i {
673
480
  });
674
481
  }
675
482
  programUploadSendBlock(epp, offset) {
676
- const remaining = epp.length - offset;
677
- if (remaining <= 0)
678
- return Promise.resolve(true);
679
- const size = remaining > MAX_DATA_BLOCK_SIZE ? MAX_DATA_BLOCK_SIZE : remaining;
680
- const payload = Buffer.alloc(size + 8);
681
- payload.writeInt32LE(size, 0);
682
- payload.writeInt32LE(offset, 4);
683
- const chunk = Buffer.from(epp.slice(offset, offset + size));
684
- chunk.copy(payload, 8);
685
- this.logEvent({ message: 'programUploadSendBlock() request', offset, size });
686
- return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_CONTINUE_PROGRAM, payload)
687
- .then((res) => {
483
+ return __awaiter(this, void 0, void 0, function* () {
484
+ const remaining = epp.length - offset;
485
+ if (remaining <= 0)
486
+ return Promise.resolve(true);
487
+ const size = remaining > consts_1.MAX_DATA_BLOCK_SIZE ? consts_1.MAX_DATA_BLOCK_SIZE : remaining;
488
+ const payload = Buffer.alloc(size + 8);
489
+ payload.writeInt32LE(size, 0);
490
+ payload.writeInt32LE(offset, 4);
491
+ const chunk = Buffer.from(epp.slice(offset, offset + size));
492
+ chunk.copy(payload, 8);
493
+ const logStr = `programUploadSendBlock(${offset},${size})`;
494
+ const res = yield this.sendReservedDaum8iCommand(logStr, utils_1.ReservedCommands.PROGRAM_LIST_CONTINUE_PROGRAM, payload);
688
495
  const buffer = Buffer.from(res);
689
496
  let success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_CONTINUE_PROGRAM;
690
497
  success = success && (buffer.readInt16LE(2) === 1);
691
498
  success = success && (buffer.readInt8(4) === 1);
692
- this.logEvent({ message: 'programUploadSendBlock() response' });
499
+ this.logEvent({ message: `${logStr} response`, data: buffer.toString('hex') });
693
500
  if (!success)
694
501
  throw new Error('Illegal Response');
695
502
  return true;
@@ -697,9 +504,8 @@ class Daum8i {
697
504
  });
698
505
  }
699
506
  programUploadDone() {
700
- this.logEvent({ message: 'programUploadDone() request' });
701
- return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_END)
702
- .then((res) => {
507
+ return __awaiter(this, void 0, void 0, function* () {
508
+ const res = yield this.sendReservedDaum8iCommand('programUploadDone()', utils_1.ReservedCommands.PROGRAM_LIST_END);
703
509
  const buffer = Buffer.from(res);
704
510
  const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_END;
705
511
  this.logEvent({ message: 'programUploadDone() response', success });
@@ -709,6 +515,21 @@ class Daum8i {
709
515
  ;
710
516
  });
711
517
  }
518
+ startProgram(programId = 1) {
519
+ return __awaiter(this, void 0, void 0, function* () {
520
+ const payload = Buffer.alloc(2);
521
+ payload.writeInt16LE(programId, 0);
522
+ const logStr = `startProgram(${programId})`;
523
+ const res = yield this.sendReservedDaum8iCommand(logStr, utils_1.ReservedCommands.PROGRAM_LIST_START, payload);
524
+ const buffer = Buffer.from(res);
525
+ const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_START;
526
+ this.logEvent({ message: 'startProgram() request', programId, success });
527
+ if (!success)
528
+ throw new Error('Illegal Response');
529
+ return true;
530
+ ;
531
+ });
532
+ }
712
533
  programUpload(bikeType, route, onStatusUpdate) {
713
534
  return __awaiter(this, void 0, void 0, function* () {
714
535
  try {
@@ -720,9 +541,11 @@ class Daum8i {
720
541
  let offset = 0;
721
542
  if (onStatusUpdate)
722
543
  onStatusUpdate(0, epp.length);
544
+ if (epp.length === 0)
545
+ done = true;
723
546
  while (success && !done) {
724
547
  success = yield this.programUploadSendBlock(epp, offset);
725
- offset += MAX_DATA_BLOCK_SIZE;
548
+ offset += consts_1.MAX_DATA_BLOCK_SIZE;
726
549
  done = offset >= epp.length;
727
550
  if (onStatusUpdate)
728
551
  onStatusUpdate(done ? epp.length : offset, epp.length);
@@ -732,41 +555,14 @@ class Daum8i {
732
555
  }
733
556
  }
734
557
  else {
558
+ onStatusUpdate(0, 0);
735
559
  return yield this.programUploadDone();
736
560
  }
737
561
  }
738
562
  catch (err) {
739
- console.log('~~~ err', err);
563
+ this.logEvent({ message: 'error', fn: 'programUpload', error: err.message, stack: err.stack });
740
564
  return false;
741
565
  }
742
- return false;
743
- });
744
- }
745
- startProgram(programId = 1) {
746
- const payload = Buffer.alloc(2);
747
- payload.writeInt16LE(programId, 0);
748
- this.logEvent({ message: 'startProgram() request', programId });
749
- return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_START, payload)
750
- .then((res) => {
751
- const buffer = Buffer.from(res);
752
- const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_START;
753
- this.logEvent({ message: 'startProgram() request', programId, success });
754
- if (!success)
755
- throw new Error('Illegal Response');
756
- return true;
757
- ;
758
- });
759
- }
760
- setGear(gear) {
761
- return this.sendDaum8iCommand(`M71${gear}`)
762
- .then((str) => {
763
- return parseInt(str);
764
- });
765
- }
766
- getGear() {
767
- return this.sendDaum8iCommand('M71')
768
- .then((str) => {
769
- return parseInt(str);
770
566
  });
771
567
  }
772
568
  }