incyclist-devices 1.4.1 → 1.4.4
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/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/bike.d.ts +3 -2
- package/lib/daum/classic/bike.js +5 -4
- package/lib/daum/classic/utils.d.ts +3 -1
- package/lib/daum/classic/utils.js +4 -16
- package/lib/daum/premium/DaumClassicCyclingMode.d.ts +14 -0
- package/lib/daum/premium/DaumClassicCyclingMode.js +87 -0
- package/lib/daum/premium/DaumPremiumAdapter.d.ts +3 -0
- package/lib/daum/premium/DaumPremiumAdapter.js +43 -3
- package/lib/daum/premium/bike.d.ts +12 -2
- package/lib/daum/premium/bike.js +133 -9
- 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;
|
|
@@ -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) {
|
|
@@ -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 const DEFAULT_AGE = 30;
|
|
2
|
+
export declare const DEFAULT_USER_WEIGHT = 75;
|
|
3
|
+
export declare const DEFAULT_BIKE_WEIGHT = 10;
|
|
1
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:
|
|
@@ -41,21 +44,6 @@ function getBikeType(type) {
|
|
|
41
44
|
}
|
|
42
45
|
}
|
|
43
46
|
exports.getBikeType = getBikeType;
|
|
44
|
-
function getAge(birthday) {
|
|
45
|
-
if (birthday === undefined) {
|
|
46
|
-
return 30;
|
|
47
|
-
}
|
|
48
|
-
try {
|
|
49
|
-
const bd = new Date(birthday);
|
|
50
|
-
const ageDifMs = Date.now() - bd.getTime();
|
|
51
|
-
var ageDate = new Date(ageDifMs);
|
|
52
|
-
return Math.abs(ageDate.getUTCFullYear() - 1970);
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
return 30;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
exports.getAge = getAge;
|
|
59
47
|
function getGender(sex) {
|
|
60
48
|
if (sex === undefined)
|
|
61
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,87 @@
|
|
|
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 distanceBike = data.distanceInternal || 0;
|
|
59
|
+
let distancePrev = prevData.distanceInternal || 0;
|
|
60
|
+
let distanceInternal = distanceBike;
|
|
61
|
+
let ts = Date.now();
|
|
62
|
+
if (!bikeData.pedalRpm || bikeData.isPedalling === false) {
|
|
63
|
+
speed = 0;
|
|
64
|
+
power = 0;
|
|
65
|
+
}
|
|
66
|
+
if (distanceBike < distancePrev) {
|
|
67
|
+
this.logger.logEvent({ message: '~~~ distance overflow', distanceBike, distancePrev });
|
|
68
|
+
let v = speed / 3.6;
|
|
69
|
+
let duration = this.prevUpdateTS === 0 ? 0 : ((ts - this.prevUpdateTS) / 1000);
|
|
70
|
+
distanceInternal = distancePrev + Math.round(v * duration);
|
|
71
|
+
}
|
|
72
|
+
data.speed = parseFloat(speed.toFixed(1));
|
|
73
|
+
data.power = Math.round(power);
|
|
74
|
+
data.distanceInternal = Math.round(distanceInternal);
|
|
75
|
+
data.distance = Math.round(distanceInternal / 100);
|
|
76
|
+
data.slope = slope;
|
|
77
|
+
this.logger.logEvent({ message: "updateData result", data, bikeData, prevRequest: {}, prevSpeed: prevData.speed });
|
|
78
|
+
this.data = JSON.parse(JSON.stringify(data));
|
|
79
|
+
this.prevUpdateTS = ts;
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
this.logger.logEvent({ message: 'error', fn: 'updateData()', error: err.message || err });
|
|
83
|
+
}
|
|
84
|
+
return data;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
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,26 @@ class DaumPremiumDevice extends DaumAdapter_1.default {
|
|
|
75
99
|
if (!info.version) {
|
|
76
100
|
info.version = yield this.bike.getProtocolVersion();
|
|
77
101
|
}
|
|
78
|
-
|
|
79
|
-
|
|
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
|
+
}
|
|
114
|
+
if (!this.getCyclingMode().getModeProperty('eppSupport')) {
|
|
115
|
+
const gear = yield this.bike.setGear(this.data.gear || (opts.gear || 10));
|
|
116
|
+
return gear;
|
|
117
|
+
}
|
|
118
|
+
return;
|
|
80
119
|
}
|
|
81
120
|
catch (err) {
|
|
121
|
+
console.error(err);
|
|
82
122
|
throw (new Error(`could not start device, reason:${err.message}`));
|
|
83
123
|
}
|
|
84
124
|
}), 5, 1000)
|
|
@@ -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 = {
|
|
@@ -574,20 +575,23 @@ class Daum8i {
|
|
|
574
575
|
this.logger.logEvent({ message: "sendCommand:sending NAK", port });
|
|
575
576
|
}
|
|
576
577
|
sendReservedDaum8iCommand(command, cmdType, data) {
|
|
577
|
-
let
|
|
578
|
-
const key = (0, utils_1.getReservedCommandKey)(command);
|
|
579
|
-
(0, utils_1.append)(cmdData, (0, utils_1.Int16ToIntArray)(key));
|
|
578
|
+
let buffer;
|
|
580
579
|
if (data !== undefined && data.length > 0) {
|
|
581
|
-
|
|
582
|
-
|
|
580
|
+
buffer = Buffer.alloc(data.length + 4);
|
|
581
|
+
buffer.writeInt16LE(command, 0);
|
|
582
|
+
buffer.writeUInt16LE(data.length, 2);
|
|
583
|
+
data.copy(buffer, 4);
|
|
583
584
|
}
|
|
584
585
|
else {
|
|
585
|
-
|
|
586
|
+
buffer = Buffer.alloc(4);
|
|
587
|
+
buffer.writeInt16LE(command, 0);
|
|
588
|
+
buffer.writeUInt16LE(0, 2);
|
|
586
589
|
}
|
|
590
|
+
const cmdData = Uint8Array.from(buffer);
|
|
587
591
|
return this.sendDaum8iCommand('M70', cmdType, (0, utils_1.bin2esc)(cmdData))
|
|
588
|
-
.then((
|
|
592
|
+
.then((res) => {
|
|
593
|
+
const resData = Uint8Array.from(res, x => x.charCodeAt(0));
|
|
589
594
|
const cmd = (0, utils_1.esc2bin)(resData);
|
|
590
|
-
cmd.splice(0, 4);
|
|
591
595
|
return cmd;
|
|
592
596
|
});
|
|
593
597
|
}
|
|
@@ -706,7 +710,127 @@ class Daum8i {
|
|
|
706
710
|
});
|
|
707
711
|
}
|
|
708
712
|
setPerson(person) {
|
|
709
|
-
|
|
713
|
+
this.logger.logEvent({ message: 'setPerson() request' });
|
|
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
|
+
const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PERSON_SET;
|
|
718
|
+
this.logger.logEvent({ message: 'setPerson() response', success, buffer });
|
|
719
|
+
if (!success)
|
|
720
|
+
throw new Error('Illegal Response');
|
|
721
|
+
return true;
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
programUploadInit() {
|
|
725
|
+
this.logger.logEvent({ message: 'programUploadInit() request' });
|
|
726
|
+
return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_BEGIN, 'BF')
|
|
727
|
+
.then((res) => {
|
|
728
|
+
const buffer = Buffer.from(res);
|
|
729
|
+
const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_BEGIN;
|
|
730
|
+
this.logger.logEvent({ message: 'programUploadInit() response', success, buffer });
|
|
731
|
+
if (!success)
|
|
732
|
+
throw new Error('Illegal Response');
|
|
733
|
+
return true;
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
programUploadStart(bikeType, route) {
|
|
737
|
+
const payload = Buffer.alloc(40);
|
|
738
|
+
const epp = (0, utils_1.routeToEpp)(route);
|
|
739
|
+
payload.writeInt32LE(0, 0);
|
|
740
|
+
payload.writeInt8(bikeType, 4);
|
|
741
|
+
payload.writeInt8(bikeType, 5);
|
|
742
|
+
payload.writeInt16LE(0, 6);
|
|
743
|
+
payload.writeInt32LE(0, 8);
|
|
744
|
+
payload.writeInt32LE(0, 12);
|
|
745
|
+
payload.writeFloatLE(0, 16);
|
|
746
|
+
payload.writeFloatLE(0, 20);
|
|
747
|
+
payload.writeInt16LE(0, 24);
|
|
748
|
+
payload.writeInt16LE(0, 26);
|
|
749
|
+
payload.writeInt16LE(0, 28);
|
|
750
|
+
payload.writeInt16LE(0, 30);
|
|
751
|
+
payload.writeInt32LE(7, 32);
|
|
752
|
+
payload.writeInt32LE(epp.length, 36);
|
|
753
|
+
this.logger.logEvent({ message: 'programUploadStart() request' });
|
|
754
|
+
return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_NEW_PROGRAM, 'BF', payload)
|
|
755
|
+
.then((res) => {
|
|
756
|
+
const buffer = Buffer.from(res);
|
|
757
|
+
if (buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_NEW_PROGRAM) {
|
|
758
|
+
this.logger.logEvent({ message: 'programUploadStart() response', success: true });
|
|
759
|
+
return epp;
|
|
760
|
+
}
|
|
761
|
+
this.logger.logEvent({ message: 'programUploadStart() response', success: false });
|
|
762
|
+
throw new Error('Illegal Response');
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
programUploadSendBlock(epp, offset) {
|
|
766
|
+
const remaining = epp.length - offset;
|
|
767
|
+
if (remaining <= 0)
|
|
768
|
+
return Promise.resolve(true);
|
|
769
|
+
const size = remaining > MAX_DATA_BLOCK_SIZE ? MAX_DATA_BLOCK_SIZE : remaining;
|
|
770
|
+
const payload = Buffer.alloc(size + 8);
|
|
771
|
+
payload.writeInt32LE(size, 0);
|
|
772
|
+
payload.writeInt32LE(offset, 4);
|
|
773
|
+
const chunk = Buffer.from(epp.slice(offset, offset + size));
|
|
774
|
+
chunk.copy(payload, 8);
|
|
775
|
+
this.logger.logEvent({ message: 'programUploadSendBlock() request', offset, size });
|
|
776
|
+
return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_CONTINUE_PROGRAM, 'BF', payload)
|
|
777
|
+
.then((res) => {
|
|
778
|
+
const buffer = Buffer.from(res);
|
|
779
|
+
let success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_CONTINUE_PROGRAM;
|
|
780
|
+
success = success && (buffer.readInt16LE(2) === 1);
|
|
781
|
+
success = success && (buffer.readInt8(4) === 1);
|
|
782
|
+
this.logger.logEvent({ message: 'programUploadSendBlock() response' });
|
|
783
|
+
if (!success)
|
|
784
|
+
throw new Error('Illegal Response');
|
|
785
|
+
return true;
|
|
786
|
+
;
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
programUploadDone() {
|
|
790
|
+
this.logger.logEvent({ message: 'programUploadDone() request' });
|
|
791
|
+
return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_END, 'BF')
|
|
792
|
+
.then((res) => {
|
|
793
|
+
const buffer = Buffer.from(res);
|
|
794
|
+
const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_END;
|
|
795
|
+
this.logger.logEvent({ message: 'programUploadDone() response', success });
|
|
796
|
+
if (!success)
|
|
797
|
+
throw new Error('Illegal Response');
|
|
798
|
+
return true;
|
|
799
|
+
;
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
programUpload(bikeType, route) {
|
|
803
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
804
|
+
yield this.programUploadInit();
|
|
805
|
+
const epp = yield this.programUploadStart(bikeType, route);
|
|
806
|
+
let success = true;
|
|
807
|
+
let done = false;
|
|
808
|
+
let offset = 0;
|
|
809
|
+
while (success && !done) {
|
|
810
|
+
success = yield this.programUploadSendBlock(epp, offset);
|
|
811
|
+
offset += MAX_DATA_BLOCK_SIZE;
|
|
812
|
+
done = offset >= epp.length;
|
|
813
|
+
}
|
|
814
|
+
if (done) {
|
|
815
|
+
return yield this.programUploadDone();
|
|
816
|
+
}
|
|
817
|
+
return false;
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
startProgram(programId = 1) {
|
|
821
|
+
const payload = Buffer.alloc(2);
|
|
822
|
+
payload.writeInt16LE(programId, 0);
|
|
823
|
+
this.logger.logEvent({ message: 'startProgram() request', programId });
|
|
824
|
+
return this.sendReservedDaum8iCommand(utils_1.ReservedCommands.PROGRAM_LIST_START, 'BF', payload)
|
|
825
|
+
.then((res) => {
|
|
826
|
+
const buffer = Buffer.from(res);
|
|
827
|
+
const success = buffer.readInt16LE(0) === utils_1.ReservedCommands.PROGRAM_LIST_START;
|
|
828
|
+
this.logger.logEvent({ message: 'startProgram() request', programId, success });
|
|
829
|
+
if (!success)
|
|
830
|
+
throw new Error('Illegal Response');
|
|
831
|
+
return true;
|
|
832
|
+
;
|
|
833
|
+
});
|
|
710
834
|
}
|
|
711
835
|
setGear(gear) {
|
|
712
836
|
return this.sendDaum8iCommand('M71', 'BF', `${gear}`)
|
|
@@ -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.4.
|
|
3
|
+
"version": "1.4.4",
|
|
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"
|