incyclist-devices 1.3.25 → 1.4.2
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 +5 -0
- package/lib/CyclingMode.js +13 -0
- package/lib/ant/AntScanner.js +0 -2
- package/lib/ant/antfe/AntFEAdapter.js +3 -2
- package/lib/daum/DaumAdapter.d.ts +3 -2
- package/lib/daum/ERGCyclingMode.js +1 -1
- package/lib/daum/SmartTrainerCyclingMode.js +1 -1
- package/lib/daum/classic/DaumClassicAdapter.js +2 -2
- package/lib/daum/classic/DaumClassicProtocol.js +8 -2
- package/lib/daum/classic/bike.d.ts +3 -2
- package/lib/daum/classic/bike.js +5 -4
- package/lib/daum/classic/utils.d.ts +4 -2
- package/lib/daum/classic/utils.js +6 -16
- package/lib/daum/premium/DaumClassicCyclingMode.d.ts +14 -0
- package/lib/daum/premium/DaumClassicCyclingMode.js +82 -0
- package/lib/daum/premium/DaumPremiumAdapter.d.ts +3 -0
- package/lib/daum/premium/DaumPremiumAdapter.js +38 -1
- package/lib/daum/premium/DaumPremiumProtocol.js +8 -2
- package/lib/daum/premium/bike.d.ts +12 -2
- package/lib/daum/premium/bike.js +107 -13
- package/lib/daum/premium/tcpserial.js +0 -6
- package/lib/daum/premium/utils.d.ts +31 -1
- package/lib/daum/premium/utils.js +140 -25
- package/lib/types/route.d.ts +21 -0
- package/lib/types/route.js +9 -0
- package/lib/types/user.d.ts +11 -0
- package/lib/types/user.js +9 -0
- package/package.json +3 -2
package/lib/CyclingMode.d.ts
CHANGED
|
@@ -52,10 +52,13 @@ export default interface CyclingMode {
|
|
|
52
52
|
setSetting(name: string, value: any): void;
|
|
53
53
|
getSetting(name: string): any;
|
|
54
54
|
getSettings(): Settings;
|
|
55
|
+
setModeProperty(name: string, value: any): void;
|
|
56
|
+
getModeProperty(name: string): any;
|
|
55
57
|
}
|
|
56
58
|
export declare class CyclingModeBase implements CyclingMode {
|
|
57
59
|
adapter: Device;
|
|
58
60
|
settings: Settings;
|
|
61
|
+
properties: Settings;
|
|
59
62
|
constructor(adapter: Device, props?: any);
|
|
60
63
|
setAdapter(adapter: Device): void;
|
|
61
64
|
getBikeInitRequest(): UpdateRequest;
|
|
@@ -69,4 +72,6 @@ export declare class CyclingModeBase implements CyclingMode {
|
|
|
69
72
|
setSetting(name: string, value: any): void;
|
|
70
73
|
getSetting(name: string): any;
|
|
71
74
|
getSettings(): Settings;
|
|
75
|
+
setModeProperty(name: string, value: any): void;
|
|
76
|
+
getModeProperty(name: string): any;
|
|
72
77
|
}
|
package/lib/CyclingMode.js
CHANGED
|
@@ -13,6 +13,7 @@ var CyclingModeProperyType;
|
|
|
13
13
|
class CyclingModeBase {
|
|
14
14
|
constructor(adapter, props) {
|
|
15
15
|
this.settings = {};
|
|
16
|
+
this.properties = {};
|
|
16
17
|
if (!adapter)
|
|
17
18
|
throw new Error('IllegalArgument: adapter is null');
|
|
18
19
|
this.setAdapter(adapter);
|
|
@@ -62,5 +63,17 @@ class CyclingModeBase {
|
|
|
62
63
|
getSettings() {
|
|
63
64
|
return this.settings;
|
|
64
65
|
}
|
|
66
|
+
setModeProperty(name, value) {
|
|
67
|
+
this.properties[name] = value;
|
|
68
|
+
}
|
|
69
|
+
getModeProperty(name) {
|
|
70
|
+
const res = this.properties[name];
|
|
71
|
+
if (res !== undefined)
|
|
72
|
+
return res;
|
|
73
|
+
const prop = this.getProperties().find(p => p.key === name);
|
|
74
|
+
if (prop && prop.default !== undefined)
|
|
75
|
+
return prop.default;
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
65
78
|
}
|
|
66
79
|
exports.CyclingModeBase = CyclingModeBase;
|
package/lib/ant/AntScanner.js
CHANGED
|
@@ -575,8 +575,6 @@ class AntProtocol extends DeviceProtocol_1.default {
|
|
|
575
575
|
const channel = channelsUsed + idx;
|
|
576
576
|
const { sensor } = i;
|
|
577
577
|
i.device.setChannel(channel);
|
|
578
|
-
if (process.env.DEBUG)
|
|
579
|
-
console.log('~~~~Ant: attach', channel, i.device.getID());
|
|
580
578
|
sensor.attach(channel, i.device.getID());
|
|
581
579
|
this.sensors.attached.push(i);
|
|
582
580
|
});
|
|
@@ -176,8 +176,9 @@ class AntFEAdapter extends AntAdapter_1.default {
|
|
|
176
176
|
});
|
|
177
177
|
return __awaiter(this, void 0, void 0, function* () {
|
|
178
178
|
yield _super.start.call(this, props);
|
|
179
|
-
this.logger.logEvent({ message: 'start()' });
|
|
180
|
-
const
|
|
179
|
+
this.logger.logEvent({ message: 'start()', props });
|
|
180
|
+
const opts = props || {};
|
|
181
|
+
const { args } = opts;
|
|
181
182
|
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
182
183
|
if (this.ignoreHrm && this.ignoreBike && this.ignorePower) {
|
|
183
184
|
this.logger.logEvent({ message: 'start() not done: bike disabled' });
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EventLogger } from 'gd-eventlog';
|
|
2
2
|
import CyclingMode from '../CyclingMode';
|
|
3
3
|
import DeviceAdapterBase, { Bike, DeviceAdapter } from '../Device';
|
|
4
|
+
import { User } from '../types/user';
|
|
4
5
|
interface DaumAdapter {
|
|
5
6
|
getCurrentBikeData(): Promise<any>;
|
|
6
7
|
}
|
|
@@ -18,7 +19,7 @@ export default class DaumAdapterBase extends DeviceAdapterBase implements Device
|
|
|
18
19
|
iv: any;
|
|
19
20
|
logger: EventLogger;
|
|
20
21
|
cyclingMode: CyclingMode;
|
|
21
|
-
userSettings:
|
|
22
|
+
userSettings: User;
|
|
22
23
|
bikeSettings: any;
|
|
23
24
|
tsPrevData: number;
|
|
24
25
|
adapterTime: number;
|
|
@@ -29,7 +30,7 @@ export default class DaumAdapterBase extends DeviceAdapterBase implements Device
|
|
|
29
30
|
getSupportedCyclingModes(): Array<any>;
|
|
30
31
|
getCyclingMode(): CyclingMode;
|
|
31
32
|
getDefaultCyclingMode(): CyclingMode;
|
|
32
|
-
setUserSettings(userSettings:
|
|
33
|
+
setUserSettings(userSettings: User): void;
|
|
33
34
|
setBikeSettings(bikeSettings: any): void;
|
|
34
35
|
getWeight(): number;
|
|
35
36
|
getCurrentBikeData(): Promise<any>;
|
|
@@ -11,7 +11,7 @@ const config = {
|
|
|
11
11
|
description: "Calculates speed based on power and slope. Power is either set by workout or calculated based on gear and cadence",
|
|
12
12
|
properties: [
|
|
13
13
|
{ key: 'bikeType', name: 'Bike Type', description: '', type: CyclingMode_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain', 'Triathlon'], default: 'Race' },
|
|
14
|
-
{ key: 'startPower', name: 'Starting Power', description: 'Initial power in Watts at start of
|
|
14
|
+
{ key: 'startPower', name: 'Starting Power', description: 'Initial power in Watts at start of training', type: CyclingMode_1.CyclingModeProperyType.Integer, default: 50, min: 25, max: 800 },
|
|
15
15
|
]
|
|
16
16
|
};
|
|
17
17
|
class ERGCyclingMode extends CyclingMode_1.CyclingModeBase {
|
|
@@ -13,7 +13,7 @@ const config = {
|
|
|
13
13
|
description: "Calculates power based on speed and slope.",
|
|
14
14
|
properties: [
|
|
15
15
|
{ key: 'bikeType', name: 'Bike Type', description: '', type: CyclingMode_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain', 'Triathlon'], default: 'Race' },
|
|
16
|
-
{ key: 'startPower', name: 'Starting Power', description: 'Initial power in Watts at start of
|
|
16
|
+
{ key: 'startPower', name: 'Starting Power', description: 'Initial power in Watts at start of training', type: CyclingMode_1.CyclingModeProperyType.Integer, default: 50 },
|
|
17
17
|
{ key: 'minPower', name: 'Minimum Power', description: 'Minimum power in declines', type: CyclingMode_1.CyclingModeProperyType.Integer, default: 50 },
|
|
18
18
|
{ key: 'simulation', name: 'Simulate ', description: 'Simulate ', type: CyclingMode_1.CyclingModeProperyType.Boolean, default: false },
|
|
19
19
|
{ key: 'chainRings', name: 'Chain Rings', description: 'Simulated chain rings (format: <min>-<max>)', type: CyclingMode_1.CyclingModeProperyType.String, validation: '', default: '36-52', condition: (s) => s.simulation },
|
|
@@ -83,7 +83,7 @@ class DaumClassicAdapter extends DaumAdapter_1.default {
|
|
|
83
83
|
return __awaiter(this, void 0, void 0, function* () {
|
|
84
84
|
this.logger.logEvent({ message: 'start()', props });
|
|
85
85
|
const opts = props || {};
|
|
86
|
-
const
|
|
86
|
+
const { user } = props;
|
|
87
87
|
this.initData();
|
|
88
88
|
let startState = {};
|
|
89
89
|
return (0, utils_1.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -96,7 +96,7 @@ class DaumClassicAdapter extends DaumAdapter_1.default {
|
|
|
96
96
|
startState.setProg = true;
|
|
97
97
|
}
|
|
98
98
|
if (!startState.setPerson) {
|
|
99
|
-
yield this.getBike().setPerson(
|
|
99
|
+
yield this.getBike().setPerson(user);
|
|
100
100
|
startState.setPerson = true;
|
|
101
101
|
}
|
|
102
102
|
if (!startState.startProg) {
|
|
@@ -156,7 +156,7 @@ class DaumClassicProtocol extends DeviceProtocol_1.default {
|
|
|
156
156
|
return;
|
|
157
157
|
scan.scanning = true;
|
|
158
158
|
return device.check()
|
|
159
|
-
.then(() => {
|
|
159
|
+
.then(() => __awaiter(this, void 0, void 0, function* () {
|
|
160
160
|
if (this.state.stopScanning)
|
|
161
161
|
return;
|
|
162
162
|
const { onDeviceFound, onScanFinished, id } = opts;
|
|
@@ -166,10 +166,16 @@ class DaumClassicProtocol extends DeviceProtocol_1.default {
|
|
|
166
166
|
if (onScanFinished) {
|
|
167
167
|
onScanFinished(id);
|
|
168
168
|
}
|
|
169
|
+
try {
|
|
170
|
+
yield device.getBike().saveClose();
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
this.logger.logEvent({ message: 'scanCommand warning: Could not close port', error: err.message });
|
|
174
|
+
}
|
|
169
175
|
clearInterval(scan.iv);
|
|
170
176
|
scan.iv = undefined;
|
|
171
177
|
scan.scanning = false;
|
|
172
|
-
})
|
|
178
|
+
}))
|
|
173
179
|
.catch(() => {
|
|
174
180
|
scan.scanning = false;
|
|
175
181
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EventLogger } from 'gd-eventlog';
|
|
2
2
|
import { Queue } from '../../utils';
|
|
3
|
+
import { User } from '../../types/user';
|
|
3
4
|
declare type SuccessCallbackFn = (data: any) => void;
|
|
4
5
|
declare type ErrorCallbackFn = (status: number, error: any) => void;
|
|
5
6
|
interface CommandInstructions {
|
|
@@ -32,7 +33,7 @@ export default class Daum8008 {
|
|
|
32
33
|
getType(): string;
|
|
33
34
|
getPort(): string;
|
|
34
35
|
isConnected(): boolean;
|
|
35
|
-
setUser(user:
|
|
36
|
+
setUser(user: User, callback: any): void;
|
|
36
37
|
getUserWeight(): number;
|
|
37
38
|
getBikeWeight(): any;
|
|
38
39
|
connect(): void;
|
|
@@ -54,7 +55,7 @@ export default class Daum8008 {
|
|
|
54
55
|
stopProg(bikeNo?: number): Promise<unknown>;
|
|
55
56
|
setProg(progNo?: number, bikeNo?: number): Promise<unknown>;
|
|
56
57
|
setBikeType(bikeType: any, bikeNo?: number): Promise<unknown>;
|
|
57
|
-
setPerson(user?:
|
|
58
|
+
setPerson(user?: User, bikeNo?: number): Promise<unknown>;
|
|
58
59
|
runData(bikeNo?: number): Promise<unknown>;
|
|
59
60
|
setGear(gear: any, bikeNo?: number): Promise<unknown>;
|
|
60
61
|
setPower(power: any, bikeNo?: number): Promise<unknown>;
|
package/lib/daum/classic/bike.js
CHANGED
|
@@ -15,8 +15,8 @@ class Daum8008 {
|
|
|
15
15
|
this.portName = opts.port || process.env.COM_PORT;
|
|
16
16
|
this.settings = opts.settings || {};
|
|
17
17
|
this.bikeData = {
|
|
18
|
-
userWeight:
|
|
19
|
-
bikeWeight:
|
|
18
|
+
userWeight: utils_1.DEFAULT_USER_WEIGHT,
|
|
19
|
+
bikeWeight: utils_1.DEFAULT_BIKE_WEIGHT,
|
|
20
20
|
maxPower: 800
|
|
21
21
|
};
|
|
22
22
|
this.sp = undefined;
|
|
@@ -45,7 +45,8 @@ class Daum8008 {
|
|
|
45
45
|
}
|
|
46
46
|
setUser(user, callback) {
|
|
47
47
|
this.logger.logEvent({ message: "setUser()", user });
|
|
48
|
-
|
|
48
|
+
if (user)
|
|
49
|
+
this.settings.user = user;
|
|
49
50
|
var cb = callback || nop;
|
|
50
51
|
cb(200, user);
|
|
51
52
|
}
|
|
@@ -361,7 +362,7 @@ class Daum8008 {
|
|
|
361
362
|
});
|
|
362
363
|
}
|
|
363
364
|
setPerson(user = {}, bikeNo = 0) {
|
|
364
|
-
const age = user.age !== undefined ? user.age :
|
|
365
|
+
const age = user.age !== undefined ? user.age : utils_1.DEFAULT_AGE;
|
|
365
366
|
const gender = (0, utils_1.getGender)(user.sex);
|
|
366
367
|
const length = (0, utils_1.getLength)(user.length);
|
|
367
368
|
const maxPower = this.settings.maxPower === undefined ? 800 : this.settings.maxPower;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
export declare
|
|
1
|
+
export declare const DEFAULT_AGE = 30;
|
|
2
|
+
export declare const DEFAULT_USER_WEIGHT = 75;
|
|
3
|
+
export declare const DEFAULT_BIKE_WEIGHT = 10;
|
|
4
|
+
export declare function getCockpit(c: any): "Cardio" | "Fitness" | "Vita De Luxe" | "8008" | "8008 TRS" | "8080" | "Therapie" | "8008 TRS Pro" | "8008 TRS3" | "Unknown";
|
|
2
5
|
export declare function getBikeType(type: any): 1 | 0;
|
|
3
|
-
export declare function getAge(birthday: any): number;
|
|
4
6
|
export declare function getGender(sex: any): 1 | 2;
|
|
5
7
|
export declare function getLength(length: any): number;
|
|
6
8
|
export declare function getWeight(weight?: any): number;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Float32ToIntArray = exports.Float32ToHex = exports.hexstr = exports.buildError = exports.parseRunData = exports.getWeight = exports.getLength = exports.getGender = exports.
|
|
3
|
+
exports.Float32ToIntArray = exports.Float32ToHex = exports.hexstr = exports.buildError = exports.parseRunData = exports.getWeight = exports.getLength = exports.getGender = exports.getBikeType = exports.getCockpit = exports.DEFAULT_BIKE_WEIGHT = exports.DEFAULT_USER_WEIGHT = exports.DEFAULT_AGE = void 0;
|
|
4
|
+
exports.DEFAULT_AGE = 30;
|
|
5
|
+
exports.DEFAULT_USER_WEIGHT = 75;
|
|
6
|
+
exports.DEFAULT_BIKE_WEIGHT = 10;
|
|
4
7
|
function getCockpit(c) {
|
|
5
8
|
switch (c) {
|
|
6
9
|
case 10:
|
|
@@ -11,6 +14,8 @@ function getCockpit(c) {
|
|
|
11
14
|
return "Vita De Luxe";
|
|
12
15
|
case 40:
|
|
13
16
|
return "8008";
|
|
17
|
+
case 0x2A:
|
|
18
|
+
return "8008 TRS";
|
|
14
19
|
case 50:
|
|
15
20
|
return "8080";
|
|
16
21
|
case 60:
|
|
@@ -39,21 +44,6 @@ function getBikeType(type) {
|
|
|
39
44
|
}
|
|
40
45
|
}
|
|
41
46
|
exports.getBikeType = getBikeType;
|
|
42
|
-
function getAge(birthday) {
|
|
43
|
-
if (birthday === undefined) {
|
|
44
|
-
return 30;
|
|
45
|
-
}
|
|
46
|
-
try {
|
|
47
|
-
const bd = new Date(birthday);
|
|
48
|
-
const ageDifMs = Date.now() - bd.getTime();
|
|
49
|
-
var ageDate = new Date(ageDifMs);
|
|
50
|
-
return Math.abs(ageDate.getUTCFullYear() - 1970);
|
|
51
|
-
}
|
|
52
|
-
catch (error) {
|
|
53
|
-
return 30;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
exports.getAge = getAge;
|
|
57
47
|
function getGender(sex) {
|
|
58
48
|
if (sex === undefined)
|
|
59
49
|
return 2;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import CyclingMode, { CyclingModeProperty, IncyclistBikeData, Settings, UpdateRequest } from "../../CyclingMode";
|
|
2
|
+
import DaumAdapter from "../DaumAdapter";
|
|
3
|
+
import PowerMeterCyclingMode from "../PowerMeterCyclingMode";
|
|
4
|
+
export default class DaumClassicCyclingMode extends PowerMeterCyclingMode implements CyclingMode {
|
|
5
|
+
constructor(adapter: DaumAdapter, props?: Settings);
|
|
6
|
+
getName(): string;
|
|
7
|
+
getDescription(): string;
|
|
8
|
+
getProperties(): CyclingModeProperty[];
|
|
9
|
+
getProperty(name: string): CyclingModeProperty;
|
|
10
|
+
getBikeInitRequest(): UpdateRequest;
|
|
11
|
+
getSettings(): Settings;
|
|
12
|
+
getSetting(name: string): any;
|
|
13
|
+
updateData(data: IncyclistBikeData): IncyclistBikeData;
|
|
14
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const gd_eventlog_1 = require("gd-eventlog");
|
|
7
|
+
const CyclingMode_1 = require("../../CyclingMode");
|
|
8
|
+
const PowerMeterCyclingMode_1 = __importDefault(require("../PowerMeterCyclingMode"));
|
|
9
|
+
const config = {
|
|
10
|
+
name: "Daum Classic",
|
|
11
|
+
description: "The device calculates speed and power based on slope. Incyclist will not modify any values recived from the device\nThis mode will not respect maximum power and/or workout limits",
|
|
12
|
+
properties: [
|
|
13
|
+
{ key: 'bikeType', name: 'Bike Type', description: '', type: CyclingMode_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain'], default: 'Race' },
|
|
14
|
+
]
|
|
15
|
+
};
|
|
16
|
+
class DaumClassicCyclingMode extends PowerMeterCyclingMode_1.default {
|
|
17
|
+
constructor(adapter, props) {
|
|
18
|
+
super(adapter, props);
|
|
19
|
+
this.logger = adapter ? adapter.logger : undefined;
|
|
20
|
+
if (!this.logger)
|
|
21
|
+
this.logger = new gd_eventlog_1.EventLogger('DaumClassic');
|
|
22
|
+
this.setModeProperty('eppSupport', true);
|
|
23
|
+
this.setModeProperty('setPersonSupport', true);
|
|
24
|
+
}
|
|
25
|
+
getName() {
|
|
26
|
+
return config.name;
|
|
27
|
+
}
|
|
28
|
+
getDescription() {
|
|
29
|
+
return config.description;
|
|
30
|
+
}
|
|
31
|
+
getProperties() {
|
|
32
|
+
return config.properties;
|
|
33
|
+
}
|
|
34
|
+
getProperty(name) {
|
|
35
|
+
return config.properties.find(p => p.name === name);
|
|
36
|
+
}
|
|
37
|
+
getBikeInitRequest() {
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
getSettings() {
|
|
41
|
+
const settings = super.getSettings();
|
|
42
|
+
settings['setPerson'] = true;
|
|
43
|
+
return settings;
|
|
44
|
+
}
|
|
45
|
+
getSetting(name) {
|
|
46
|
+
if (name === 'setPerson')
|
|
47
|
+
return true;
|
|
48
|
+
return super.getSetting(name);
|
|
49
|
+
}
|
|
50
|
+
updateData(data) {
|
|
51
|
+
try {
|
|
52
|
+
const prevData = this.data || {};
|
|
53
|
+
const prevRequest = this.prevRequest || {};
|
|
54
|
+
const bikeData = JSON.parse(JSON.stringify(data));
|
|
55
|
+
let power = data.power || 0;
|
|
56
|
+
let speed = data.speed || 0;
|
|
57
|
+
let slope = (prevData.slope !== undefined ? prevData.slope : prevRequest.slope || 0);
|
|
58
|
+
let distanceInternal = prevData.distanceInternal || 0;
|
|
59
|
+
if (!bikeData.pedalRpm || bikeData.isPedalling === false) {
|
|
60
|
+
speed = 0;
|
|
61
|
+
power = 0;
|
|
62
|
+
}
|
|
63
|
+
let ts = Date.now();
|
|
64
|
+
let v = speed / 3.6;
|
|
65
|
+
let duration = this.prevUpdateTS === 0 ? 0 : ((ts - this.prevUpdateTS) / 1000);
|
|
66
|
+
distanceInternal += Math.round(v * duration);
|
|
67
|
+
data.speed = parseFloat(speed.toFixed(1));
|
|
68
|
+
data.power = Math.round(power);
|
|
69
|
+
data.distanceInternal = Math.round(distanceInternal);
|
|
70
|
+
data.distance = Math.round(distanceInternal / 100);
|
|
71
|
+
data.slope = slope;
|
|
72
|
+
this.logger.logEvent({ message: "updateData result", data, bikeData, prevRequest: {}, prevSpeed: prevData.speed });
|
|
73
|
+
this.data = JSON.parse(JSON.stringify(data));
|
|
74
|
+
this.prevUpdateTS = ts;
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
this.logger.logEvent({ message: 'error', fn: 'updateData()', error: err.message || err });
|
|
78
|
+
}
|
|
79
|
+
return data;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
exports.default = DaumClassicCyclingMode;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Route } from '../../types/route';
|
|
1
2
|
import DaumAdapter from '../DaumAdapter';
|
|
2
3
|
export default class DaumPremiumDevice extends DaumAdapter {
|
|
3
4
|
static NAME: string;
|
|
@@ -5,7 +6,9 @@ export default class DaumPremiumDevice extends DaumAdapter {
|
|
|
5
6
|
getName(): string;
|
|
6
7
|
getPort(): any;
|
|
7
8
|
getInterface(): any;
|
|
9
|
+
getSupportedCyclingModes(): Array<any>;
|
|
8
10
|
check(): Promise<unknown>;
|
|
11
|
+
initClassic(route: Route): Promise<boolean>;
|
|
9
12
|
start(props: any): Promise<unknown>;
|
|
10
13
|
getCurrentBikeData(): Promise<any>;
|
|
11
14
|
}
|
|
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
16
16
|
const utils_1 = require("../../utils");
|
|
17
17
|
const DaumAdapter_1 = __importDefault(require("../DaumAdapter"));
|
|
18
|
+
const DaumClassicCyclingMode_1 = __importDefault(require("./DaumClassicCyclingMode"));
|
|
18
19
|
const PROTOCOL_NAME = "Daum Premium";
|
|
19
20
|
class DaumPremiumDevice extends DaumAdapter_1.default {
|
|
20
21
|
constructor(protocol, bike) {
|
|
@@ -38,6 +39,11 @@ class DaumPremiumDevice extends DaumAdapter_1.default {
|
|
|
38
39
|
getInterface() {
|
|
39
40
|
return this.bike.getInterface();
|
|
40
41
|
}
|
|
42
|
+
getSupportedCyclingModes() {
|
|
43
|
+
const supported = super.getSupportedCyclingModes();
|
|
44
|
+
supported.push(DaumClassicCyclingMode_1.default);
|
|
45
|
+
return supported;
|
|
46
|
+
}
|
|
41
47
|
check() {
|
|
42
48
|
var info = {};
|
|
43
49
|
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -56,10 +62,28 @@ class DaumPremiumDevice extends DaumAdapter_1.default {
|
|
|
56
62
|
}
|
|
57
63
|
}));
|
|
58
64
|
}
|
|
65
|
+
initClassic(route) {
|
|
66
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
67
|
+
if (!route)
|
|
68
|
+
return true;
|
|
69
|
+
let res;
|
|
70
|
+
const bikeType = this.getCyclingMode().getSetting('bikeType');
|
|
71
|
+
res = yield this.bike.programUpload(bikeType, route);
|
|
72
|
+
if (!res)
|
|
73
|
+
return false;
|
|
74
|
+
res = yield this.bike.startProgram(route.programId);
|
|
75
|
+
if (!res)
|
|
76
|
+
return false;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
59
79
|
start(props) {
|
|
60
80
|
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
-
this.logger.logEvent({ message: 'start()'
|
|
81
|
+
this.logger.logEvent({ message: 'start()' });
|
|
82
|
+
console.log('~~~setPersonSupport:', this.getCyclingMode().getModeProperty('setPersonSupport'));
|
|
83
|
+
console.log('~~~eppSupport:', this.getCyclingMode().getModeProperty('eppSupport'));
|
|
62
84
|
const opts = props || {};
|
|
85
|
+
const user = opts.user || this.userSettings;
|
|
86
|
+
const route = opts.route;
|
|
63
87
|
var info = {};
|
|
64
88
|
this.initData();
|
|
65
89
|
return (0, utils_1.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -75,10 +99,23 @@ class DaumPremiumDevice extends DaumAdapter_1.default {
|
|
|
75
99
|
if (!info.version) {
|
|
76
100
|
info.version = yield this.bike.getProtocolVersion();
|
|
77
101
|
}
|
|
102
|
+
if (!info.init && this.getCyclingMode().getModeProperty('setPersonSupport')) {
|
|
103
|
+
info.init = yield this.initClassic(route);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
info.init = true;
|
|
107
|
+
}
|
|
108
|
+
if (!info.person && this.getCyclingMode().getModeProperty('eppSupport')) {
|
|
109
|
+
info.person = yield this.bike.setPerson(user);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
info.person = true;
|
|
113
|
+
}
|
|
78
114
|
const gear = yield this.bike.setGear(this.data.gear || (opts.gear || 10));
|
|
79
115
|
return gear;
|
|
80
116
|
}
|
|
81
117
|
catch (err) {
|
|
118
|
+
console.error(err);
|
|
82
119
|
throw (new Error(`could not start device, reason:${err.message}`));
|
|
83
120
|
}
|
|
84
121
|
}), 5, 1000)
|
|
@@ -177,7 +177,7 @@ class DaumPremiumProtocol extends DeviceProtocol_1.default {
|
|
|
177
177
|
return;
|
|
178
178
|
scan.scanning = true;
|
|
179
179
|
device.check()
|
|
180
|
-
.then(() => {
|
|
180
|
+
.then(() => __awaiter(this, void 0, void 0, function* () {
|
|
181
181
|
if (this.state.stopScanning)
|
|
182
182
|
return;
|
|
183
183
|
const { onDeviceFound, onScanFinished, id } = opts;
|
|
@@ -187,10 +187,16 @@ class DaumPremiumProtocol extends DeviceProtocol_1.default {
|
|
|
187
187
|
if (onScanFinished) {
|
|
188
188
|
onScanFinished(id);
|
|
189
189
|
}
|
|
190
|
+
try {
|
|
191
|
+
yield device.getBike().saveClose();
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
this.logger.logEvent({ message: 'scanCommand warning: Could not close port', error: err.message });
|
|
195
|
+
}
|
|
190
196
|
clearInterval(scan.iv);
|
|
191
197
|
scan.iv = undefined;
|
|
192
198
|
scan.scanning = false;
|
|
193
|
-
})
|
|
199
|
+
}))
|
|
194
200
|
.catch(() => {
|
|
195
201
|
scan.scanning = false;
|
|
196
202
|
});
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { ReservedCommands, BikeType } from './utils';
|
|
1
3
|
import { Queue } from '../../utils';
|
|
2
4
|
import { EventLogger } from 'gd-eventlog';
|
|
5
|
+
import { User } from "../../types/user";
|
|
6
|
+
import { Route } from "../../types/route";
|
|
3
7
|
declare class Daum8i {
|
|
4
8
|
portName: string;
|
|
5
9
|
logger: EventLogger;
|
|
@@ -63,7 +67,7 @@ declare class Daum8i {
|
|
|
63
67
|
sendDaum8iCommand(command: any, queryType: any, payload: any): Promise<unknown>;
|
|
64
68
|
sendACK(): void;
|
|
65
69
|
sendNAK(): void;
|
|
66
|
-
sendReservedDaum8iCommand(command:
|
|
70
|
+
sendReservedDaum8iCommand(command: ReservedCommands, cmdType: any, data?: Buffer): Promise<any[]>;
|
|
67
71
|
getProtocolVersion(): Promise<string>;
|
|
68
72
|
getDashboardVersion(): Promise<unknown>;
|
|
69
73
|
getDeviceType(): Promise<any>;
|
|
@@ -89,7 +93,13 @@ declare class Daum8i {
|
|
|
89
93
|
setSlope(slope: any): void;
|
|
90
94
|
setPower(power: any): Promise<number>;
|
|
91
95
|
getPower(power: any): Promise<number>;
|
|
92
|
-
setPerson(person:
|
|
96
|
+
setPerson(person: User): Promise<boolean>;
|
|
97
|
+
programUploadInit(): Promise<boolean>;
|
|
98
|
+
programUploadStart(bikeType: BikeType, route: Route): Promise<Uint8Array>;
|
|
99
|
+
programUploadSendBlock(epp: Uint8Array, offset: number): Promise<boolean>;
|
|
100
|
+
programUploadDone(): Promise<boolean>;
|
|
101
|
+
programUpload(bikeType: BikeType, route: Route): Promise<boolean>;
|
|
102
|
+
startProgram(programId?: number): Promise<boolean>;
|
|
93
103
|
setGear(gear: any): Promise<number>;
|
|
94
104
|
getGear(): Promise<number>;
|
|
95
105
|
}
|
package/lib/daum/premium/bike.js
CHANGED
|
@@ -25,6 +25,7 @@ const TIMEOUT_START = 15000;
|
|
|
25
25
|
const OPEN_TIMEOUT = 1000;
|
|
26
26
|
const DAUM_PREMIUM_DEFAULT_PORT = 51955;
|
|
27
27
|
const DAUM_PREMIUM_DEFAULT_HOST = '127.0.0.1';
|
|
28
|
+
const MAX_DATA_BLOCK_SIZE = 512;
|
|
28
29
|
var __SerialPort = undefined;
|
|
29
30
|
var net = undefined;
|
|
30
31
|
const DEBUG_LOGGER = {
|
|
@@ -166,21 +167,18 @@ class Daum8i {
|
|
|
166
167
|
const tTimeout = Date.now() + TIMEOUT_START;
|
|
167
168
|
const iv = setInterval(() => {
|
|
168
169
|
if (this.state.error !== undefined) {
|
|
169
|
-
console.log('~~ -> error');
|
|
170
170
|
clearInterval(iv);
|
|
171
171
|
this.forceClose();
|
|
172
172
|
reject(this.state.error);
|
|
173
173
|
this.state = { opened: false, closed: true, busy: false };
|
|
174
174
|
}
|
|
175
175
|
else if (this.isConnected()) {
|
|
176
|
-
console.log('~~ -> connected');
|
|
177
176
|
this.state.connecting = false;
|
|
178
177
|
resolve(true);
|
|
179
178
|
clearInterval(iv);
|
|
180
179
|
}
|
|
181
180
|
else {
|
|
182
181
|
if (Date.now() > tTimeout) {
|
|
183
|
-
console.log('~~ -> timeout');
|
|
184
182
|
this.state.connecting = false;
|
|
185
183
|
this.forceClose();
|
|
186
184
|
clearInterval(iv);
|
|
@@ -281,7 +279,6 @@ class Daum8i {
|
|
|
281
279
|
});
|
|
282
280
|
}
|
|
283
281
|
forceClose(updateState = false) {
|
|
284
|
-
console.log('~~~ forceClose', updateState);
|
|
285
282
|
const sp = this.sp;
|
|
286
283
|
if (!this.sp)
|
|
287
284
|
return;
|
|
@@ -578,20 +575,24 @@ class Daum8i {
|
|
|
578
575
|
this.logger.logEvent({ message: "sendCommand:sending NAK", port });
|
|
579
576
|
}
|
|
580
577
|
sendReservedDaum8iCommand(command, cmdType, data) {
|
|
581
|
-
let
|
|
582
|
-
const key = (0, utils_1.getReservedCommandKey)(command);
|
|
583
|
-
(0, utils_1.append)(cmdData, (0, utils_1.Int16ToIntArray)(key));
|
|
578
|
+
let buffer;
|
|
584
579
|
if (data !== undefined && data.length > 0) {
|
|
585
|
-
|
|
586
|
-
|
|
580
|
+
buffer = Buffer.alloc(data.length + 4);
|
|
581
|
+
buffer.writeInt16LE(command, 0);
|
|
582
|
+
buffer.writeUInt16LE(data.length, 2);
|
|
583
|
+
data.copy(buffer, 4);
|
|
587
584
|
}
|
|
588
585
|
else {
|
|
589
|
-
|
|
586
|
+
buffer = Buffer.alloc(4);
|
|
587
|
+
buffer.writeInt16LE(command, 0);
|
|
588
|
+
buffer.writeUInt16LE(0, 2);
|
|
590
589
|
}
|
|
590
|
+
const cmdData = Uint8Array.from(buffer);
|
|
591
591
|
return this.sendDaum8iCommand('M70', cmdType, (0, utils_1.bin2esc)(cmdData))
|
|
592
|
-
.then((
|
|
592
|
+
.then((res) => {
|
|
593
|
+
const resData = Uint8Array.from(res, x => x.charCodeAt(0));
|
|
593
594
|
const cmd = (0, utils_1.esc2bin)(resData);
|
|
594
|
-
|
|
595
|
+
console.log('~~~ cmd', cmd);
|
|
595
596
|
return cmd;
|
|
596
597
|
});
|
|
597
598
|
}
|
|
@@ -710,7 +711,100 @@ class Daum8i {
|
|
|
710
711
|
});
|
|
711
712
|
}
|
|
712
713
|
setPerson(person) {
|
|
713
|
-
return this.sendReservedDaum8iCommand(
|
|
714
|
+
return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PERSON_SET, 'BF', (0, utils_1.getPersonData)(person))
|
|
715
|
+
.then((res) => {
|
|
716
|
+
const buffer = Buffer.from(res);
|
|
717
|
+
return buffer.readInt16LE(0) === utils_1.ReservedCommands.PERSON_SET;
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
programUploadInit() {
|
|
721
|
+
return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_BEGIN, 'BF')
|
|
722
|
+
.then((res) => {
|
|
723
|
+
const buffer = Buffer.from(res);
|
|
724
|
+
return buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_BEGIN;
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
programUploadStart(bikeType, route) {
|
|
728
|
+
const payload = Buffer.alloc(40);
|
|
729
|
+
const epp = (0, utils_1.routeToEpp)(route);
|
|
730
|
+
payload.writeInt32LE(0, 0);
|
|
731
|
+
payload.writeInt8(bikeType, 4);
|
|
732
|
+
payload.writeInt8(bikeType, 5);
|
|
733
|
+
payload.writeInt16LE(0, 6);
|
|
734
|
+
payload.writeInt32LE(0, 8);
|
|
735
|
+
payload.writeInt32LE(0, 12);
|
|
736
|
+
payload.writeFloatLE(0, 16);
|
|
737
|
+
payload.writeFloatLE(0, 20);
|
|
738
|
+
payload.writeInt16LE(0, 24);
|
|
739
|
+
payload.writeInt16LE(0, 26);
|
|
740
|
+
payload.writeInt16LE(0, 28);
|
|
741
|
+
payload.writeInt16LE(0, 30);
|
|
742
|
+
payload.writeInt32LE(7, 32);
|
|
743
|
+
payload.writeInt32LE(epp.length, 36);
|
|
744
|
+
return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_NEW_PROGRAM, 'BF', payload)
|
|
745
|
+
.then((res) => {
|
|
746
|
+
const buffer = Buffer.from(res);
|
|
747
|
+
if (buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_NEW_PROGRAM) {
|
|
748
|
+
return epp;
|
|
749
|
+
}
|
|
750
|
+
throw new Error('Illegal Response');
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
programUploadSendBlock(epp, offset) {
|
|
754
|
+
const remaining = epp.length - offset;
|
|
755
|
+
if (remaining <= 0)
|
|
756
|
+
return Promise.resolve(true);
|
|
757
|
+
const size = remaining > MAX_DATA_BLOCK_SIZE ? MAX_DATA_BLOCK_SIZE : remaining;
|
|
758
|
+
const payload = Buffer.alloc(size + 8);
|
|
759
|
+
payload.writeInt32LE(size, 0);
|
|
760
|
+
payload.writeInt32LE(offset, 4);
|
|
761
|
+
const chunk = Buffer.from(epp.slice(offset, offset + size));
|
|
762
|
+
chunk.copy(payload, 8);
|
|
763
|
+
return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_CONTINUE_PROGRAM, 'BF', payload)
|
|
764
|
+
.then((res) => {
|
|
765
|
+
const buffer = Buffer.from(res);
|
|
766
|
+
let success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_CONTINUE_PROGRAM;
|
|
767
|
+
console.log('~~ Buffer', buffer, buffer.readInt16LE(2), buffer.readInt8(4));
|
|
768
|
+
success = success && (buffer.readInt16LE(2) === 1);
|
|
769
|
+
success = success && (buffer.readInt8(4) === 1);
|
|
770
|
+
if (!success)
|
|
771
|
+
throw new Error('Illegal Response');
|
|
772
|
+
return success;
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
programUploadDone() {
|
|
776
|
+
return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_END, 'BF')
|
|
777
|
+
.then((res) => {
|
|
778
|
+
const buffer = Buffer.from(res);
|
|
779
|
+
return buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_END;
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
programUpload(bikeType, route) {
|
|
783
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
784
|
+
yield this.programUploadInit();
|
|
785
|
+
const epp = yield this.programUploadStart(bikeType, route);
|
|
786
|
+
let success = true;
|
|
787
|
+
let done = false;
|
|
788
|
+
let offset = 0;
|
|
789
|
+
while (success && !done) {
|
|
790
|
+
success = yield this.programUploadSendBlock(epp, offset);
|
|
791
|
+
offset += MAX_DATA_BLOCK_SIZE;
|
|
792
|
+
done = offset >= epp.length;
|
|
793
|
+
}
|
|
794
|
+
if (done) {
|
|
795
|
+
return yield this.programUploadDone();
|
|
796
|
+
}
|
|
797
|
+
return false;
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
startProgram(programId = 1) {
|
|
801
|
+
const payload = Buffer.alloc(2);
|
|
802
|
+
payload.writeInt16LE(programId, 0);
|
|
803
|
+
return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_START, 'BF', payload)
|
|
804
|
+
.then((res) => {
|
|
805
|
+
const buffer = Buffer.from(res);
|
|
806
|
+
return buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_START;
|
|
807
|
+
});
|
|
714
808
|
}
|
|
715
809
|
setGear(gear) {
|
|
716
810
|
return this.sendDaum8iCommand('M71', 'BF', `${gear}`)
|
|
@@ -38,18 +38,15 @@ class TcpSocketPort {
|
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
this.logger.logEvent({ message: 'opening', id: this.id, retry });
|
|
41
|
-
console.log('~~opening socket', this.id);
|
|
42
41
|
this.socket.connect(this.port, this.host);
|
|
43
42
|
}
|
|
44
43
|
catch (err) {
|
|
45
44
|
this.logger.logEvent({ message: 'opening error', id: this.id, error: err.message, stack: err.stack });
|
|
46
|
-
console.log('~~open socket error', this.id, err);
|
|
47
45
|
this.emit('error', err);
|
|
48
46
|
}
|
|
49
47
|
}
|
|
50
48
|
close() {
|
|
51
49
|
this.logger.logEvent({ message: 'closing', id: this.id });
|
|
52
|
-
console.log('~~closing socket', this.id);
|
|
53
50
|
this.isOpen = false;
|
|
54
51
|
this.isClosed = true;
|
|
55
52
|
try {
|
|
@@ -67,7 +64,6 @@ class TcpSocketPort {
|
|
|
67
64
|
if (this.isOpen)
|
|
68
65
|
return;
|
|
69
66
|
this.logger.logEvent({ message: 'timeout', id: this.id });
|
|
70
|
-
console.log('~~socket timeout', this.id);
|
|
71
67
|
try {
|
|
72
68
|
this.socket.end();
|
|
73
69
|
}
|
|
@@ -78,14 +74,12 @@ class TcpSocketPort {
|
|
|
78
74
|
}
|
|
79
75
|
onConnect() {
|
|
80
76
|
this.logger.logEvent({ message: 'connected', id: this.id });
|
|
81
|
-
console.log('~~socket connected', this.id);
|
|
82
77
|
this.isOpen = true;
|
|
83
78
|
this.isClosed = false;
|
|
84
79
|
this.emit('open');
|
|
85
80
|
}
|
|
86
81
|
onError(err) {
|
|
87
82
|
this.logger.logEvent({ message: 'error', error: err.message });
|
|
88
|
-
console.log('~~socket error', this.id, err);
|
|
89
83
|
if (this.callbacks['error'])
|
|
90
84
|
this.callbacks['error'](err);
|
|
91
85
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Route } from "../../types/route";
|
|
3
|
+
import { User } from "../../types/user";
|
|
1
4
|
export declare function bin2esc(arr: any): any[];
|
|
2
5
|
export declare function esc2bin(arr: any): any[];
|
|
3
6
|
export declare function checkSum(cmdArr: any, payload: any): string;
|
|
@@ -14,7 +17,33 @@ export declare function Float32ToHex(float32: any): any;
|
|
|
14
17
|
export declare function Float32ToIntArray(float32: any): any[];
|
|
15
18
|
export declare function Int16ToIntArray(int16: any): any[];
|
|
16
19
|
export declare function Int32ToIntArray(int32: any): any[];
|
|
17
|
-
export declare
|
|
20
|
+
export declare enum ReservedCommands {
|
|
21
|
+
RESULT_RESET = 0,
|
|
22
|
+
RESULT_GET = 1,
|
|
23
|
+
NETRACE_START = 2,
|
|
24
|
+
NETRACE_STOP = 3,
|
|
25
|
+
NETRACE_USERNAME = 4,
|
|
26
|
+
NETRACE_USERDATA = 5,
|
|
27
|
+
PERSON_GET = 6,
|
|
28
|
+
PERSON_SET = 7,
|
|
29
|
+
PROGRAM_LIST_BEGIN = 8,
|
|
30
|
+
PROGRAM_LIST_NEW_PROGRAM = 9,
|
|
31
|
+
PROGRAM_LIST_CONTINUE_PROGRAM = 10,
|
|
32
|
+
PROGRAM_LIST_END = 11,
|
|
33
|
+
PROGRAM_LIST_START = 12,
|
|
34
|
+
RELAX_START = 12,
|
|
35
|
+
RELAX_STOP = 14,
|
|
36
|
+
RELAX_GET_DATA = 15,
|
|
37
|
+
KEY_PRESSED = 16,
|
|
38
|
+
PROGRAM_CONTROL = 17
|
|
39
|
+
}
|
|
40
|
+
export declare enum BikeType {
|
|
41
|
+
ALLROUND = 0,
|
|
42
|
+
RACE = 1,
|
|
43
|
+
MOUNTAIN = 2
|
|
44
|
+
}
|
|
45
|
+
export declare function getBikeType(bikeTypeStr?: string): BikeType;
|
|
46
|
+
export declare function routeToEpp(route: Route, date?: Date): Uint8Array;
|
|
18
47
|
export declare function parseTrainingData(payload: any): {
|
|
19
48
|
time: number;
|
|
20
49
|
heartrate: number;
|
|
@@ -30,3 +59,4 @@ export declare function parseTrainingData(payload: any): {
|
|
|
30
59
|
deviceState: number;
|
|
31
60
|
speedStatus: string;
|
|
32
61
|
};
|
|
62
|
+
export declare function getPersonData(user: User): Buffer;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseTrainingData = exports.
|
|
6
|
+
exports.getPersonData = exports.parseTrainingData = exports.routeToEpp = exports.getBikeType = exports.BikeType = exports.ReservedCommands = exports.Int32ToIntArray = exports.Int16ToIntArray = exports.Float32ToIntArray = exports.Float32ToHex = exports.getAsciiArrayFromStr = exports.asciiArrayToString = exports.charArrayToString = exports.ascii = exports.append = exports.getHex = exports.hexstr = exports.getMessageData = exports.buildMessage = exports.checkSum = exports.esc2bin = exports.bin2esc = void 0;
|
|
7
|
+
const user_1 = require("../../types/user");
|
|
8
|
+
const utils_1 = require("../classic/utils");
|
|
9
|
+
const win32filetime_1 = __importDefault(require("win32filetime"));
|
|
4
10
|
const sum = (arr) => arr.reduce((a, b) => a + b, 0);
|
|
5
11
|
function bin2esc(arr) {
|
|
6
12
|
if (arr === undefined) {
|
|
@@ -114,7 +120,7 @@ function getMessageData(command) {
|
|
|
114
120
|
}
|
|
115
121
|
exports.getMessageData = getMessageData;
|
|
116
122
|
function hexstr(arr, start, len) {
|
|
117
|
-
const isArr = Array.isArray(arr);
|
|
123
|
+
const isArr = Array.isArray(arr) || arr instanceof Uint8Array;
|
|
118
124
|
if (!arr)
|
|
119
125
|
return '';
|
|
120
126
|
var str = "";
|
|
@@ -211,30 +217,95 @@ function Int32ToIntArray(int32) {
|
|
|
211
217
|
return arr;
|
|
212
218
|
}
|
|
213
219
|
exports.Int32ToIntArray = Int32ToIntArray;
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
220
|
+
var ReservedCommands;
|
|
221
|
+
(function (ReservedCommands) {
|
|
222
|
+
ReservedCommands[ReservedCommands["RESULT_RESET"] = 0] = "RESULT_RESET";
|
|
223
|
+
ReservedCommands[ReservedCommands["RESULT_GET"] = 1] = "RESULT_GET";
|
|
224
|
+
ReservedCommands[ReservedCommands["NETRACE_START"] = 2] = "NETRACE_START";
|
|
225
|
+
ReservedCommands[ReservedCommands["NETRACE_STOP"] = 3] = "NETRACE_STOP";
|
|
226
|
+
ReservedCommands[ReservedCommands["NETRACE_USERNAME"] = 4] = "NETRACE_USERNAME";
|
|
227
|
+
ReservedCommands[ReservedCommands["NETRACE_USERDATA"] = 5] = "NETRACE_USERDATA";
|
|
228
|
+
ReservedCommands[ReservedCommands["PERSON_GET"] = 6] = "PERSON_GET";
|
|
229
|
+
ReservedCommands[ReservedCommands["PERSON_SET"] = 7] = "PERSON_SET";
|
|
230
|
+
ReservedCommands[ReservedCommands["PROGRAM_LIST_BEGIN"] = 8] = "PROGRAM_LIST_BEGIN";
|
|
231
|
+
ReservedCommands[ReservedCommands["PROGRAM_LIST_NEW_PROGRAM"] = 9] = "PROGRAM_LIST_NEW_PROGRAM";
|
|
232
|
+
ReservedCommands[ReservedCommands["PROGRAM_LIST_CONTINUE_PROGRAM"] = 10] = "PROGRAM_LIST_CONTINUE_PROGRAM";
|
|
233
|
+
ReservedCommands[ReservedCommands["PROGRAM_LIST_END"] = 11] = "PROGRAM_LIST_END";
|
|
234
|
+
ReservedCommands[ReservedCommands["PROGRAM_LIST_START"] = 12] = "PROGRAM_LIST_START";
|
|
235
|
+
ReservedCommands[ReservedCommands["RELAX_START"] = 12] = "RELAX_START";
|
|
236
|
+
ReservedCommands[ReservedCommands["RELAX_STOP"] = 14] = "RELAX_STOP";
|
|
237
|
+
ReservedCommands[ReservedCommands["RELAX_GET_DATA"] = 15] = "RELAX_GET_DATA";
|
|
238
|
+
ReservedCommands[ReservedCommands["KEY_PRESSED"] = 16] = "KEY_PRESSED";
|
|
239
|
+
ReservedCommands[ReservedCommands["PROGRAM_CONTROL"] = 17] = "PROGRAM_CONTROL";
|
|
240
|
+
})(ReservedCommands = exports.ReservedCommands || (exports.ReservedCommands = {}));
|
|
241
|
+
var BikeType;
|
|
242
|
+
(function (BikeType) {
|
|
243
|
+
BikeType[BikeType["ALLROUND"] = 0] = "ALLROUND";
|
|
244
|
+
BikeType[BikeType["RACE"] = 1] = "RACE";
|
|
245
|
+
BikeType[BikeType["MOUNTAIN"] = 2] = "MOUNTAIN";
|
|
246
|
+
})(BikeType = exports.BikeType || (exports.BikeType = {}));
|
|
247
|
+
function getBikeType(bikeTypeStr) {
|
|
248
|
+
if (bikeTypeStr === undefined || bikeTypeStr === null)
|
|
249
|
+
return BikeType.RACE;
|
|
250
|
+
if (bikeTypeStr.toLowerCase() === 'mountain')
|
|
251
|
+
return BikeType.MOUNTAIN;
|
|
252
|
+
return BikeType.RACE;
|
|
253
|
+
}
|
|
254
|
+
exports.getBikeType = getBikeType;
|
|
255
|
+
function routeToEpp(route, date) {
|
|
256
|
+
const buffer = Buffer.alloc(376 + route.points.length * 12);
|
|
257
|
+
const fileTime = win32filetime_1.default.fromUnix(date ? date : Date.now());
|
|
258
|
+
let offset = 0;
|
|
259
|
+
const name = route.name || '';
|
|
260
|
+
const description = route.description || '';
|
|
261
|
+
const minElevation = Math.min(...route.points.map(p => p.elevation));
|
|
262
|
+
const maxElevation = Math.max(...route.points.map(p => p.elevation));
|
|
263
|
+
const sampleRate = route.points.length !== 0 ? route.totalDistance / route.points.length : 0;
|
|
264
|
+
buffer.writeUInt32LE(fileTime.low, offset);
|
|
265
|
+
offset += 4;
|
|
266
|
+
buffer.writeUInt32LE(fileTime.high, offset);
|
|
267
|
+
offset += 4;
|
|
268
|
+
buffer.write(name, offset, name.length, 'ascii');
|
|
269
|
+
offset += 64;
|
|
270
|
+
buffer.write(description, offset, description.length, 'ascii');
|
|
271
|
+
offset += 256;
|
|
272
|
+
buffer.writeInt32LE(0x10, offset);
|
|
273
|
+
offset += 4;
|
|
274
|
+
buffer.writeInt32LE(0x0, offset);
|
|
275
|
+
offset += 4;
|
|
276
|
+
buffer.writeInt32LE(minElevation, offset);
|
|
277
|
+
offset += 4;
|
|
278
|
+
buffer.writeInt32LE(maxElevation, offset);
|
|
279
|
+
offset += 4;
|
|
280
|
+
buffer.writeInt32LE(route.points.length, offset);
|
|
281
|
+
offset += 4;
|
|
282
|
+
buffer.writeInt32LE(sampleRate, offset);
|
|
283
|
+
offset += 4;
|
|
284
|
+
buffer.writeInt32LE(0x01, offset);
|
|
285
|
+
offset += 4;
|
|
286
|
+
buffer.writeInt32LE(0x0, offset);
|
|
287
|
+
offset += 4;
|
|
288
|
+
buffer.writeInt16LE(0x0, offset);
|
|
289
|
+
offset += 2;
|
|
290
|
+
buffer.writeInt16LE(0x0, offset);
|
|
291
|
+
offset += 2;
|
|
292
|
+
buffer.writeInt32LE(0x0, offset);
|
|
293
|
+
offset += 4;
|
|
294
|
+
buffer.writeInt32LE(0x0, offset);
|
|
295
|
+
offset += 4;
|
|
296
|
+
buffer.writeInt32LE(0x0, offset);
|
|
297
|
+
offset += 4;
|
|
298
|
+
route.points.forEach(p => {
|
|
299
|
+
buffer.writeUInt32LE(sampleRate, offset);
|
|
300
|
+
offset += 4;
|
|
301
|
+
buffer.writeFloatLE(p.elevation, offset);
|
|
302
|
+
offset += 4;
|
|
303
|
+
buffer.writeFloatLE(0, offset);
|
|
304
|
+
offset += 4;
|
|
305
|
+
});
|
|
306
|
+
return new Uint8Array(buffer);
|
|
236
307
|
}
|
|
237
|
-
exports.
|
|
308
|
+
exports.routeToEpp = routeToEpp;
|
|
238
309
|
function parseTrainingData(payload) {
|
|
239
310
|
const GS = 0x1D;
|
|
240
311
|
const speedVals = ['ok', 'too low', 'too high'];
|
|
@@ -258,3 +329,47 @@ function parseTrainingData(payload) {
|
|
|
258
329
|
return data;
|
|
259
330
|
}
|
|
260
331
|
exports.parseTrainingData = parseTrainingData;
|
|
332
|
+
function getPersonData(user) {
|
|
333
|
+
const buffer = Buffer.alloc(136);
|
|
334
|
+
let offset = 0;
|
|
335
|
+
for (let i = 0; i < 4; i++) {
|
|
336
|
+
buffer.writeInt32LE(0, offset);
|
|
337
|
+
offset += 4;
|
|
338
|
+
buffer.writeFloatLE(-100, offset);
|
|
339
|
+
offset += 4;
|
|
340
|
+
buffer.writeFloatLE(0, offset);
|
|
341
|
+
offset += 4;
|
|
342
|
+
buffer.writeFloatLE(0, offset);
|
|
343
|
+
offset += 4;
|
|
344
|
+
buffer.writeUInt16LE(0, offset);
|
|
345
|
+
offset += 2;
|
|
346
|
+
buffer.writeUInt16LE(0, offset);
|
|
347
|
+
offset += 2;
|
|
348
|
+
buffer.writeUInt16LE(0, offset);
|
|
349
|
+
offset += 2;
|
|
350
|
+
buffer.writeUInt16LE(0, offset);
|
|
351
|
+
offset += 2;
|
|
352
|
+
buffer.writeUInt8(0, offset);
|
|
353
|
+
offset += 1;
|
|
354
|
+
buffer.writeUInt8(0, offset);
|
|
355
|
+
offset += 1;
|
|
356
|
+
buffer.writeUInt8(0, offset);
|
|
357
|
+
offset += 1;
|
|
358
|
+
buffer.writeUInt8(0, offset);
|
|
359
|
+
offset += 1;
|
|
360
|
+
}
|
|
361
|
+
buffer.writeInt32LE(user.sex === user_1.Gender.FEMALE ? 2 : 1, offset);
|
|
362
|
+
offset += 4;
|
|
363
|
+
buffer.writeInt32LE(user.age !== undefined ? user.age : utils_1.DEFAULT_AGE, offset);
|
|
364
|
+
offset += 4;
|
|
365
|
+
buffer.writeInt32LE(user.length !== undefined ? user.length : 180, offset);
|
|
366
|
+
offset += 4;
|
|
367
|
+
buffer.writeFloatLE(user.weight !== undefined ? user.weight : utils_1.DEFAULT_USER_WEIGHT, offset);
|
|
368
|
+
offset += 4;
|
|
369
|
+
buffer.writeFloatLE(0, offset);
|
|
370
|
+
offset += 4;
|
|
371
|
+
buffer.writeUInt32LE(0, offset);
|
|
372
|
+
offset += 4;
|
|
373
|
+
return buffer;
|
|
374
|
+
}
|
|
375
|
+
exports.getPersonData = getPersonData;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare type Point = {
|
|
2
|
+
lat?: number;
|
|
3
|
+
lng?: number;
|
|
4
|
+
elevation?: number;
|
|
5
|
+
distance: number;
|
|
6
|
+
slope?: number;
|
|
7
|
+
};
|
|
8
|
+
export declare enum RouteType {
|
|
9
|
+
FREE_RIDE = "free ride",
|
|
10
|
+
FOLLOW_ROUTE = "follow route",
|
|
11
|
+
VIDEO = "video"
|
|
12
|
+
}
|
|
13
|
+
export declare type Route = {
|
|
14
|
+
programId: number;
|
|
15
|
+
points: Point[];
|
|
16
|
+
type: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
lapMode: boolean;
|
|
20
|
+
totalDistance: number;
|
|
21
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RouteType = void 0;
|
|
4
|
+
var RouteType;
|
|
5
|
+
(function (RouteType) {
|
|
6
|
+
RouteType["FREE_RIDE"] = "free ride";
|
|
7
|
+
RouteType["FOLLOW_ROUTE"] = "follow route";
|
|
8
|
+
RouteType["VIDEO"] = "video";
|
|
9
|
+
})(RouteType = exports.RouteType || (exports.RouteType = {}));
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Gender = void 0;
|
|
4
|
+
var Gender;
|
|
5
|
+
(function (Gender) {
|
|
6
|
+
Gender["MALE"] = "M";
|
|
7
|
+
Gender["FEMALE"] = "F";
|
|
8
|
+
Gender["OTHERS"] = "o";
|
|
9
|
+
})(Gender = exports.Gender || (exports.Gender = {}));
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "incyclist-devices",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"@serialport/parser-byte-length": "^9.0.1",
|
|
6
6
|
"@serialport/parser-delimiter": "^9.0.1",
|
|
7
7
|
"@types/serialport": "^8.0.1",
|
|
8
|
-
"gd-ant-plus": "^0.0.33"
|
|
8
|
+
"gd-ant-plus": "^0.0.33",
|
|
9
|
+
"win32filetime": "^1.0.2"
|
|
9
10
|
},
|
|
10
11
|
"peerDependencies": {
|
|
11
12
|
"gd-eventlog": "^0.1.22"
|