incyclist-devices 2.0.34 → 2.0.36
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.
- package/lib/antv2/modes/ant-fe-adv-st-mode.d.ts +2 -2
- package/lib/antv2/modes/ant-fe-erg-mode.d.ts +2 -2
- package/lib/antv2/modes/ant-fe-st-mode.d.ts +2 -2
- package/lib/base/adpater.d.ts +2 -1
- package/lib/base/adpater.js +7 -6
- package/lib/interfaces.d.ts +1 -1
- package/lib/modes/ble-erg-mode.d.ts +2 -2
- package/lib/modes/ble-st-mode.d.ts +2 -2
- package/lib/modes/cycling-mode.d.ts +7 -7
- package/lib/modes/power-base.d.ts +3 -3
- package/lib/modes/power-base.js +3 -2
- package/lib/modes/power-meter.d.ts +2 -2
- package/lib/serial/comms.d.ts +62 -0
- package/lib/serial/comms.js +280 -0
- package/lib/serial/daum/DaumAdapter.d.ts +13 -8
- package/lib/serial/daum/DaumAdapter.js +49 -12
- package/lib/serial/daum/ERGCyclingMode.d.ts +2 -2
- package/lib/serial/daum/ERGCyclingMode.js +1 -1
- package/lib/serial/daum/SmartTrainerCyclingMode.d.ts +3 -2
- package/lib/serial/daum/SmartTrainerCyclingMode.js +10 -5
- package/lib/serial/daum/classic/adapter.d.ts +4 -6
- package/lib/serial/daum/classic/adapter.js +5 -23
- package/lib/serial/daum/classic/comms.d.ts +33 -65
- package/lib/serial/daum/classic/comms.js +148 -332
- package/lib/serial/daum/classic/mock.js +5 -3
- package/lib/serial/daum/classic/modes/daum-classic.d.ts +2 -2
- package/lib/serial/daum/classic/modes/daum-classic.js +1 -1
- package/lib/serial/daum/classic/types.d.ts +59 -0
- package/lib/serial/daum/classic/types.js +2 -0
- package/lib/serial/daum/classic/utils.d.ts +11 -10
- package/lib/serial/daum/classic/utils.js +33 -68
- package/lib/serial/daum/premium/adapter.d.ts +4 -7
- package/lib/serial/daum/premium/adapter.js +7 -30
- package/lib/serial/daum/premium/comms.d.ts +28 -105
- package/lib/serial/daum/premium/comms.js +262 -466
- package/lib/serial/daum/premium/consts.d.ts +6 -0
- package/lib/serial/daum/premium/consts.js +9 -0
- package/lib/serial/daum/premium/mock.d.ts +32 -1
- package/lib/serial/daum/premium/mock.js +131 -8
- package/lib/serial/daum/premium/modes/daum-classic.d.ts +2 -2
- package/lib/serial/daum/premium/modes/daum-classic.js +1 -1
- package/lib/serial/daum/premium/types.d.ts +35 -1
- package/lib/serial/daum/premium/types.js +29 -0
- package/lib/serial/daum/premium/utils.d.ts +11 -18
- package/lib/serial/daum/premium/utils.js +25 -18
- package/lib/serial/serial-interface.js +17 -10
- package/lib/types/adapter.d.ts +2 -0
- package/lib/types/device.d.ts +11 -0
- package/lib/types/route.d.ts +0 -5
- package/lib/types/route.js +0 -7
- package/lib/utils/calculations.js +1 -5
- package/lib/utils/utils.d.ts +2 -1
- package/lib/utils/utils.js +39 -3
- package/package.json +3 -2
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const DEFAULT_TIMEOUT = 10000;
|
|
2
|
+
export declare const DEFAULT_ACK_TIMEOUT = 11000;
|
|
3
|
+
export declare const DEFAULT_BUSY_TIMEOUT = 5000;
|
|
4
|
+
export declare const MAX_DATA_BLOCK_SIZE = 512;
|
|
5
|
+
export declare const DS_BITS_OFF = 0;
|
|
6
|
+
export declare const DS_BITS_ENDLESS_RACE = 2;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DS_BITS_ENDLESS_RACE = exports.DS_BITS_OFF = exports.MAX_DATA_BLOCK_SIZE = exports.DEFAULT_BUSY_TIMEOUT = exports.DEFAULT_ACK_TIMEOUT = exports.DEFAULT_TIMEOUT = void 0;
|
|
4
|
+
exports.DEFAULT_TIMEOUT = 10000;
|
|
5
|
+
exports.DEFAULT_ACK_TIMEOUT = 11000;
|
|
6
|
+
exports.DEFAULT_BUSY_TIMEOUT = 5000;
|
|
7
|
+
exports.MAX_DATA_BLOCK_SIZE = 512;
|
|
8
|
+
exports.DS_BITS_OFF = 0;
|
|
9
|
+
exports.DS_BITS_ENDLESS_RACE = 2;
|
|
@@ -28,6 +28,26 @@ export declare class Daum8iMockImpl {
|
|
|
28
28
|
list(): Promise<import("@serialport/bindings-interface").PortInfo[]>;
|
|
29
29
|
open(options: any): Promise<Daum8iMockBinding>;
|
|
30
30
|
}
|
|
31
|
+
type Program = {
|
|
32
|
+
lapMode: boolean;
|
|
33
|
+
id?: number;
|
|
34
|
+
started?: boolean;
|
|
35
|
+
};
|
|
36
|
+
type trainingData = {
|
|
37
|
+
time: number;
|
|
38
|
+
heartrate: number;
|
|
39
|
+
v: number;
|
|
40
|
+
slope: number;
|
|
41
|
+
distanceInternal: number;
|
|
42
|
+
pedalRpm: number;
|
|
43
|
+
power: number;
|
|
44
|
+
physEnergy: number;
|
|
45
|
+
realEnergy: number;
|
|
46
|
+
torque: number;
|
|
47
|
+
gear: number;
|
|
48
|
+
deviceState: number;
|
|
49
|
+
speedStatus: number;
|
|
50
|
+
};
|
|
31
51
|
export declare class Daum8MockSimulator {
|
|
32
52
|
protoVersion: string;
|
|
33
53
|
dashboardVersion: string;
|
|
@@ -38,16 +58,21 @@ export declare class Daum8MockSimulator {
|
|
|
38
58
|
currentPower: number;
|
|
39
59
|
loadControl: number;
|
|
40
60
|
person: User;
|
|
61
|
+
program: Program;
|
|
62
|
+
data: trainingData;
|
|
41
63
|
_isSimulateACKTimeout: boolean;
|
|
42
64
|
_isSimulateCheckSumError: boolean;
|
|
65
|
+
_isSimulateReservedError: boolean;
|
|
43
66
|
_timeoutResponse: number;
|
|
44
67
|
timeoutNAKRetry: number;
|
|
45
68
|
simulateACKTimeout(): void;
|
|
46
69
|
simulateTimeout(ms: number): void;
|
|
47
70
|
simulateChecksumError(): void;
|
|
71
|
+
simulateReservedError(): void;
|
|
48
72
|
onNAK(): void;
|
|
49
73
|
onACK(): void;
|
|
50
74
|
}
|
|
75
|
+
export declare function parseProgramListNewData(buffer: Buffer): Program;
|
|
51
76
|
export declare class Daum8iMockBinding extends MockPortBinding {
|
|
52
77
|
waitingForCommand: boolean;
|
|
53
78
|
waitingForAck: boolean;
|
|
@@ -59,7 +84,7 @@ export declare class Daum8iMockBinding extends MockPortBinding {
|
|
|
59
84
|
initHandlers(): void;
|
|
60
85
|
write(buffer: Buffer): Promise<void>;
|
|
61
86
|
processData(buffer: Buffer): Promise<void>;
|
|
62
|
-
createResponse(cmd: string, payload: Buffer): Buffer;
|
|
87
|
+
createResponse(cmd: string, payload: Buffer, binary?: boolean): Buffer;
|
|
63
88
|
emitData(data: string | Buffer): void;
|
|
64
89
|
onGetProtcolVersion(_payload: Buffer): void;
|
|
65
90
|
onGetDashboardVersion(_payload: Buffer): void;
|
|
@@ -71,5 +96,11 @@ export declare class Daum8iMockBinding extends MockPortBinding {
|
|
|
71
96
|
onReservedCommand(payload: Buffer): void;
|
|
72
97
|
onPersonSet(payload: Buffer): void;
|
|
73
98
|
onPersonGet(): void;
|
|
99
|
+
onProgramListBegin(): void;
|
|
100
|
+
onProgramListNewProgram(payload: Buffer): void;
|
|
101
|
+
onProgramListEnd(): void;
|
|
102
|
+
onProgramListContinueProgram(): void;
|
|
103
|
+
onProgramListStart(payload: Buffer): void;
|
|
74
104
|
onGetTrainingData(_payload: Buffer): void;
|
|
75
105
|
}
|
|
106
|
+
export {};
|
|
@@ -9,12 +9,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.Daum8iMockBinding = exports.Daum8MockSimulator = exports.Daum8iMockImpl = exports.Daum8iMock = void 0;
|
|
12
|
+
exports.Daum8iMockBinding = exports.parseProgramListNewData = exports.Daum8MockSimulator = exports.Daum8iMockImpl = exports.Daum8iMock = void 0;
|
|
13
13
|
const binding_mock_1 = require("@serialport/binding-mock");
|
|
14
14
|
const __1 = require("../../");
|
|
15
15
|
const user_1 = require("../../../types/user");
|
|
16
16
|
const utils_1 = require("../../../utils/utils");
|
|
17
17
|
const utils_2 = require("./utils");
|
|
18
|
+
const consts_1 = require("./consts");
|
|
18
19
|
exports.Daum8iMock = {
|
|
19
20
|
reset() {
|
|
20
21
|
Daum8iMockImpl.getInstance().reset();
|
|
@@ -73,6 +74,21 @@ class Daum8iMockImpl {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
exports.Daum8iMockImpl = Daum8iMockImpl;
|
|
77
|
+
const DEFAULT_TRAINING_DATA = {
|
|
78
|
+
time: 0,
|
|
79
|
+
heartrate: 0,
|
|
80
|
+
v: 0,
|
|
81
|
+
slope: 0,
|
|
82
|
+
distanceInternal: 0,
|
|
83
|
+
pedalRpm: 0,
|
|
84
|
+
power: 0,
|
|
85
|
+
physEnergy: 0,
|
|
86
|
+
realEnergy: 0,
|
|
87
|
+
torque: 0,
|
|
88
|
+
gear: 10,
|
|
89
|
+
deviceState: 1,
|
|
90
|
+
speedStatus: 0
|
|
91
|
+
};
|
|
76
92
|
class Daum8MockSimulator {
|
|
77
93
|
constructor() {
|
|
78
94
|
this.protoVersion = '201';
|
|
@@ -84,8 +100,10 @@ class Daum8MockSimulator {
|
|
|
84
100
|
this.currentPower = 0;
|
|
85
101
|
this.loadControl = 1;
|
|
86
102
|
this.person = { weight: 75, length: 180, age: 30, sex: user_1.Gender.MALE };
|
|
103
|
+
this.data = DEFAULT_TRAINING_DATA;
|
|
87
104
|
this._isSimulateACKTimeout = false;
|
|
88
105
|
this._isSimulateCheckSumError = false;
|
|
106
|
+
this._isSimulateReservedError = false;
|
|
89
107
|
this._timeoutResponse = 0;
|
|
90
108
|
this.timeoutNAKRetry = 1000;
|
|
91
109
|
}
|
|
@@ -98,10 +116,19 @@ class Daum8MockSimulator {
|
|
|
98
116
|
simulateChecksumError() {
|
|
99
117
|
this._isSimulateCheckSumError = true;
|
|
100
118
|
}
|
|
119
|
+
simulateReservedError() {
|
|
120
|
+
this._isSimulateReservedError = true;
|
|
121
|
+
}
|
|
101
122
|
onNAK() { }
|
|
102
123
|
onACK() { }
|
|
103
124
|
}
|
|
104
125
|
exports.Daum8MockSimulator = Daum8MockSimulator;
|
|
126
|
+
function parseProgramListNewData(buffer) {
|
|
127
|
+
const wBits = buffer.readInt16LE(30);
|
|
128
|
+
const lapMode = wBits === consts_1.DS_BITS_ENDLESS_RACE;
|
|
129
|
+
return { lapMode };
|
|
130
|
+
}
|
|
131
|
+
exports.parseProgramListNewData = parseProgramListNewData;
|
|
105
132
|
class Daum8iMockBinding extends binding_mock_1.MockPortBinding {
|
|
106
133
|
constructor(parent) {
|
|
107
134
|
super(parent.port, parent.openOptions);
|
|
@@ -214,8 +241,14 @@ class Daum8iMockBinding extends binding_mock_1.MockPortBinding {
|
|
|
214
241
|
}
|
|
215
242
|
});
|
|
216
243
|
}
|
|
217
|
-
createResponse(cmd, payload) {
|
|
218
|
-
|
|
244
|
+
createResponse(cmd, payload, binary = false) {
|
|
245
|
+
let buffer;
|
|
246
|
+
if (binary) {
|
|
247
|
+
buffer = Buffer.from((0, utils_2.buildMessage)(cmd, (0, utils_2.bin2esc)(payload)));
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
buffer = Buffer.from((0, utils_2.buildMessage)(cmd, payload));
|
|
251
|
+
}
|
|
219
252
|
this.prevCommand = Buffer.from(buffer);
|
|
220
253
|
if (this.simulator._isSimulateCheckSumError) {
|
|
221
254
|
this.simulator._isSimulateCheckSumError = false;
|
|
@@ -267,20 +300,110 @@ class Daum8iMockBinding extends binding_mock_1.MockPortBinding {
|
|
|
267
300
|
}
|
|
268
301
|
onReservedCommand(payload) {
|
|
269
302
|
const cmd = payload.readInt16LE(0);
|
|
270
|
-
const
|
|
271
|
-
const data = (0, utils_2.esc2bin)(payload.subarray(4, 4 + length - 1));
|
|
303
|
+
const data = (0, utils_2.esc2bin)(payload.subarray(4, 4 + payload.length - 1));
|
|
272
304
|
switch (cmd) {
|
|
273
|
-
case utils_2.ReservedCommands.PERSON_SET:
|
|
274
|
-
|
|
305
|
+
case utils_2.ReservedCommands.PERSON_SET:
|
|
306
|
+
this.onPersonSet(Buffer.from(data));
|
|
307
|
+
break;
|
|
308
|
+
case utils_2.ReservedCommands.PERSON_GET:
|
|
309
|
+
this.onPersonGet();
|
|
310
|
+
break;
|
|
311
|
+
case utils_2.ReservedCommands.PROGRAM_LIST_BEGIN:
|
|
312
|
+
this.onProgramListBegin();
|
|
313
|
+
break;
|
|
314
|
+
case utils_2.ReservedCommands.PROGRAM_LIST_NEW_PROGRAM:
|
|
315
|
+
this.onProgramListNewProgram(Buffer.from(data));
|
|
316
|
+
break;
|
|
317
|
+
case utils_2.ReservedCommands.PROGRAM_LIST_CONTINUE_PROGRAM:
|
|
318
|
+
this.onProgramListContinueProgram();
|
|
319
|
+
break;
|
|
320
|
+
case utils_2.ReservedCommands.PROGRAM_LIST_END:
|
|
321
|
+
this.onProgramListEnd();
|
|
322
|
+
break;
|
|
323
|
+
case utils_2.ReservedCommands.PROGRAM_LIST_START:
|
|
324
|
+
this.onProgramListStart(Buffer.from(data));
|
|
325
|
+
break;
|
|
275
326
|
}
|
|
276
327
|
}
|
|
277
328
|
onPersonSet(payload) {
|
|
278
329
|
this.simulator.person = (0, utils_2.parsePersonData)(payload);
|
|
279
|
-
|
|
330
|
+
if (this.simulator._isSimulateReservedError) {
|
|
331
|
+
this.emitData(this.createResponse('M70', Buffer.from('08000000', 'hex')));
|
|
332
|
+
this.simulator._isSimulateReservedError = false;
|
|
333
|
+
}
|
|
334
|
+
else
|
|
335
|
+
this.emitData(this.createResponse('M70', Buffer.from('07000000', 'hex'), true));
|
|
280
336
|
}
|
|
281
337
|
onPersonGet() {
|
|
282
338
|
}
|
|
339
|
+
onProgramListBegin() {
|
|
340
|
+
if (this.simulator._isSimulateReservedError) {
|
|
341
|
+
this.emitData(this.createResponse('M70', Buffer.from('07000000', 'hex'), true));
|
|
342
|
+
this.simulator._isSimulateReservedError = false;
|
|
343
|
+
}
|
|
344
|
+
else
|
|
345
|
+
this.emitData(this.createResponse('M70', Buffer.from('08000000', 'hex'), true));
|
|
346
|
+
}
|
|
347
|
+
onProgramListNewProgram(payload) {
|
|
348
|
+
this.simulator.program = parseProgramListNewData(payload);
|
|
349
|
+
if (this.simulator._isSimulateReservedError) {
|
|
350
|
+
this.emitData(this.createResponse('M70', Buffer.from('08000000', 'hex'), true));
|
|
351
|
+
this.simulator._isSimulateReservedError = false;
|
|
352
|
+
}
|
|
353
|
+
else
|
|
354
|
+
this.emitData(this.createResponse('M70', Buffer.from('09000000', 'hex'), true));
|
|
355
|
+
}
|
|
356
|
+
onProgramListEnd() {
|
|
357
|
+
if (this.simulator._isSimulateReservedError) {
|
|
358
|
+
this.emitData(this.createResponse('M70', Buffer.from('08000000', 'hex'), true));
|
|
359
|
+
this.simulator._isSimulateReservedError = false;
|
|
360
|
+
}
|
|
361
|
+
else
|
|
362
|
+
this.emitData(this.createResponse('M70', Buffer.from('0B00010001', 'hex'), true));
|
|
363
|
+
}
|
|
364
|
+
onProgramListContinueProgram() {
|
|
365
|
+
if (this.simulator._isSimulateReservedError) {
|
|
366
|
+
this.emitData(this.createResponse('M70', Buffer.from('08000000', 'hex'), true));
|
|
367
|
+
this.simulator._isSimulateReservedError = false;
|
|
368
|
+
}
|
|
369
|
+
else
|
|
370
|
+
this.emitData(this.createResponse('M70', Buffer.from('0A00010001', 'hex'), true));
|
|
371
|
+
}
|
|
372
|
+
onProgramListStart(payload) {
|
|
373
|
+
if (this.simulator._isSimulateReservedError) {
|
|
374
|
+
this.emitData(this.createResponse('M70', Buffer.from('08000000', 'hex'), true));
|
|
375
|
+
this.simulator._isSimulateReservedError = false;
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
try {
|
|
379
|
+
if (!this.simulator.program)
|
|
380
|
+
this.simulator.program = { lapMode: false };
|
|
381
|
+
this.simulator.program.id = payload.readInt16LE(0);
|
|
382
|
+
this.simulator.program.started = true;
|
|
383
|
+
}
|
|
384
|
+
catch (err) {
|
|
385
|
+
console.log('~~~ ERROR', payload, err, payload.toString('hex'));
|
|
386
|
+
}
|
|
387
|
+
this.emitData(this.createResponse('M70', Buffer.from('0C00000', 'hex'), true));
|
|
388
|
+
}
|
|
389
|
+
}
|
|
283
390
|
onGetTrainingData(_payload) {
|
|
391
|
+
const GS = Buffer.from([0x1D]).toString();
|
|
392
|
+
const { time, heartrate, v, slope, distanceInternal, pedalRpm, power, physEnergy, realEnergy, torque, gear, deviceState, speedStatus } = this.simulator.data;
|
|
393
|
+
const res = `${time}` + GS +
|
|
394
|
+
`${heartrate}` + GS +
|
|
395
|
+
`${v}` + GS +
|
|
396
|
+
`${slope}` + GS +
|
|
397
|
+
`${distanceInternal}` + GS +
|
|
398
|
+
`${pedalRpm}` + GS +
|
|
399
|
+
`${power}` + GS +
|
|
400
|
+
`${physEnergy}` + GS +
|
|
401
|
+
`${realEnergy}` + GS +
|
|
402
|
+
`${torque}` + GS +
|
|
403
|
+
`${gear}` + GS +
|
|
404
|
+
`${deviceState}` + GS +
|
|
405
|
+
`${speedStatus}`;
|
|
406
|
+
this.emitData(this.createResponse('X70', Buffer.from(res)));
|
|
284
407
|
}
|
|
285
408
|
}
|
|
286
409
|
exports.Daum8iMockBinding = Daum8iMockBinding;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import CyclingMode, { CyclingModeProperty, IncyclistBikeData, Settings, UpdateRequest } from "../../../../modes/cycling-mode";
|
|
2
|
-
import DaumAdapter from "../../DaumAdapter";
|
|
3
2
|
import DaumPowerMeterCyclingMode from "../../DaumPowerMeterCyclingMode";
|
|
3
|
+
import { ControllableDeviceAdapter } from "../../../..";
|
|
4
4
|
export default class DaumClassicCyclingMode extends DaumPowerMeterCyclingMode implements CyclingMode {
|
|
5
|
-
constructor(adapter:
|
|
5
|
+
constructor(adapter: ControllableDeviceAdapter, props?: Settings);
|
|
6
6
|
getName(): string;
|
|
7
7
|
getDescription(): string;
|
|
8
8
|
getProperties(): CyclingModeProperty[];
|
|
@@ -16,7 +16,7 @@ const config = {
|
|
|
16
16
|
class DaumClassicCyclingMode extends DaumPowerMeterCyclingMode_1.default {
|
|
17
17
|
constructor(adapter, props) {
|
|
18
18
|
super(adapter, props);
|
|
19
|
-
this.logger = adapter ? adapter.
|
|
19
|
+
this.logger = adapter ? adapter.getLogger() : undefined;
|
|
20
20
|
if (!this.logger)
|
|
21
21
|
this.logger = new gd_eventlog_1.EventLogger('DaumClassic');
|
|
22
22
|
this.setModeProperty('eppSupport', true);
|
|
@@ -1,5 +1,21 @@
|
|
|
1
|
-
import { DeviceProperties } from "../../../types/device";
|
|
1
|
+
import { DaumBikeData, DeviceProperties } from "../../../types/device";
|
|
2
2
|
import { Route } from "../../../types/route";
|
|
3
|
+
import { Queue } from "../../../utils/utils";
|
|
4
|
+
import { Request, Response } from "../../comms";
|
|
5
|
+
export declare class CheckSumError extends Error {
|
|
6
|
+
constructor();
|
|
7
|
+
}
|
|
8
|
+
export declare class ACKTimeout extends Error {
|
|
9
|
+
constructor();
|
|
10
|
+
}
|
|
11
|
+
export declare class BusyTimeout extends Error {
|
|
12
|
+
constructor();
|
|
13
|
+
}
|
|
14
|
+
export declare class ResponseTimeout extends Error {
|
|
15
|
+
constructor();
|
|
16
|
+
}
|
|
17
|
+
export interface DaumPremiumBikeData extends DaumBikeData {
|
|
18
|
+
}
|
|
3
19
|
export type OnDeviceStartCallback = (completed: number, total: number) => void;
|
|
4
20
|
export type DaumPremiumAdapterProps = {
|
|
5
21
|
path: string;
|
|
@@ -10,3 +26,21 @@ export interface Daum8iDeviceProperties extends DeviceProperties {
|
|
|
10
26
|
gear?: number;
|
|
11
27
|
onStatusUpdate?: OnDeviceStartCallback;
|
|
12
28
|
}
|
|
29
|
+
export interface DaumPremiumRequest extends Request {
|
|
30
|
+
command: string;
|
|
31
|
+
payload?: string | Uint8Array;
|
|
32
|
+
}
|
|
33
|
+
export interface ResponseObject extends Response {
|
|
34
|
+
type: ResponseType;
|
|
35
|
+
cmd?: string;
|
|
36
|
+
data?: string;
|
|
37
|
+
error?: Error;
|
|
38
|
+
}
|
|
39
|
+
export type ResponseType = 'ACK' | 'NAK' | 'Response' | 'Error';
|
|
40
|
+
export type DaumPremiumCommsState = {
|
|
41
|
+
waitingForStart?: boolean;
|
|
42
|
+
waitingForACK?: boolean;
|
|
43
|
+
waitingForEnd?: boolean;
|
|
44
|
+
partialCmd?: any;
|
|
45
|
+
data: Queue<ResponseObject>;
|
|
46
|
+
};
|
|
@@ -1,2 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResponseTimeout = exports.BusyTimeout = exports.ACKTimeout = exports.CheckSumError = void 0;
|
|
4
|
+
class CheckSumError extends Error {
|
|
5
|
+
constructor() {
|
|
6
|
+
super();
|
|
7
|
+
this.message = 'checksum incorrect';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.CheckSumError = CheckSumError;
|
|
11
|
+
class ACKTimeout extends Error {
|
|
12
|
+
constructor() {
|
|
13
|
+
super();
|
|
14
|
+
this.message = 'ACK timeout';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.ACKTimeout = ACKTimeout;
|
|
18
|
+
class BusyTimeout extends Error {
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
this.message = 'BUSY timeout';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.BusyTimeout = BusyTimeout;
|
|
25
|
+
class ResponseTimeout extends Error {
|
|
26
|
+
constructor() {
|
|
27
|
+
super();
|
|
28
|
+
this.message = 'RESP timeout';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.ResponseTimeout = ResponseTimeout;
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
import { IncyclistBikeData } from "../../..";
|
|
2
3
|
import { Route } from "../../../types/route";
|
|
3
4
|
import { User } from "../../../types/user";
|
|
4
|
-
export declare
|
|
5
|
-
|
|
5
|
+
export declare const DEBUG_LOGGER: {
|
|
6
|
+
log: (e: any, ...args: any[]) => void;
|
|
7
|
+
logEvent: (event: any) => void;
|
|
8
|
+
};
|
|
9
|
+
export declare const validateHost: (host: string) => string;
|
|
10
|
+
export declare const validatePath: (path: string) => string;
|
|
11
|
+
export declare function bin2esc(arr: Uint8Array): Uint8Array;
|
|
12
|
+
export declare function esc2bin(arr: Uint8Array): Uint8Array;
|
|
6
13
|
export declare function checkSum(cmdArr: any, payload: any): string;
|
|
7
14
|
export declare function buildMessage(command: any, payload?: any): any[];
|
|
8
15
|
export declare function getMessageData(command: any): any[];
|
|
9
16
|
export declare function hexstr(arr: any, start?: any, len?: any): string;
|
|
10
|
-
export declare function ascii(c:
|
|
17
|
+
export declare function ascii(c: string): number;
|
|
11
18
|
export declare function getAsciiArrayFromStr(str: any): any[];
|
|
12
19
|
export declare enum ReservedCommands {
|
|
13
20
|
RESULT_RESET = 0,
|
|
@@ -40,20 +47,6 @@ export declare const FileTimeSupport: {
|
|
|
40
47
|
fromDate: (date: Date) => any;
|
|
41
48
|
};
|
|
42
49
|
export declare function routeToEpp(route: Route, date?: Date): Uint8Array;
|
|
43
|
-
export declare function parseTrainingData(payload: string):
|
|
44
|
-
time: number;
|
|
45
|
-
heartrate: number;
|
|
46
|
-
speed: number;
|
|
47
|
-
slope: number;
|
|
48
|
-
distanceInternal: number;
|
|
49
|
-
cadence: number;
|
|
50
|
-
power: number;
|
|
51
|
-
physEnergy: number;
|
|
52
|
-
realEnergy: number;
|
|
53
|
-
torque: number;
|
|
54
|
-
gear: number;
|
|
55
|
-
deviceState: number;
|
|
56
|
-
speedStatus: string;
|
|
57
|
-
};
|
|
50
|
+
export declare function parseTrainingData(payload: string): IncyclistBikeData;
|
|
58
51
|
export declare function getPersonData(user: User): Buffer;
|
|
59
52
|
export declare function parsePersonData(buffer: Buffer): User;
|
|
@@ -3,14 +3,31 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.parsePersonData = exports.getPersonData = exports.parseTrainingData = exports.routeToEpp = exports.FileTimeSupport = exports.getBikeType = exports.BikeType = exports.ReservedCommands = exports.getAsciiArrayFromStr = exports.ascii = exports.hexstr = exports.getMessageData = exports.buildMessage = exports.checkSum = exports.esc2bin = exports.bin2esc = void 0;
|
|
6
|
+
exports.parsePersonData = exports.getPersonData = exports.parseTrainingData = exports.routeToEpp = exports.FileTimeSupport = exports.getBikeType = exports.BikeType = exports.ReservedCommands = exports.getAsciiArrayFromStr = exports.ascii = exports.hexstr = exports.getMessageData = exports.buildMessage = exports.checkSum = exports.esc2bin = exports.bin2esc = exports.validatePath = exports.validateHost = exports.DEBUG_LOGGER = void 0;
|
|
7
7
|
const user_1 = require("../../../types/user");
|
|
8
8
|
const win32filetime_1 = __importDefault(require("win32filetime"));
|
|
9
9
|
const sum = (arr) => arr.reduce((a, b) => a + b, 0);
|
|
10
|
+
exports.DEBUG_LOGGER = {
|
|
11
|
+
log: (e, ...args) => console.log(e, ...args),
|
|
12
|
+
logEvent: (event) => console.log(JSON.stringify(event))
|
|
13
|
+
};
|
|
14
|
+
const validateHost = (host) => {
|
|
15
|
+
const ipParts = host.split('.');
|
|
16
|
+
if (ipParts.length > 1)
|
|
17
|
+
return ipParts.map(p => Number(p)).join('.');
|
|
18
|
+
return host;
|
|
19
|
+
};
|
|
20
|
+
exports.validateHost = validateHost;
|
|
21
|
+
const validatePath = (path) => {
|
|
22
|
+
const parts = path.split(':');
|
|
23
|
+
if (parts.length < 2)
|
|
24
|
+
return path;
|
|
25
|
+
const host = (0, exports.validateHost)(parts[0]);
|
|
26
|
+
const port = parts[1];
|
|
27
|
+
return `${host}:${port}`;
|
|
28
|
+
};
|
|
29
|
+
exports.validatePath = validatePath;
|
|
10
30
|
function bin2esc(arr) {
|
|
11
|
-
if (arr === undefined) {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
31
|
const res = [];
|
|
15
32
|
arr.forEach(v => {
|
|
16
33
|
switch (v) {
|
|
@@ -42,13 +59,10 @@ function bin2esc(arr) {
|
|
|
42
59
|
res.push(v);
|
|
43
60
|
}
|
|
44
61
|
});
|
|
45
|
-
return res;
|
|
62
|
+
return new Uint8Array(res);
|
|
46
63
|
}
|
|
47
64
|
exports.bin2esc = bin2esc;
|
|
48
65
|
function esc2bin(arr) {
|
|
49
|
-
if (arr === undefined) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
66
|
const res = [];
|
|
53
67
|
let escaped = false;
|
|
54
68
|
arr.forEach((v, idx) => {
|
|
@@ -84,7 +98,7 @@ function esc2bin(arr) {
|
|
|
84
98
|
res.push(v);
|
|
85
99
|
}
|
|
86
100
|
});
|
|
87
|
-
return res;
|
|
101
|
+
return new Uint8Array(res);
|
|
88
102
|
}
|
|
89
103
|
exports.esc2bin = esc2bin;
|
|
90
104
|
function checkSum(cmdArr, payload) {
|
|
@@ -147,8 +161,6 @@ function hexstr(arr, start, len) {
|
|
|
147
161
|
}
|
|
148
162
|
exports.hexstr = hexstr;
|
|
149
163
|
function ascii(c) {
|
|
150
|
-
if (c === undefined || c === null)
|
|
151
|
-
return;
|
|
152
164
|
return c.charCodeAt(0);
|
|
153
165
|
}
|
|
154
166
|
exports.ascii = ascii;
|
|
@@ -258,7 +270,6 @@ function routeToEpp(route, date) {
|
|
|
258
270
|
exports.routeToEpp = routeToEpp;
|
|
259
271
|
function parseTrainingData(payload) {
|
|
260
272
|
const GS = 0x1D;
|
|
261
|
-
const speedVals = ['ok', 'too low', 'too high'];
|
|
262
273
|
const gearVal = (v) => v > 0 ? v - 1 : undefined;
|
|
263
274
|
const vals = payload.split(String.fromCharCode(GS));
|
|
264
275
|
const data = {
|
|
@@ -267,15 +278,11 @@ function parseTrainingData(payload) {
|
|
|
267
278
|
speed: parseFloat(vals[2]) * 3.6,
|
|
268
279
|
slope: parseFloat(vals[3]),
|
|
269
280
|
distanceInternal: parseInt(vals[4]),
|
|
270
|
-
|
|
281
|
+
pedalRpm: parseFloat(vals[5]),
|
|
271
282
|
power: parseInt(vals[6]),
|
|
272
|
-
physEnergy: parseFloat(vals[7]),
|
|
273
|
-
realEnergy: parseFloat(vals[8]),
|
|
274
|
-
torque: parseFloat(vals[9]),
|
|
275
283
|
gear: gearVal(parseInt(vals[10])),
|
|
276
|
-
deviceState: parseInt(vals[11]),
|
|
277
|
-
speedStatus: speedVals[parseInt(vals[12])],
|
|
278
284
|
};
|
|
285
|
+
data.isPedalling = (data.pedalRpm > 0);
|
|
279
286
|
return data;
|
|
280
287
|
}
|
|
281
288
|
exports.parseTrainingData = parseTrainingData;
|
|
@@ -58,7 +58,7 @@ class SinglePathScanner {
|
|
|
58
58
|
return;
|
|
59
59
|
this.isScanning = true;
|
|
60
60
|
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
61
|
-
this.logEvent({ message: 'starting scan', path: this.path });
|
|
61
|
+
this.logEvent({ message: 'starting scan', path: this.path, interface: this.serial.getName() });
|
|
62
62
|
this.serial.scanEvents.on('timeout', () => this.onStopRequest(resolve));
|
|
63
63
|
this.serial.scanEvents.on('stop', () => this.onStopRequest(resolve));
|
|
64
64
|
let found = false;
|
|
@@ -78,6 +78,7 @@ class SinglePathScanner {
|
|
|
78
78
|
if (found) {
|
|
79
79
|
this.isFound = true;
|
|
80
80
|
const name = adapter.getName();
|
|
81
|
+
yield adapter.close();
|
|
81
82
|
resolve(Object.assign(Object.assign({}, adapterSettings), { name }));
|
|
82
83
|
}
|
|
83
84
|
yield (0, utils_1.sleep)(100);
|
|
@@ -166,9 +167,11 @@ class SerialInterface extends events_1.default {
|
|
|
166
167
|
}
|
|
167
168
|
connect() {
|
|
168
169
|
return __awaiter(this, void 0, void 0, function* () {
|
|
170
|
+
this.logEvent({ message: 'connecting', interface: this.ifaceName });
|
|
169
171
|
const binding = serialport_1.default.getInstance().getBinding(this.ifaceName);
|
|
170
172
|
if (!binding || !this.binding) {
|
|
171
173
|
this.connected = false;
|
|
174
|
+
this.logEvent({ message: 'connecting error', interface: this.ifaceName, reason: 'no binfing found' });
|
|
172
175
|
return false;
|
|
173
176
|
}
|
|
174
177
|
try {
|
|
@@ -178,6 +181,7 @@ class SerialInterface extends events_1.default {
|
|
|
178
181
|
return true;
|
|
179
182
|
}
|
|
180
183
|
catch (err) {
|
|
184
|
+
this.logEvent({ message: 'connecting error', interface: this.ifaceName, reason: err.message });
|
|
181
185
|
this.connected = false;
|
|
182
186
|
return false;
|
|
183
187
|
}
|
|
@@ -210,7 +214,7 @@ class SerialInterface extends events_1.default {
|
|
|
210
214
|
}
|
|
211
215
|
return new Promise((resolve) => {
|
|
212
216
|
port.once('error', (err) => {
|
|
213
|
-
this.logEvent({ message: 'error', path, error: err.message || err });
|
|
217
|
+
this.logEvent({ message: 'error', path, error: err.message || err, stack: err.stack });
|
|
214
218
|
port.removeAllListeners();
|
|
215
219
|
resolve(null);
|
|
216
220
|
});
|
|
@@ -273,14 +277,15 @@ class SerialInterface extends events_1.default {
|
|
|
273
277
|
}
|
|
274
278
|
this.isScanning = true;
|
|
275
279
|
let attemptNo = 0;
|
|
280
|
+
const isTcpip = this.getName() === 'tcpip';
|
|
276
281
|
do {
|
|
277
282
|
if (attemptNo === 0)
|
|
278
|
-
this.logEvent({ message: 'checking for ports', port, excludes: this.inUse });
|
|
283
|
+
this.logEvent({ message: 'checking for ports', interface: this.ifaceName, port, excludes: this.inUse });
|
|
279
284
|
else
|
|
280
|
-
this.logEvent({ message: 'checking for ports retry', retry: attemptNo });
|
|
285
|
+
this.logEvent({ message: 'checking for ports retry', interface: this.ifaceName, retry: attemptNo });
|
|
281
286
|
attemptNo++;
|
|
282
287
|
try {
|
|
283
|
-
if (
|
|
288
|
+
if (isTcpip) {
|
|
284
289
|
const _binding = binding;
|
|
285
290
|
paths = (yield _binding.list(port, this.inUse)) || [];
|
|
286
291
|
}
|
|
@@ -289,8 +294,9 @@ class SerialInterface extends events_1.default {
|
|
|
289
294
|
}
|
|
290
295
|
}
|
|
291
296
|
catch (err) {
|
|
292
|
-
|
|
297
|
+
this.logEvent({ message: 'error', fn: 'scan#detect ports', error: err.message, interface: this.ifaceName, port, excludes: this.inUse });
|
|
293
298
|
}
|
|
299
|
+
paths = paths.filter(p => !this.inUse.includes(p.path));
|
|
294
300
|
if (!paths || paths.length === 0) {
|
|
295
301
|
this.logEvent({ message: 'scanning: no ports detected', interface: this.ifaceName, paths: paths.map(p => p.path), timeout });
|
|
296
302
|
yield (0, utils_1.sleep)(1000);
|
|
@@ -298,7 +304,6 @@ class SerialInterface extends events_1.default {
|
|
|
298
304
|
if (Date.now() > toExpiresAt)
|
|
299
305
|
timeOutExpired = true;
|
|
300
306
|
} while (this.isScanning && !timeOutExpired && paths.length === 0);
|
|
301
|
-
paths = paths.filter(p => !this.inUse.includes(p.path));
|
|
302
307
|
if (paths.length === 0) {
|
|
303
308
|
this.logEvent({ message: 'nothing to scan ' });
|
|
304
309
|
if (this.toScan) {
|
|
@@ -307,19 +312,20 @@ class SerialInterface extends events_1.default {
|
|
|
307
312
|
}
|
|
308
313
|
return [];
|
|
309
314
|
}
|
|
310
|
-
this.logEvent({ message: 'scanning on ', paths: paths.map(p => p.path), timeout });
|
|
315
|
+
this.logEvent({ message: 'scanning on ', interface: this.ifaceName, paths: paths.map(p => p.path).join(','), timeout });
|
|
311
316
|
const scanners = paths.map(p => new SinglePathScanner(p.path, this, Object.assign(Object.assign({}, props), { logger: this.logger })));
|
|
312
317
|
try {
|
|
313
318
|
yield Promise.all(scanners.map(s => s.scan()
|
|
314
|
-
.then(device => {
|
|
319
|
+
.then((device) => __awaiter(this, void 0, void 0, function* () {
|
|
315
320
|
if (device) {
|
|
316
321
|
const adapter = adapter_factory_1.default.getInstance().createInstance(device);
|
|
317
322
|
const path = adapter.getPort();
|
|
318
323
|
this.inUse.push(path);
|
|
324
|
+
yield adapter.stop();
|
|
319
325
|
detected.push(device);
|
|
320
326
|
this.emit('device', device);
|
|
321
327
|
}
|
|
322
|
-
})
|
|
328
|
+
}))
|
|
323
329
|
.catch()));
|
|
324
330
|
}
|
|
325
331
|
catch (err) {
|
|
@@ -346,6 +352,7 @@ class SerialInterface extends events_1.default {
|
|
|
346
352
|
clearTimeout(this.toScan);
|
|
347
353
|
this.toScan = null;
|
|
348
354
|
}
|
|
355
|
+
this.isScanning = false;
|
|
349
356
|
this.scanEvents.emit('stop');
|
|
350
357
|
return true;
|
|
351
358
|
});
|
package/lib/types/adapter.d.ts
CHANGED
|
@@ -5,8 +5,10 @@ import { IncyclistCapability } from "./capabilities";
|
|
|
5
5
|
import { DeviceData } from "./data";
|
|
6
6
|
import { DeviceProperties, DeviceSettings } from "./device";
|
|
7
7
|
import { User } from "./user";
|
|
8
|
+
import { EventLogger } from "gd-eventlog";
|
|
8
9
|
export type OnDeviceDataCallback = (data: DeviceData) => void;
|
|
9
10
|
export interface IncyclistDeviceAdapter extends EventEmitter {
|
|
11
|
+
getLogger(): EventLogger;
|
|
10
12
|
connect(): Promise<boolean>;
|
|
11
13
|
close(): Promise<boolean>;
|
|
12
14
|
check(): Promise<boolean>;
|
package/lib/types/device.d.ts
CHANGED
|
@@ -9,11 +9,22 @@ export declare const INTERFACE: {
|
|
|
9
9
|
USB: string;
|
|
10
10
|
SIMULATOR: string;
|
|
11
11
|
};
|
|
12
|
+
export type DeviceType = 'race' | 'mountain' | 'triathlon';
|
|
12
13
|
export type Device = {
|
|
13
14
|
getID(): string;
|
|
14
15
|
getName(): string;
|
|
15
16
|
getInterface(): string;
|
|
16
17
|
};
|
|
18
|
+
export type DaumBikeData = {
|
|
19
|
+
cadence: number;
|
|
20
|
+
speed: number;
|
|
21
|
+
power: number;
|
|
22
|
+
heartrate: number;
|
|
23
|
+
distanceInternal: number;
|
|
24
|
+
gear: number;
|
|
25
|
+
time: number;
|
|
26
|
+
slope?: number;
|
|
27
|
+
};
|
|
17
28
|
export type DeviceProperties = {
|
|
18
29
|
user?: User;
|
|
19
30
|
userWeight?: number;
|