incyclist-devices 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/CyclingMode.d.ts +72 -0
- package/lib/CyclingMode.js +66 -0
- package/lib/Device.d.ts +48 -10
- package/lib/Device.js +9 -8
- package/lib/DeviceProtocol.d.ts +40 -12
- package/lib/DeviceProtocol.js +16 -16
- package/lib/DeviceRegistry.d.ts +4 -4
- package/lib/DeviceRegistry.js +10 -10
- package/lib/DeviceSupport.d.ts +4 -3
- package/lib/DeviceSupport.js +32 -8
- package/lib/ant/AntAdapter.d.ts +7 -3
- package/lib/ant/AntAdapter.js +23 -3
- package/lib/ant/AntScanner.d.ts +15 -6
- package/lib/ant/AntScanner.js +372 -128
- package/lib/ant/antfe/AntFEAdapter.d.ts +1 -1
- package/lib/ant/antfe/AntFEAdapter.js +191 -92
- package/lib/ant/anthrm/AntHrmAdapter.d.ts +3 -1
- package/lib/ant/anthrm/AntHrmAdapter.js +70 -19
- package/lib/ant/utils.js +2 -1
- package/lib/calculations.d.ts +12 -13
- package/lib/calculations.js +88 -125
- package/lib/daum/DaumAdapter.d.ts +29 -6
- package/lib/daum/DaumAdapter.js +219 -96
- package/lib/daum/ERGCyclingMode.d.ts +28 -0
- package/lib/daum/ERGCyclingMode.js +207 -0
- package/lib/daum/PowerMeterCyclingMode.d.ts +18 -0
- package/lib/daum/PowerMeterCyclingMode.js +79 -0
- package/lib/daum/SmartTrainerCyclingMode.d.ts +41 -0
- package/lib/daum/SmartTrainerCyclingMode.js +344 -0
- package/lib/daum/classic/DaumClassicAdapter.d.ts +3 -1
- package/lib/daum/classic/DaumClassicAdapter.js +46 -32
- package/lib/daum/classic/DaumClassicCyclingMode.d.ts +13 -0
- package/lib/daum/classic/DaumClassicCyclingMode.js +98 -0
- package/lib/daum/classic/DaumClassicProtocol.d.ts +5 -3
- package/lib/daum/classic/DaumClassicProtocol.js +47 -8
- package/lib/daum/classic/ERGCyclingMode.d.ts +23 -0
- package/lib/daum/classic/ERGCyclingMode.js +171 -0
- package/lib/daum/classic/bike.d.ts +41 -37
- package/lib/daum/classic/bike.js +86 -53
- package/lib/daum/classic/utils.d.ts +3 -3
- package/lib/daum/classic/utils.js +18 -10
- package/lib/daum/indoorbike.d.ts +2 -1
- package/lib/daum/indoorbike.js +23 -21
- package/lib/daum/premium/DaumPremiumAdapter.d.ts +2 -2
- package/lib/daum/premium/DaumPremiumAdapter.js +30 -20
- package/lib/daum/premium/DaumPremiumProtocol.d.ts +11 -2
- package/lib/daum/premium/DaumPremiumProtocol.js +57 -10
- package/lib/daum/premium/bike.d.ts +63 -52
- package/lib/daum/premium/bike.js +254 -207
- package/lib/daum/premium/tcpserial.d.ts +18 -14
- package/lib/daum/premium/tcpserial.js +44 -20
- package/lib/daum/premium/utils.d.ts +2 -2
- package/lib/simulator/Simulator.d.ts +13 -7
- package/lib/simulator/Simulator.js +62 -21
- package/lib/utils.d.ts +3 -1
- package/lib/utils.js +39 -18
- package/package.json +12 -11
- package/lib/ant/AntScanner.unit.tests.d.ts +0 -1
- package/lib/ant/AntScanner.unit.tests.js +0 -25
- package/lib/ant/antfe/AntFEProcessor.d.ts +0 -40
- package/lib/ant/antfe/AntFEProcessor.js +0 -238
- package/lib/ant/antfe/AntHrmProtocol.d.ts +0 -9
- package/lib/ant/antfe/AntHrmProtocol.js +0 -30
- package/lib/ant/antfe/FEDevice.d.ts +0 -1
- package/lib/ant/antfe/FEDevice.js +0 -7
- package/lib/ant/antfe/bike.d.ts +0 -47
- package/lib/ant/antfe/bike.js +0 -602
- package/lib/ant/anthrm/anthrm.d.ts +0 -33
- package/lib/ant/anthrm/anthrm.js +0 -523
- package/lib/simulator/Simulator.unit.tests.d.ts +0 -1
- package/lib/simulator/Simulator.unit.tests.js +0 -79
|
@@ -20,7 +20,7 @@ export default class AntFEAdapter extends AntAdapter {
|
|
|
20
20
|
onDeviceEvent(data: any): void;
|
|
21
21
|
updateData(data: any, deviceData: any): any;
|
|
22
22
|
transformData(bikeData: any): any;
|
|
23
|
-
start(props?: any): Promise<
|
|
23
|
+
start(props?: any): Promise<any>;
|
|
24
24
|
stop(): Promise<boolean>;
|
|
25
25
|
sendUpdate(request: any): Promise<void>;
|
|
26
26
|
send(msg: any, logStr: any, callback?: any, expectedResponse?: any): void;
|
|
@@ -8,19 +8,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
15
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
13
|
-
const AntAdapter_1 = require("../AntAdapter");
|
|
16
|
+
const AntAdapter_1 = __importDefault(require("../AntAdapter"));
|
|
14
17
|
const utils_1 = require("../utils");
|
|
15
18
|
const utils_2 = require("../../utils");
|
|
16
19
|
const floatVal = (d) => d ? parseFloat(d) : d;
|
|
17
20
|
const intVal = (d) => d ? parseInt(d) : d;
|
|
21
|
+
const hex = (v) => Math.abs(v).toString(16).toUpperCase();
|
|
18
22
|
const TIMEOUT_ACK = 5000;
|
|
19
23
|
const TIMEOUT_START = 10000;
|
|
24
|
+
const TIMEOUT_ATTACH = 3000;
|
|
25
|
+
const DEFAULT_USER_WEIGHT = 75;
|
|
26
|
+
const DEFAULT_BIKE_WEIGHT = 12.75;
|
|
20
27
|
class AntFEAdapter extends AntAdapter_1.default {
|
|
21
28
|
constructor(DeviceID, port, stick, protocol) {
|
|
22
29
|
super(protocol);
|
|
23
30
|
this.logger = new gd_eventlog_1.EventLogger('Ant+FE');
|
|
31
|
+
this.logger.logEvent({ message: 'Ant+FE Adapter created', DeviceID, port });
|
|
24
32
|
this.deviceID = DeviceID;
|
|
25
33
|
this.port = port;
|
|
26
34
|
this.stick = stick;
|
|
@@ -44,18 +52,20 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
44
52
|
getDisplayName() {
|
|
45
53
|
const { DeviceID, ManId, ComputedHeartRate } = this.deviceData;
|
|
46
54
|
const hrmStr = ComputedHeartRate ? ` (${ComputedHeartRate})` : '';
|
|
47
|
-
return `${utils_1.getBrand(ManId)} FE ${DeviceID}${hrmStr}`;
|
|
55
|
+
return `${(0, utils_1.getBrand)(ManId)} FE ${DeviceID}${hrmStr}`;
|
|
48
56
|
}
|
|
49
57
|
onAttached() {
|
|
58
|
+
this.logger.logEvent({ message: 'Device connected' });
|
|
50
59
|
this.connected = true;
|
|
51
60
|
}
|
|
52
61
|
onDeviceData(deviceData) {
|
|
53
|
-
if (!this.started)
|
|
62
|
+
if (!this.started || this.isStopped())
|
|
54
63
|
return;
|
|
55
64
|
this.deviceData = deviceData;
|
|
56
65
|
try {
|
|
57
66
|
if (this.onDataFn && !(this.ignoreHrm && this.ignoreBike && this.ignorePower) && !this.paused) {
|
|
58
67
|
if (!this.lastUpdate || (Date.now() - this.lastUpdate) > this.updateFrequency) {
|
|
68
|
+
this.logger.logEvent({ message: 'onDeviceData', data: deviceData });
|
|
59
69
|
this.data = this.updateData(this.data, deviceData);
|
|
60
70
|
const data = this.transformData(this.data);
|
|
61
71
|
this.onDataFn(data);
|
|
@@ -68,40 +78,45 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
68
78
|
}
|
|
69
79
|
onDeviceEvent(data) {
|
|
70
80
|
try {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
81
|
+
const cmdInfo = this.currentCmd;
|
|
82
|
+
if (!cmdInfo)
|
|
83
|
+
return;
|
|
84
|
+
const msg = cmdInfo.msg.readUInt8(2);
|
|
74
85
|
const Constants = this.getProtocol().getAnt().Constants;
|
|
75
86
|
const { expectedResponse } = cmdInfo;
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
this.currentCmd.response = { success: true };
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
if (this.currentCmd !== undefined && data.message === 1 && expectedResponse !== undefined && data.code === expectedResponse) {
|
|
89
|
-
this.currentCmd.response = { success: true };
|
|
90
|
-
return;
|
|
87
|
+
if (data.message === msg) {
|
|
88
|
+
if (expectedResponse === undefined && data.code === Constants.EVENT_TRANSFER_TX_COMPLETED) {
|
|
89
|
+
this.currentCmd.response = { success: true, message: hex(data.message), code: hex(data.code) };
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (expectedResponse === undefined && data.code !== Constants.EVENT_TRANSFER_TX_COMPLETED) {
|
|
93
|
+
this.currentCmd.response = { success: false, message: hex(data.message), code: hex(data.code) };
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
91
96
|
}
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
if (data.message === 1) {
|
|
98
|
+
if (expectedResponse !== undefined && data.code === expectedResponse) {
|
|
99
|
+
this.currentCmd.response = { success: true, message: hex(data.message), code: hex(data.code) };
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (expectedResponse === undefined && (data.code === Constants.EVENT_TRANSFER_TX_COMPLETED || data.code === 3)) {
|
|
103
|
+
this.currentCmd.response = { success: true, message: hex(data.message), code: hex(data.code) };
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (data.code === Constants.EVENT_TRANSFER_TX_FAILED || data.code === Constants.EVENT_CHANNEL_COLLISION) {
|
|
107
|
+
this.currentCmd.response = { success: false, message: hex(data.message), code: hex(data.code) };
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
96
110
|
}
|
|
97
111
|
if (this.currentCmd !== undefined && data.message === Constants.MESSAGE_CHANNEL_ACKNOWLEDGED_DATA && data.code === 31) {
|
|
98
112
|
this.logger.log("could not send (TRANSFER_IN_PROGRESS)");
|
|
113
|
+
this.currentCmd.response = { success: false, message: hex(data.message), code: hex(data.code) };
|
|
99
114
|
return;
|
|
100
115
|
}
|
|
101
|
-
this.logger.logEvent({ message: "Incoming Event ", event: data });
|
|
116
|
+
this.logger.logEvent({ message: "Incoming Event ", event: { message: hex(data.message), code: hex(data.code) } });
|
|
102
117
|
}
|
|
103
118
|
catch (err) {
|
|
104
|
-
this.logger.logEvent({ message: 'Error', fn: 'parseEvent', data:
|
|
119
|
+
this.logger.logEvent({ message: 'Error', fn: 'parseEvent', event: { message: hex(data.message), code: hex(data.code) }, error: err.message || err });
|
|
105
120
|
}
|
|
106
121
|
}
|
|
107
122
|
updateData(data, deviceData) {
|
|
@@ -112,10 +127,18 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
112
127
|
data.power = (deviceData.InstantaneousPower !== undefined ? deviceData.InstantaneousPower : data.power);
|
|
113
128
|
data.pedalRpm = (deviceData.Cadence !== undefined ? deviceData.Cadence : data.pedalRpm);
|
|
114
129
|
data.heartrate = (deviceData.HeartRate !== undefined ? deviceData.HeartRate : data.heartrate);
|
|
115
|
-
if (deviceData.Distance !== undefined) {
|
|
130
|
+
if (deviceData.Distance !== undefined && deviceData.Distance !== 0) {
|
|
116
131
|
data.distanceInternal = deviceData.Distance - data.distanceOffs;
|
|
117
132
|
data.distance = data.distanceInternal / 1000;
|
|
118
133
|
}
|
|
134
|
+
else {
|
|
135
|
+
if (this.lastUpdate && deviceData.Cadence !== undefined && deviceData.Cadence > 0 && data.speed) {
|
|
136
|
+
const t = (Date.now() - this.lastUpdate) / 1000;
|
|
137
|
+
const prevDistance = data.distanceInternal || 0;
|
|
138
|
+
data.distanceInternal = Math.round(data.speed / 3.6 * t) + prevDistance;
|
|
139
|
+
data.distance = data.distanceInternal / 1000;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
119
142
|
return data;
|
|
120
143
|
}
|
|
121
144
|
transformData(bikeData) {
|
|
@@ -148,102 +171,156 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
148
171
|
return data;
|
|
149
172
|
}
|
|
150
173
|
start(props) {
|
|
174
|
+
const _super = Object.create(null, {
|
|
175
|
+
start: { get: () => super.start }
|
|
176
|
+
});
|
|
151
177
|
return __awaiter(this, void 0, void 0, function* () {
|
|
178
|
+
yield _super.start.call(this, props);
|
|
152
179
|
this.logger.logEvent({ message: 'start()' });
|
|
153
|
-
const
|
|
180
|
+
const args = props || {};
|
|
154
181
|
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
155
|
-
if (this.ignoreHrm && this.ignoreBike && this.ignorePower)
|
|
182
|
+
if (this.ignoreHrm && this.ignoreBike && this.ignorePower) {
|
|
183
|
+
this.logger.logEvent({ message: 'start() not done: bike disabled' });
|
|
156
184
|
return resolve(false);
|
|
185
|
+
}
|
|
157
186
|
if (this.starting) {
|
|
187
|
+
this.logger.logEvent({ message: 'start() not done: bike starting' });
|
|
158
188
|
return resolve(false);
|
|
159
189
|
}
|
|
160
190
|
if (this.started) {
|
|
191
|
+
this.logger.logEvent({ message: 'start() done: bike was already started' });
|
|
192
|
+
this.startWorker();
|
|
161
193
|
return resolve(true);
|
|
162
194
|
}
|
|
163
195
|
this.starting = true;
|
|
164
196
|
const Ant = this.getProtocol().getAnt();
|
|
165
197
|
const protocol = this.getProtocol();
|
|
166
|
-
|
|
167
|
-
|
|
198
|
+
let start = Date.now();
|
|
199
|
+
let timeout = start + (args.timeout || TIMEOUT_ATTACH);
|
|
200
|
+
const ivAttach = setInterval(() => {
|
|
201
|
+
if (Date.now() > timeout) {
|
|
202
|
+
clearInterval(ivAttach);
|
|
203
|
+
this.starting = false;
|
|
204
|
+
reject(new Error('timeout'));
|
|
205
|
+
}
|
|
206
|
+
if (this.isStopped()) {
|
|
207
|
+
clearInterval(ivAttach);
|
|
208
|
+
this.starting = false;
|
|
209
|
+
reject(new Error('stopped'));
|
|
210
|
+
}
|
|
211
|
+
}, 100);
|
|
212
|
+
try {
|
|
213
|
+
if (!this.connected) {
|
|
214
|
+
this.logger.logEvent({ message: 'attach device ...' });
|
|
215
|
+
yield protocol.attachSensors(this, Ant.FitnessEquipmentSensor, 'fitnessData');
|
|
216
|
+
}
|
|
217
|
+
clearInterval(ivAttach);
|
|
168
218
|
this.startWorker();
|
|
169
219
|
const tsStart = Date.now();
|
|
170
220
|
const iv = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
171
221
|
if (this.connected) {
|
|
172
222
|
clearInterval(iv);
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
223
|
+
let status = {
|
|
224
|
+
trackResistanceSent: false,
|
|
225
|
+
userSent: false,
|
|
226
|
+
};
|
|
227
|
+
(0, utils_2.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () {
|
|
228
|
+
if (this.isStopped())
|
|
229
|
+
resolve(false);
|
|
230
|
+
try {
|
|
231
|
+
if (!status.trackResistanceSent) {
|
|
232
|
+
yield this.sendTrackResistance(0.0);
|
|
233
|
+
status.trackResistanceSent = true;
|
|
234
|
+
}
|
|
235
|
+
if (!status.userSent) {
|
|
236
|
+
yield this.sendUserConfiguration(args.userWeight || DEFAULT_USER_WEIGHT, args.bikeWeight || DEFAULT_BIKE_WEIGHT, args.wheelDiameter, args.gearRatio);
|
|
237
|
+
status.userSent = true;
|
|
238
|
+
}
|
|
239
|
+
this.started = true;
|
|
240
|
+
this.starting = false;
|
|
241
|
+
resolve(true);
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
throw (new Error(`could not start device, reason:${err.message || err}`));
|
|
245
|
+
}
|
|
246
|
+
}), 5, 1500)
|
|
247
|
+
.catch(err => {
|
|
248
|
+
this.logger.logEvent({ message: 'start() error', error: err.message || err });
|
|
249
|
+
this.starting = false;
|
|
250
|
+
reject(err);
|
|
251
|
+
});
|
|
183
252
|
}
|
|
184
253
|
else if ((Date.now() - tsStart) > TIMEOUT_START) {
|
|
185
254
|
clearInterval(iv);
|
|
186
|
-
this.started = true;
|
|
187
255
|
try {
|
|
188
256
|
yield protocol.detachSensor(this);
|
|
189
257
|
}
|
|
190
258
|
catch (err) { }
|
|
259
|
+
this.started = false;
|
|
191
260
|
this.starting = false;
|
|
192
|
-
reject(new Error('timeout'));
|
|
261
|
+
reject(new Error('could not start device, reason:timeout'));
|
|
193
262
|
}
|
|
194
263
|
}), 50);
|
|
195
|
-
}
|
|
196
|
-
|
|
264
|
+
}
|
|
265
|
+
catch (err) {
|
|
266
|
+
this.logger.logEvent({ message: 'start() error', error: err.message });
|
|
197
267
|
this.starting = false;
|
|
198
|
-
reject(err);
|
|
199
|
-
}
|
|
268
|
+
reject(new Error(`could not start device, reason:${err.message}`));
|
|
269
|
+
}
|
|
200
270
|
}));
|
|
201
271
|
});
|
|
202
272
|
}
|
|
203
273
|
stop() {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
this.
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
274
|
+
const _super = Object.create(null, {
|
|
275
|
+
stop: { get: () => super.stop }
|
|
276
|
+
});
|
|
277
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
278
|
+
yield _super.stop.call(this);
|
|
279
|
+
this.logger.logEvent({ message: 'stop()' });
|
|
280
|
+
this.stopWorker();
|
|
281
|
+
const Messages = this.getProtocol().getAnt().Messages;
|
|
282
|
+
const stick = this.stick;
|
|
283
|
+
const channel = this.channel;
|
|
284
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
285
|
+
this.starting = false;
|
|
286
|
+
return resolve(true);
|
|
287
|
+
if (!this.started && !this.connected)
|
|
288
|
+
return resolve(false);
|
|
289
|
+
try {
|
|
290
|
+
stick.write(Messages.openChannel(channel));
|
|
291
|
+
const protocol = this.getProtocol();
|
|
292
|
+
yield protocol.detachSensor(this);
|
|
293
|
+
this.started = false;
|
|
294
|
+
this.connected = false;
|
|
295
|
+
this.logger.logEvent({ message: 'stop() finished' });
|
|
296
|
+
resolve(true);
|
|
297
|
+
}
|
|
298
|
+
catch (err) {
|
|
299
|
+
this.connected = false;
|
|
300
|
+
this.logger.logEvent({ message: 'stop() error', error: err.message });
|
|
301
|
+
reject(err);
|
|
302
|
+
}
|
|
303
|
+
}));
|
|
304
|
+
});
|
|
225
305
|
}
|
|
226
306
|
sendUpdate(request) {
|
|
227
307
|
return __awaiter(this, void 0, void 0, function* () {
|
|
228
308
|
this.logger.logEvent({ message: "sendBikeUpdate():", request });
|
|
229
309
|
try {
|
|
310
|
+
const isReset = (!request || request.reset || Object.keys(request).length === 0);
|
|
230
311
|
if (request.slope !== undefined) {
|
|
231
|
-
yield this.sendTrackResistance(request.slope);
|
|
312
|
+
yield (0, utils_2.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () { return yield this.sendTrackResistance(request.slope); }), 2, 100);
|
|
232
313
|
}
|
|
233
314
|
if (request.targetPower !== undefined) {
|
|
234
|
-
yield this.sendTargetPower(request.targetPower);
|
|
315
|
+
yield (0, utils_2.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () { return yield this.sendTargetPower(request.targetPower); }), 2, 100);
|
|
235
316
|
}
|
|
236
317
|
else if (request.maxPower !== undefined) {
|
|
237
318
|
if (this.data.power && this.data.power > request.maxPower)
|
|
238
|
-
yield this.sendTargetPower(request.maxPower);
|
|
319
|
+
yield (0, utils_2.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () { return yield this.sendTargetPower(request.maxPower); }), 2, 100);
|
|
239
320
|
}
|
|
240
321
|
else if (request.minPower !== undefined) {
|
|
241
322
|
if (this.data.power && this.data.power < request.minPower)
|
|
242
|
-
yield this.sendTargetPower(request.minPower);
|
|
243
|
-
}
|
|
244
|
-
if (request.maxHrm !== undefined) {
|
|
245
|
-
}
|
|
246
|
-
if (request.minHrm !== undefined) {
|
|
323
|
+
yield (0, utils_2.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () { return yield this.sendTargetPower(request.minPower); }), 2, 100);
|
|
247
324
|
}
|
|
248
325
|
}
|
|
249
326
|
catch (err) {
|
|
@@ -267,10 +344,20 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
267
344
|
});
|
|
268
345
|
}
|
|
269
346
|
startWorker() {
|
|
347
|
+
this.logger.logEvent({ message: 'startWorker()' });
|
|
270
348
|
if (this.queue === undefined) {
|
|
271
349
|
this.queue = new utils_2.Queue();
|
|
272
350
|
}
|
|
273
|
-
|
|
351
|
+
if (this.workerId)
|
|
352
|
+
return;
|
|
353
|
+
this.workerId = setInterval(() => {
|
|
354
|
+
try {
|
|
355
|
+
this.sendFromQueue();
|
|
356
|
+
}
|
|
357
|
+
catch (err) {
|
|
358
|
+
this.logger.logEvent({ message: 'sendFromQueue error', error: err.message });
|
|
359
|
+
}
|
|
360
|
+
}, 10);
|
|
274
361
|
}
|
|
275
362
|
stopWorker() {
|
|
276
363
|
if (!this.workerId)
|
|
@@ -280,8 +367,9 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
280
367
|
this.workerId = undefined;
|
|
281
368
|
}
|
|
282
369
|
sendFromQueue() {
|
|
283
|
-
if (this.queue === undefined)
|
|
370
|
+
if (this.queue === undefined) {
|
|
284
371
|
return;
|
|
372
|
+
}
|
|
285
373
|
if (this.currentCmd !== undefined) {
|
|
286
374
|
const cmdInfo = this.currentCmd;
|
|
287
375
|
if (this.currentCmd.response === undefined) {
|
|
@@ -304,7 +392,7 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
304
392
|
this.currentCmd = undefined;
|
|
305
393
|
if (callback !== undefined) {
|
|
306
394
|
if (response && response.success === false) {
|
|
307
|
-
callback(undefined, new Error(
|
|
395
|
+
callback(undefined, new Error(`ANT error ${response.code}`));
|
|
308
396
|
return;
|
|
309
397
|
}
|
|
310
398
|
callback(response);
|
|
@@ -317,14 +405,17 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
317
405
|
this.currentCmd = this.queue.dequeue();
|
|
318
406
|
this.currentCmd.tsStart = Date.now();
|
|
319
407
|
const { msg, logStr } = this.currentCmd;
|
|
320
|
-
this.logger.logEvent({ message: "sending", cmd: logStr, msg: utils_2.hexstr(msg), queueSize: this.queue.size() });
|
|
321
|
-
this.stick
|
|
408
|
+
this.logger.logEvent({ message: "sending", cmd: logStr, msg: (0, utils_2.hexstr)(msg), queueSize: this.queue.size() });
|
|
409
|
+
if (this.stick)
|
|
410
|
+
this.stick.write(msg);
|
|
322
411
|
}
|
|
323
412
|
}
|
|
324
413
|
sendUserConfiguration(userWeight, bikeWeight, wheelDiameter, gearRatio) {
|
|
325
|
-
if (!this.connected)
|
|
326
|
-
return;
|
|
327
414
|
return new Promise((resolve, reject) => {
|
|
415
|
+
if (!this.connected)
|
|
416
|
+
reject(new Error('not connected'));
|
|
417
|
+
if (!this.queue)
|
|
418
|
+
this.startWorker();
|
|
328
419
|
var payload = [];
|
|
329
420
|
payload.push(this.channel);
|
|
330
421
|
const logStr = `sendUserConfiguration(${userWeight},${bikeWeight},${wheelDiameter},${gearRatio})`;
|
|
@@ -363,9 +454,11 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
363
454
|
});
|
|
364
455
|
}
|
|
365
456
|
sendBasicResistance(resistance) {
|
|
366
|
-
if (!this.connected)
|
|
367
|
-
return;
|
|
368
457
|
return new Promise((resolve, reject) => {
|
|
458
|
+
if (!this.connected)
|
|
459
|
+
reject(new Error('not connected'));
|
|
460
|
+
if (!this.queue)
|
|
461
|
+
this.startWorker();
|
|
369
462
|
var payload = [];
|
|
370
463
|
payload.push(this.channel);
|
|
371
464
|
const logStr = `sendBasicResistance(${resistance})`;
|
|
@@ -389,9 +482,11 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
389
482
|
});
|
|
390
483
|
}
|
|
391
484
|
sendTargetPower(power) {
|
|
392
|
-
if (!this.connected)
|
|
393
|
-
return;
|
|
394
485
|
return new Promise((resolve, reject) => {
|
|
486
|
+
if (!this.connected)
|
|
487
|
+
reject(new Error('not connected'));
|
|
488
|
+
if (!this.queue)
|
|
489
|
+
this.startWorker();
|
|
395
490
|
var payload = [];
|
|
396
491
|
payload.push(this.channel);
|
|
397
492
|
const logStr = `sendTargetPower(${power})`;
|
|
@@ -415,9 +510,11 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
415
510
|
});
|
|
416
511
|
}
|
|
417
512
|
sendWindResistance(windCoeff, windSpeed, draftFactor) {
|
|
418
|
-
if (!this.connected)
|
|
419
|
-
return;
|
|
420
513
|
return new Promise((resolve, reject) => {
|
|
514
|
+
if (!this.connected)
|
|
515
|
+
reject(new Error('not connected'));
|
|
516
|
+
if (!this.queue)
|
|
517
|
+
this.startWorker();
|
|
421
518
|
var payload = [];
|
|
422
519
|
payload.push(this.channel);
|
|
423
520
|
const logStr = `sendWindResistance(${windCoeff},${windSpeed},${draftFactor})`;
|
|
@@ -451,9 +548,11 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
451
548
|
});
|
|
452
549
|
}
|
|
453
550
|
sendTrackResistance(slope, rrCoeff) {
|
|
454
|
-
if (!this.connected)
|
|
455
|
-
return;
|
|
456
551
|
return new Promise((resolve, reject) => {
|
|
552
|
+
if (!this.connected)
|
|
553
|
+
reject(new Error('not connected'));
|
|
554
|
+
if (!this.queue)
|
|
555
|
+
this.startWorker();
|
|
457
556
|
var payload = [];
|
|
458
557
|
payload.push(this.channel);
|
|
459
558
|
const logStr = `sendTrackResistance(${slope},${rrCoeff})`;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import AntAdapter from '../AntAdapter';
|
|
2
2
|
export default class AntHrmAdapter extends AntAdapter {
|
|
3
|
+
started: boolean;
|
|
4
|
+
starting: boolean;
|
|
3
5
|
constructor(DeviceID: any, port: any, stick: any, protocol: any);
|
|
4
6
|
isBike(): boolean;
|
|
5
7
|
isHrm(): boolean;
|
|
@@ -9,6 +11,6 @@ export default class AntHrmAdapter extends AntAdapter {
|
|
|
9
11
|
getDisplayName(): string;
|
|
10
12
|
onDeviceData(deviceData: any): void;
|
|
11
13
|
updateData(data: any, deviceData: any): any;
|
|
12
|
-
start(): Promise<
|
|
14
|
+
start(props?: any): Promise<any>;
|
|
13
15
|
stop(): Promise<boolean>;
|
|
14
16
|
}
|
|
@@ -8,10 +8,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
15
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
13
|
-
const AntAdapter_1 = require("../AntAdapter");
|
|
16
|
+
const AntAdapter_1 = __importDefault(require("../AntAdapter"));
|
|
14
17
|
const utils_1 = require("../utils");
|
|
18
|
+
const DEFAULT_START_TIMEOUT = 5000;
|
|
15
19
|
class AntHrmAdapter extends AntAdapter_1.default {
|
|
16
20
|
constructor(DeviceID, port, stick, protocol) {
|
|
17
21
|
super(protocol);
|
|
@@ -19,10 +23,13 @@ class AntHrmAdapter extends AntAdapter_1.default {
|
|
|
19
23
|
this.deviceID = DeviceID;
|
|
20
24
|
this.port = port;
|
|
21
25
|
this.stick = stick;
|
|
26
|
+
this.paused = false;
|
|
22
27
|
this.deviceData = {
|
|
23
28
|
DeviceID
|
|
24
29
|
};
|
|
25
30
|
this.data = {};
|
|
31
|
+
this.started = false;
|
|
32
|
+
this.starting = false;
|
|
26
33
|
}
|
|
27
34
|
isBike() { return false; }
|
|
28
35
|
isHrm() { return true; }
|
|
@@ -36,14 +43,16 @@ class AntHrmAdapter extends AntAdapter_1.default {
|
|
|
36
43
|
getDisplayName() {
|
|
37
44
|
const { DeviceID, manID, ComputedHeartRate } = this.deviceData;
|
|
38
45
|
const hrmStr = ComputedHeartRate ? ` (${ComputedHeartRate})` : '';
|
|
39
|
-
return `${utils_1.getBrand(manID)} Hrm ${DeviceID}${hrmStr}`;
|
|
46
|
+
return `${(0, utils_1.getBrand)(manID)} Hrm ${DeviceID}${hrmStr}`;
|
|
40
47
|
}
|
|
41
48
|
onDeviceData(deviceData) {
|
|
49
|
+
if (!this.started)
|
|
50
|
+
return;
|
|
42
51
|
this.deviceData = deviceData;
|
|
43
52
|
try {
|
|
44
53
|
if (this.onDataFn && !this.ignoreHrm && !this.paused) {
|
|
45
|
-
if (
|
|
46
|
-
|
|
54
|
+
if (this.lastUpdate === undefined || (Date.now() - this.lastUpdate) > this.updateFrequency) {
|
|
55
|
+
this.logger.logEvent({ message: 'onDeviceData', data: deviceData });
|
|
47
56
|
const data = this.updateData(this.data, deviceData);
|
|
48
57
|
this.onDataFn(data);
|
|
49
58
|
this.lastUpdate = Date.now();
|
|
@@ -57,34 +66,76 @@ class AntHrmAdapter extends AntAdapter_1.default {
|
|
|
57
66
|
data.heartrate = deviceData.ComputedHeartRate;
|
|
58
67
|
return data;
|
|
59
68
|
}
|
|
60
|
-
start() {
|
|
69
|
+
start(props) {
|
|
70
|
+
const _super = Object.create(null, {
|
|
71
|
+
start: { get: () => super.start }
|
|
72
|
+
});
|
|
61
73
|
return __awaiter(this, void 0, void 0, function* () {
|
|
74
|
+
yield _super.start.call(this, props);
|
|
62
75
|
this.logger.logEvent({ message: 'start()' });
|
|
76
|
+
const args = props || {};
|
|
63
77
|
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
64
78
|
if (this.ignoreHrm)
|
|
65
79
|
resolve(false);
|
|
80
|
+
if (this.starting) {
|
|
81
|
+
this.logger.logEvent({ message: 'start() not done: bike starting' });
|
|
82
|
+
return resolve(false);
|
|
83
|
+
}
|
|
84
|
+
if (this.started) {
|
|
85
|
+
this.logger.logEvent({ message: 'start() done: bike was already started' });
|
|
86
|
+
return resolve(true);
|
|
87
|
+
}
|
|
88
|
+
this.starting = true;
|
|
66
89
|
const Ant = this.getProtocol().getAnt();
|
|
67
90
|
const protocol = this.getProtocol();
|
|
91
|
+
let start = Date.now();
|
|
92
|
+
let timeout = start + (args.timeout || DEFAULT_START_TIMEOUT);
|
|
93
|
+
const iv = setInterval(() => {
|
|
94
|
+
if (Date.now() > timeout) {
|
|
95
|
+
clearInterval(iv);
|
|
96
|
+
this.starting = false;
|
|
97
|
+
reject(new Error('timeout'));
|
|
98
|
+
}
|
|
99
|
+
if (this.isStopped()) {
|
|
100
|
+
clearInterval(iv);
|
|
101
|
+
this.starting = false;
|
|
102
|
+
reject(new Error('stopped'));
|
|
103
|
+
}
|
|
104
|
+
}, 100);
|
|
68
105
|
protocol.attachSensors(this, Ant.HeartRateSensor, 'hbData')
|
|
69
|
-
.then(() =>
|
|
106
|
+
.then(() => {
|
|
107
|
+
this.starting = false;
|
|
108
|
+
this.started = true;
|
|
109
|
+
clearInterval(iv);
|
|
110
|
+
resolve(true);
|
|
111
|
+
})
|
|
70
112
|
.catch(err => reject(err));
|
|
71
113
|
}));
|
|
72
114
|
});
|
|
73
115
|
}
|
|
74
116
|
stop() {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
117
|
+
const _super = Object.create(null, {
|
|
118
|
+
stop: { get: () => super.stop }
|
|
119
|
+
});
|
|
120
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
121
|
+
yield _super.stop.call(this);
|
|
122
|
+
this.logger.logEvent({ message: 'stop()' });
|
|
123
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
124
|
+
this.starting = false;
|
|
125
|
+
return resolve(true);
|
|
126
|
+
this.started = false;
|
|
127
|
+
if (this.ignoreHrm)
|
|
128
|
+
return resolve(false);
|
|
129
|
+
try {
|
|
130
|
+
const protocol = this.getProtocol();
|
|
131
|
+
yield protocol.detachSensor(this);
|
|
132
|
+
resolve(true);
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
reject(err);
|
|
136
|
+
}
|
|
137
|
+
}));
|
|
138
|
+
});
|
|
88
139
|
}
|
|
89
140
|
}
|
|
90
141
|
exports.default = AntHrmAdapter;
|
package/lib/ant/utils.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getBrand = void 0;
|
|
4
|
-
|
|
4
|
+
const getBrand = (manId) => {
|
|
5
5
|
if (manId === undefined)
|
|
6
6
|
return "ANT+";
|
|
7
7
|
switch (manId) {
|
|
@@ -20,3 +20,4 @@ exports.getBrand = (manId) => {
|
|
|
20
20
|
return "ANT+";
|
|
21
21
|
}
|
|
22
22
|
};
|
|
23
|
+
exports.getBrand = getBrand;
|