incyclist-devices 2.0.31 → 2.0.33
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/serial/adapter.d.ts +1 -0
- package/lib/serial/adapter.js +3 -0
- package/lib/serial/bindings/tcp.d.ts +2 -2
- package/lib/serial/bindings/tcp.js +7 -5
- package/lib/serial/daum/DaumAdapter.js +5 -3
- package/lib/serial/daum/classic/adapter.d.ts +2 -0
- package/lib/serial/daum/classic/adapter.js +4 -0
- package/lib/serial/daum/premium/adapter.d.ts +2 -0
- package/lib/serial/daum/premium/adapter.js +6 -4
- package/lib/serial/daum/premium/comms.d.ts +48 -27
- package/lib/serial/daum/premium/comms.js +287 -256
- package/lib/serial/kettler/comms.d.ts +1 -0
- package/lib/serial/kettler/comms.js +3 -0
- package/lib/serial/kettler/ergo-racer/adapter.d.ts +2 -0
- package/lib/serial/kettler/ergo-racer/adapter.js +4 -0
- package/lib/serial/serial-interface.d.ts +4 -0
- package/lib/serial/serial-interface.js +29 -4
- package/package.json +1 -1
package/lib/serial/adapter.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare class SerialIncyclistDevice extends ControllableDevice {
|
|
|
14
14
|
isEqual(settings: SerialDeviceSettings): boolean;
|
|
15
15
|
getPort(): string;
|
|
16
16
|
getUniqueName(): string;
|
|
17
|
+
getSerialInterface(): SerialInterface;
|
|
17
18
|
getInterface(): string;
|
|
18
19
|
setMaxUpdateFrequency(ms: number): void;
|
|
19
20
|
setPullFrequency(ms: number): void;
|
package/lib/serial/adapter.js
CHANGED
|
@@ -40,6 +40,9 @@ class SerialIncyclistDevice extends adpater_1.ControllableDevice {
|
|
|
40
40
|
getUniqueName() {
|
|
41
41
|
return `${this.getName()} (${this.getPort()})`;
|
|
42
42
|
}
|
|
43
|
+
getSerialInterface() {
|
|
44
|
+
throw new Error('not implemented');
|
|
45
|
+
}
|
|
43
46
|
getInterface() {
|
|
44
47
|
return 'serial';
|
|
45
48
|
}
|
|
@@ -7,14 +7,14 @@ export interface TCPOpenOptions extends OpenOptions {
|
|
|
7
7
|
timeout?: number;
|
|
8
8
|
}
|
|
9
9
|
export declare interface TCPBindingInterface<T extends BindingPortInterface = BindingPortInterface, R extends OpenOptions = OpenOptions, P extends PortInfo = PortInfo> extends BindingInterface<TCPPortBinding, TCPOpenOptions> {
|
|
10
|
-
list(port?: number): Promise<P[]>;
|
|
10
|
+
list(port?: number, excludeList?: string[]): Promise<P[]>;
|
|
11
11
|
}
|
|
12
12
|
export declare class CanceledError extends Error {
|
|
13
13
|
canceled: true;
|
|
14
14
|
constructor(message: string);
|
|
15
15
|
}
|
|
16
16
|
export declare function scanPort(host: string, port: number): Promise<boolean>;
|
|
17
|
-
export declare function scanSubNet(sn: string, port: number): Promise<string[]>;
|
|
17
|
+
export declare function scanSubNet(sn: string, port: number, excludeHosts?: string[]): Promise<string[]>;
|
|
18
18
|
export declare function getSubnets(): string[];
|
|
19
19
|
export declare const TCPBinding: TCPBindingInterface;
|
|
20
20
|
export declare class TCPPortBinding implements BindingPortInterface {
|
|
@@ -50,10 +50,11 @@ function scanPort(host, port) {
|
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
exports.scanPort = scanPort;
|
|
53
|
-
function scanSubNet(sn, port) {
|
|
53
|
+
function scanSubNet(sn, port, excludeHosts) {
|
|
54
54
|
const range = [];
|
|
55
55
|
for (let i = 1; i < 255; i++)
|
|
56
|
-
|
|
56
|
+
if (!excludeHosts || !excludeHosts.includes(`${sn}.${i}`))
|
|
57
|
+
range.push(i);
|
|
57
58
|
return Promise.all(range.map(j => scanPort(`${sn}.${j}`, port).then(success => success ? `${sn}.${j}` : null).catch()))
|
|
58
59
|
.then(hosts => hosts.filter(h => h !== null))
|
|
59
60
|
.catch();
|
|
@@ -86,13 +87,14 @@ function getSubnets() {
|
|
|
86
87
|
}
|
|
87
88
|
exports.getSubnets = getSubnets;
|
|
88
89
|
exports.TCPBinding = {
|
|
89
|
-
list(port) {
|
|
90
|
+
list(port, excludeList) {
|
|
90
91
|
return __awaiter(this, void 0, void 0, function* () {
|
|
91
92
|
if (!port)
|
|
92
93
|
return [];
|
|
93
94
|
const subnets = getSubnets();
|
|
94
|
-
|
|
95
|
-
|
|
95
|
+
let hosts = [];
|
|
96
|
+
const excludeHosts = excludeList.map(e => e && e.includes(':') ? e.split(':')[0] : e);
|
|
97
|
+
yield Promise.all(subnets.map(sn => scanSubNet(sn, port, excludeHosts).then(found => { hosts.push(...found); })));
|
|
96
98
|
return hosts.map(host => ({
|
|
97
99
|
path: `${host}:${port}`,
|
|
98
100
|
manufacturer: undefined,
|
|
@@ -199,8 +199,10 @@ class DaumAdapterBase extends adapter_1.SerialIncyclistDevice {
|
|
|
199
199
|
if (this.stopped)
|
|
200
200
|
return Promise.resolve(true);
|
|
201
201
|
this.logEvent({ message: 'stop request' });
|
|
202
|
+
if (this.paused)
|
|
203
|
+
this.resume();
|
|
202
204
|
this.stopped = true;
|
|
203
|
-
return new Promise((resolve, reject) => {
|
|
205
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
204
206
|
try {
|
|
205
207
|
if (this.iv) {
|
|
206
208
|
if (this.iv.sync)
|
|
@@ -211,15 +213,15 @@ class DaumAdapterBase extends adapter_1.SerialIncyclistDevice {
|
|
|
211
213
|
}
|
|
212
214
|
if (this.bike.stopWorker && typeof this.bike.stopWorker === 'function')
|
|
213
215
|
this.bike.stopWorker();
|
|
216
|
+
yield this.bike.close();
|
|
214
217
|
this.logEvent({ message: 'stop request completed' });
|
|
215
|
-
this.paused = undefined;
|
|
216
218
|
resolve(true);
|
|
217
219
|
}
|
|
218
220
|
catch (err) {
|
|
219
221
|
this.logEvent({ message: 'stop error', error: err.message });
|
|
220
222
|
reject(err);
|
|
221
223
|
}
|
|
222
|
-
});
|
|
224
|
+
}));
|
|
223
225
|
}
|
|
224
226
|
canSendUpdate() {
|
|
225
227
|
if (this.paused || this.stopped)
|
|
@@ -2,6 +2,7 @@ import CyclingMode from '../../../modes/cycling-mode';
|
|
|
2
2
|
import DaumAdapter from '../DaumAdapter';
|
|
3
3
|
import { DeviceProperties } from '../../../types/device';
|
|
4
4
|
import { SerialDeviceSettings } from '../../adapter';
|
|
5
|
+
import SerialInterface from '../../serial-interface';
|
|
5
6
|
export interface DaumClassicDeviceProperties extends DeviceProperties {
|
|
6
7
|
gear?: number;
|
|
7
8
|
}
|
|
@@ -21,6 +22,7 @@ export default class DaumClassicAdapter extends DaumAdapter {
|
|
|
21
22
|
getProtocolName(): string;
|
|
22
23
|
getSupportedCyclingModes(): Array<any>;
|
|
23
24
|
getDefaultCyclingMode(): CyclingMode;
|
|
25
|
+
getSerialInterface(): SerialInterface;
|
|
24
26
|
check(): Promise<boolean>;
|
|
25
27
|
performCheck(): Promise<boolean>;
|
|
26
28
|
pause(): Promise<boolean>;
|
|
@@ -80,6 +80,10 @@ class DaumClassicAdapter extends DaumAdapter_1.default {
|
|
|
80
80
|
getDefaultCyclingMode() {
|
|
81
81
|
return new daum_classic_1.default(this);
|
|
82
82
|
}
|
|
83
|
+
getSerialInterface() {
|
|
84
|
+
var _a;
|
|
85
|
+
return (_a = this.bike) === null || _a === void 0 ? void 0 : _a.serial;
|
|
86
|
+
}
|
|
83
87
|
check() {
|
|
84
88
|
return __awaiter(this, void 0, void 0, function* () {
|
|
85
89
|
if (this.isStopped())
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DeviceProperties } from '../../../types/device';
|
|
2
|
+
import { SerialInterface } from '../..';
|
|
2
3
|
import { SerialDeviceSettings } from '../../adapter';
|
|
3
4
|
import { SerialCommProps } from '../../comm';
|
|
4
5
|
import DaumAdapter from '../DaumAdapter';
|
|
@@ -14,6 +15,7 @@ export default class DaumPremiumAdapter extends DaumAdapter {
|
|
|
14
15
|
getPort(): any;
|
|
15
16
|
getInterface(): string;
|
|
16
17
|
getProtocolName(): string;
|
|
18
|
+
getSerialInterface(): SerialInterface;
|
|
17
19
|
isEqual(settings: SerialDeviceSettings): boolean;
|
|
18
20
|
getSupportedCyclingModes(): Array<any>;
|
|
19
21
|
check(): Promise<boolean>;
|
|
@@ -90,6 +90,10 @@ class DaumPremiumAdapter extends DaumAdapter_1.default {
|
|
|
90
90
|
getProtocolName() {
|
|
91
91
|
return PROTOCOL_NAME;
|
|
92
92
|
}
|
|
93
|
+
getSerialInterface() {
|
|
94
|
+
var _a;
|
|
95
|
+
return (_a = this.bike) === null || _a === void 0 ? void 0 : _a.serial;
|
|
96
|
+
}
|
|
93
97
|
isEqual(settings) {
|
|
94
98
|
if (this.getInterface() === device_1.INTERFACE.TCPIP) {
|
|
95
99
|
const as = this.settings;
|
|
@@ -186,9 +190,7 @@ class DaumPremiumAdapter extends DaumAdapter_1.default {
|
|
|
186
190
|
const { route, onStatusUpdate, gear } = props;
|
|
187
191
|
var info = {};
|
|
188
192
|
this.initData();
|
|
189
|
-
|
|
190
|
-
yield this.stop();
|
|
191
|
-
}
|
|
193
|
+
yield this.stop();
|
|
192
194
|
return (0, utils_1.runWithRetries)(() => __awaiter(this, void 0, void 0, function* () {
|
|
193
195
|
try {
|
|
194
196
|
yield this.connect();
|
|
@@ -240,7 +242,7 @@ class DaumPremiumAdapter extends DaumAdapter_1.default {
|
|
|
240
242
|
if (!this.bike.isConnected()) {
|
|
241
243
|
const connected = yield this.bike.connect();
|
|
242
244
|
if (!connected)
|
|
243
|
-
|
|
245
|
+
throw new Error('not connected');
|
|
244
246
|
}
|
|
245
247
|
return this.getBike().getTrainingData();
|
|
246
248
|
});
|
|
@@ -1,13 +1,39 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { ReservedCommands } from './utils';
|
|
3
3
|
import { SerialInterface, SerialPortProvider } from '../..';
|
|
4
|
-
import { Queue } from '../../../utils/utils';
|
|
5
4
|
import { EventLogger } from 'gd-eventlog';
|
|
6
5
|
import { User } from "../../../types/user";
|
|
7
6
|
import { Route } from "../../../types/route";
|
|
8
7
|
import { SerialCommProps } from "../../comm";
|
|
9
8
|
import { SerialPortStream } from "@serialport/stream";
|
|
10
9
|
import { OnDeviceStartCallback } from "./types";
|
|
10
|
+
import { Queue } from "../../../utils/utils";
|
|
11
|
+
export type ResponseObject = {
|
|
12
|
+
type: ResponseType;
|
|
13
|
+
data?: string;
|
|
14
|
+
error?: Error;
|
|
15
|
+
};
|
|
16
|
+
export type ResponseType = 'ACK' | 'NAK' | 'Response' | 'Error';
|
|
17
|
+
export type Daum8iCommsState = {
|
|
18
|
+
waitingForStart?: boolean;
|
|
19
|
+
waitingForACK?: boolean;
|
|
20
|
+
waitingForEnd?: boolean;
|
|
21
|
+
partialCmd?: any;
|
|
22
|
+
data: Queue<ResponseObject>;
|
|
23
|
+
};
|
|
24
|
+
export type ConnectionState = 'Connecting' | 'Connected' | 'Disconnected' | 'Disconnecting';
|
|
25
|
+
export declare class CheckSumError extends Error {
|
|
26
|
+
constructor();
|
|
27
|
+
}
|
|
28
|
+
export declare class ACKTimeout extends Error {
|
|
29
|
+
constructor();
|
|
30
|
+
}
|
|
31
|
+
export declare class BusyTimeout extends Error {
|
|
32
|
+
constructor();
|
|
33
|
+
}
|
|
34
|
+
export declare class ResponseTimeout extends Error {
|
|
35
|
+
constructor();
|
|
36
|
+
}
|
|
11
37
|
export default class Daum8i {
|
|
12
38
|
logger: EventLogger;
|
|
13
39
|
serial: SerialInterface;
|
|
@@ -18,17 +44,16 @@ export default class Daum8i {
|
|
|
18
44
|
};
|
|
19
45
|
port: string;
|
|
20
46
|
settings: any;
|
|
21
|
-
sp: SerialPortStream;
|
|
22
47
|
props: any;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
48
|
+
protected sp: SerialPortStream;
|
|
49
|
+
protected connectState: ConnectionState;
|
|
50
|
+
protected connectPromise: Promise<SerialPortStream>;
|
|
51
|
+
protected disconnectPromise: Promise<boolean>;
|
|
52
|
+
protected writePromise: Promise<void>;
|
|
53
|
+
protected sendCmdPromise: Promise<string>;
|
|
54
|
+
protected actualBikeType?: string;
|
|
55
|
+
protected recvState: Daum8iCommsState;
|
|
26
56
|
bikeData: any;
|
|
27
|
-
processor: any;
|
|
28
|
-
error: Error;
|
|
29
|
-
queue: Queue<any>;
|
|
30
|
-
cmdCurrent: any;
|
|
31
|
-
cmdStart: number;
|
|
32
57
|
isLoggingPaused: boolean;
|
|
33
58
|
spp: SerialPortProvider;
|
|
34
59
|
serialportProps: any;
|
|
@@ -40,29 +65,25 @@ export default class Daum8i {
|
|
|
40
65
|
resumeLogging(): void;
|
|
41
66
|
logEvent(e: any): void;
|
|
42
67
|
connect(): Promise<boolean>;
|
|
68
|
+
closePort(): Promise<boolean>;
|
|
69
|
+
cleanupPort(): void;
|
|
43
70
|
close(): Promise<boolean>;
|
|
44
71
|
flush(): Promise<void>;
|
|
45
|
-
getLogState(): {
|
|
46
|
-
sending: any;
|
|
47
|
-
busy: any;
|
|
48
|
-
writeBusy: any;
|
|
49
|
-
opening: any;
|
|
50
|
-
connecting: any;
|
|
51
|
-
waitingForStart: any;
|
|
52
|
-
waitingForEnd: any;
|
|
53
|
-
waitingForAck: any;
|
|
54
|
-
retry: any;
|
|
55
|
-
};
|
|
56
72
|
onPortClose(): Promise<void>;
|
|
57
|
-
onPortError(error:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
checkForResponse(): boolean;
|
|
73
|
+
onPortError(error: Error): Promise<void>;
|
|
74
|
+
isSending(): boolean;
|
|
75
|
+
rejectCurrent(error: Error): void;
|
|
61
76
|
getTimeoutValue(cmd?: any): number;
|
|
62
77
|
onData(data: any, depth?: number): any;
|
|
78
|
+
waitWithTimeout(promise: Promise<any>, timeout: number, onTimeout?: () => void): Promise<any>;
|
|
63
79
|
sendDaum8iCommand(command: string, payload?: string | any[]): Promise<string>;
|
|
64
|
-
|
|
65
|
-
|
|
80
|
+
onIgnored(payload: string): void;
|
|
81
|
+
onACK(): void;
|
|
82
|
+
onNAK: () => void;
|
|
83
|
+
waitForACK(): Promise<boolean>;
|
|
84
|
+
waitForResponse(): Promise<string>;
|
|
85
|
+
portWrite(buffer: Buffer): Promise<void>;
|
|
86
|
+
write(buffer: Buffer, ackExpected?: boolean): Promise<void>;
|
|
66
87
|
sendACK(): Promise<void>;
|
|
67
88
|
sendNAK(): Promise<void>;
|
|
68
89
|
sendReservedDaum8iCommand(command: ReservedCommands, data?: Buffer): Promise<any[]>;
|
|
@@ -9,9 +9,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ResponseTimeout = exports.BusyTimeout = exports.ACKTimeout = exports.CheckSumError = void 0;
|
|
12
13
|
const constants_1 = require("../constants");
|
|
13
14
|
const utils_1 = require("./utils");
|
|
14
15
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
16
|
+
const utils_2 = require("../../../utils/utils");
|
|
15
17
|
const DEFAULT_TIMEOUT = 10000;
|
|
16
18
|
const MAX_DATA_BLOCK_SIZE = 512;
|
|
17
19
|
const DS_BITS_OFF = 0;
|
|
@@ -34,9 +36,38 @@ const validatePath = (path) => {
|
|
|
34
36
|
const port = parts[1];
|
|
35
37
|
return `${host}:${port}`;
|
|
36
38
|
};
|
|
37
|
-
|
|
39
|
+
class CheckSumError extends Error {
|
|
40
|
+
constructor() {
|
|
41
|
+
super();
|
|
42
|
+
this.message = 'checksum incorrect';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.CheckSumError = CheckSumError;
|
|
46
|
+
class ACKTimeout extends Error {
|
|
47
|
+
constructor() {
|
|
48
|
+
super();
|
|
49
|
+
this.message = 'ACK timeout';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.ACKTimeout = ACKTimeout;
|
|
53
|
+
class BusyTimeout extends Error {
|
|
54
|
+
constructor() {
|
|
55
|
+
super();
|
|
56
|
+
this.message = 'BUSY timeout';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.BusyTimeout = BusyTimeout;
|
|
60
|
+
class ResponseTimeout extends Error {
|
|
61
|
+
constructor() {
|
|
62
|
+
super();
|
|
63
|
+
this.message = 'RESP timeout';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.ResponseTimeout = ResponseTimeout;
|
|
38
67
|
class Daum8i {
|
|
39
68
|
constructor(props) {
|
|
69
|
+
this.onNAK = () => {
|
|
70
|
+
};
|
|
40
71
|
this.props = props || {};
|
|
41
72
|
const { logger, serial, path } = props;
|
|
42
73
|
this.serial = serial;
|
|
@@ -44,12 +75,9 @@ class Daum8i {
|
|
|
44
75
|
const w = global.window;
|
|
45
76
|
this.logger = logger || ((w === null || w === void 0 ? void 0 : w.DEVICE_DEBUG) || process.env.DEBUG ? DEBUG_LOGGER : new gd_eventlog_1.EventLogger('DaumPremium'));
|
|
46
77
|
this.isLoggingPaused = false;
|
|
47
|
-
this.
|
|
48
|
-
this.
|
|
49
|
-
this.
|
|
50
|
-
ack: { wait: false, startWait: undefined },
|
|
51
|
-
commandsInQueue: {},
|
|
52
|
-
};
|
|
78
|
+
this.connectState = 'Disconnected';
|
|
79
|
+
this.connectPromise = null;
|
|
80
|
+
this.recvState = { data: new utils_2.Queue() };
|
|
53
81
|
this.settings = {};
|
|
54
82
|
this.bikeData = {
|
|
55
83
|
userWeight: 75,
|
|
@@ -65,7 +93,7 @@ class Daum8i {
|
|
|
65
93
|
return this.path;
|
|
66
94
|
}
|
|
67
95
|
isConnected() {
|
|
68
|
-
return this.
|
|
96
|
+
return this.connectState === 'Connected' || this.connectState === 'Disconnecting';
|
|
69
97
|
}
|
|
70
98
|
pauseLogging() {
|
|
71
99
|
this.isLoggingPaused = true;
|
|
@@ -87,159 +115,124 @@ class Daum8i {
|
|
|
87
115
|
if (this.isConnected() && this.sp) {
|
|
88
116
|
return true;
|
|
89
117
|
}
|
|
118
|
+
if (this.connectState === 'Connecting') {
|
|
119
|
+
if (this.connectPromise) {
|
|
120
|
+
try {
|
|
121
|
+
yield this.connectPromise;
|
|
122
|
+
}
|
|
123
|
+
catch (_a) {
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return this.isConnected();
|
|
127
|
+
}
|
|
90
128
|
try {
|
|
91
|
-
|
|
129
|
+
this.connectState = 'Connecting';
|
|
130
|
+
this.connectPromise = this.serial.openPort(this.path);
|
|
131
|
+
const port = yield this.connectPromise;
|
|
132
|
+
this.connectPromise = null;
|
|
92
133
|
if (port !== null) {
|
|
93
|
-
this.
|
|
134
|
+
this.connectState = 'Connected';
|
|
94
135
|
this.sp = port;
|
|
95
136
|
this.sp.on('close', this.onPortClose.bind(this));
|
|
96
|
-
this.sp.on('error',
|
|
97
|
-
this.sp.on('data',
|
|
137
|
+
this.sp.on('error', this.onPortError.bind(this));
|
|
138
|
+
this.sp.on('data', this.onData.bind(this));
|
|
98
139
|
return true;
|
|
99
140
|
}
|
|
100
141
|
else {
|
|
142
|
+
this.connectState = 'Disconnected';
|
|
101
143
|
return false;
|
|
102
144
|
}
|
|
103
145
|
}
|
|
104
|
-
catch (
|
|
146
|
+
catch (_b) {
|
|
147
|
+
this.connectState = 'Disconnected';
|
|
105
148
|
return false;
|
|
106
149
|
}
|
|
107
150
|
});
|
|
108
151
|
}
|
|
152
|
+
closePort() {
|
|
153
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
154
|
+
if (!this.sp)
|
|
155
|
+
return true;
|
|
156
|
+
try {
|
|
157
|
+
yield this.flush();
|
|
158
|
+
yield this.serial.closePort(this.path);
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
this.logEvent({ message: 'could not close ', reason: err.message });
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
cleanupPort() {
|
|
168
|
+
if (this.sp) {
|
|
169
|
+
this.sp.removeAllListeners();
|
|
170
|
+
}
|
|
171
|
+
this.sp = null;
|
|
172
|
+
this.recvState.data.clear();
|
|
173
|
+
}
|
|
109
174
|
close() {
|
|
110
175
|
return __awaiter(this, void 0, void 0, function* () {
|
|
111
|
-
|
|
176
|
+
let isDisconnected = false;
|
|
177
|
+
if (this.disconnectPromise) {
|
|
112
178
|
try {
|
|
113
|
-
yield this.
|
|
114
|
-
yield this.serial.closePort(this.path);
|
|
179
|
+
isDisconnected = yield this.disconnectPromise;
|
|
115
180
|
}
|
|
116
|
-
catch (
|
|
117
|
-
this.logEvent({ message: 'could not close ', reason: err.message });
|
|
118
|
-
return false;
|
|
181
|
+
catch (_a) {
|
|
119
182
|
}
|
|
183
|
+
return isDisconnected;
|
|
120
184
|
}
|
|
121
|
-
this.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
this.sp = null;
|
|
185
|
+
if (this.connectState === 'Disconnected') {
|
|
186
|
+
this.cleanupPort();
|
|
187
|
+
return true;
|
|
125
188
|
}
|
|
126
|
-
|
|
189
|
+
else if (this.connectState === 'Disconnecting' || this.connectState === 'Connected' || this.connectState === 'Connecting') {
|
|
190
|
+
this.connectState = 'Disconnecting';
|
|
191
|
+
this.disconnectPromise = this.closePort();
|
|
192
|
+
isDisconnected = yield this.disconnectPromise;
|
|
193
|
+
this.connectPromise = null;
|
|
194
|
+
this.disconnectPromise = null;
|
|
195
|
+
if (isDisconnected)
|
|
196
|
+
this.connectState = 'Disconnected';
|
|
197
|
+
this.cleanupPort();
|
|
198
|
+
}
|
|
199
|
+
return isDisconnected;
|
|
127
200
|
});
|
|
128
201
|
}
|
|
129
202
|
flush() {
|
|
130
203
|
return __awaiter(this, void 0, void 0, function* () {
|
|
131
|
-
if (
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (!this.state.writeBusy) {
|
|
136
|
-
clearInterval(iv);
|
|
137
|
-
this.writeDone();
|
|
138
|
-
done();
|
|
139
|
-
}
|
|
140
|
-
}, 100);
|
|
141
|
-
});
|
|
204
|
+
if (this.writePromise) {
|
|
205
|
+
yield this.waitWithTimeout(this.writePromise, 1000);
|
|
206
|
+
this.writePromise = null;
|
|
207
|
+
}
|
|
142
208
|
});
|
|
143
209
|
}
|
|
144
|
-
getLogState() {
|
|
145
|
-
let s = undefined;
|
|
146
|
-
const { sending, busy, opening, connecting, writeBusy, waitingForStart, waitingForAck, waitingForEnd, retry } = this.state;
|
|
147
|
-
if (sending) {
|
|
148
|
-
s = {};
|
|
149
|
-
s.command = sending.command;
|
|
150
|
-
s.payload = sending.payload;
|
|
151
|
-
}
|
|
152
|
-
return { sending: s, busy, writeBusy, opening, connecting, waitingForStart, waitingForEnd, waitingForAck, retry };
|
|
153
|
-
}
|
|
154
210
|
onPortClose() {
|
|
155
211
|
return __awaiter(this, void 0, void 0, function* () {
|
|
156
|
-
this.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
212
|
+
if (this.connectState !== 'Disconnected' && this.connectState !== 'Disconnecting')
|
|
213
|
+
this.logEvent({ message: "port closed:", port: this.path });
|
|
214
|
+
this.connectState = 'Disconnected';
|
|
215
|
+
this.cleanupPort();
|
|
161
216
|
});
|
|
162
217
|
}
|
|
163
218
|
onPortError(error) {
|
|
164
219
|
return __awaiter(this, void 0, void 0, function* () {
|
|
165
|
-
|
|
166
|
-
this.error = error;
|
|
167
|
-
if (this.blocked) {
|
|
168
|
-
if (!this.state.closed) {
|
|
169
|
-
yield this.close();
|
|
170
|
-
}
|
|
220
|
+
if (this.connectState === 'Disconnecting' || this.connectState === 'Disconnected') {
|
|
171
221
|
return;
|
|
172
222
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
this.writeDone();
|
|
177
|
-
yield this.close();
|
|
178
|
-
return;
|
|
223
|
+
this.logEvent({ message: "port error:", port: this.path, error: error.message, connected: this.isConnected(), state: this.connectState });
|
|
224
|
+
if (this.isSending()) {
|
|
225
|
+
this.rejectCurrent(error);
|
|
179
226
|
}
|
|
180
|
-
this.
|
|
227
|
+
if (this.connectState === 'Connected')
|
|
228
|
+
this.close();
|
|
181
229
|
});
|
|
182
230
|
}
|
|
183
|
-
|
|
184
|
-
return
|
|
185
|
-
if (!this.sp)
|
|
186
|
-
return;
|
|
187
|
-
try {
|
|
188
|
-
yield this.close();
|
|
189
|
-
this.writeDone();
|
|
190
|
-
if (this.queue !== undefined)
|
|
191
|
-
this.queue.clear();
|
|
192
|
-
}
|
|
193
|
-
catch (_a) { }
|
|
194
|
-
this.connected = false;
|
|
195
|
-
if (updateState)
|
|
196
|
-
this.state = { opened: false, closed: true, busy: false };
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
sendTimeout(message) {
|
|
200
|
-
this.logEvent({ message: `sendCommand:${message || 'timeout'}`, port: this.path, cmd: this.cmdCurrent });
|
|
201
|
-
delete this.state.commandsInQueue[this.cmdCurrent.command];
|
|
202
|
-
if (this.cmdCurrent.callbackErr !== undefined) {
|
|
203
|
-
let cb = this.cmdCurrent.callbackErr;
|
|
204
|
-
this.state.busy = false;
|
|
205
|
-
this.cmdCurrent = undefined;
|
|
206
|
-
this.cmdStart = undefined;
|
|
207
|
-
cb(408, { message: message || "timeout" });
|
|
208
|
-
}
|
|
231
|
+
isSending() {
|
|
232
|
+
return (this.writePromise !== undefined && this.writePromise !== null) || (this.sendCmdPromise !== null && this.sendCmdPromise !== undefined);
|
|
209
233
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const s = this.state.sending;
|
|
213
|
-
if (s === undefined)
|
|
214
|
-
return false;
|
|
215
|
-
const rejectFn = s.reject;
|
|
216
|
-
const reject = (err) => {
|
|
217
|
-
if (rejectFn && typeof rejectFn === 'function') {
|
|
218
|
-
rejectFn(err);
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
const error = this.state.error;
|
|
222
|
-
if (error !== undefined) {
|
|
223
|
-
reject(error);
|
|
224
|
-
return false;
|
|
225
|
-
}
|
|
226
|
-
try {
|
|
227
|
-
if (this.state.waitingForACK) {
|
|
228
|
-
const timeoutACK = this.state.ack ? this.state.ack.timeout : this.state.sending.timeout;
|
|
229
|
-
if (d < timeoutACK)
|
|
230
|
-
return true;
|
|
231
|
-
reject(new Error('ACK timeout'));
|
|
232
|
-
return false;
|
|
233
|
-
}
|
|
234
|
-
if (d < this.state.sending.timeout)
|
|
235
|
-
return true;
|
|
236
|
-
reject(new Error('RESP timeout'));
|
|
237
|
-
return false;
|
|
238
|
-
}
|
|
239
|
-
catch (err) {
|
|
240
|
-
this.logEvent({ message: 'checkForResponse: Exception', port: this.path, error: err.message, stack: err.stack });
|
|
241
|
-
}
|
|
242
|
-
return true;
|
|
234
|
+
rejectCurrent(error) {
|
|
235
|
+
this.recvState.data.enqueue({ type: 'Error', error });
|
|
243
236
|
}
|
|
244
237
|
getTimeoutValue(cmd) {
|
|
245
238
|
let timeout = DEFAULT_TIMEOUT;
|
|
@@ -254,18 +247,13 @@ class Daum8i {
|
|
|
254
247
|
return __awaiter(this, void 0, void 0, function* () {
|
|
255
248
|
let cmd = '';
|
|
256
249
|
const MAX_DEPTH = 5;
|
|
257
|
-
if (this.
|
|
258
|
-
cmd = this.
|
|
250
|
+
if (this.recvState.waitingForEnd) {
|
|
251
|
+
cmd = this.recvState.partialCmd;
|
|
259
252
|
}
|
|
260
253
|
const bufferData = Buffer.isBuffer(data) ? data : Buffer.from(data, 'latin1');
|
|
261
|
-
const s = this.state.sending;
|
|
262
|
-
if (s === undefined) {
|
|
263
|
-
this.logEvent({ message: 'onData:IGNORED', data: bufferData.toString('hex') });
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
const { portName, resolve } = this.state.sending;
|
|
267
254
|
let incoming = bufferData;
|
|
268
|
-
|
|
255
|
+
if (depth === 0)
|
|
256
|
+
this.logEvent({ message: 'sendCommand:RECV', data: (0, utils_1.hexstr)(incoming), state: this.recvState });
|
|
269
257
|
for (let i = 0; i < incoming.length; i++) {
|
|
270
258
|
const getRemaining = () => {
|
|
271
259
|
let remaining = '';
|
|
@@ -278,179 +266,222 @@ class Daum8i {
|
|
|
278
266
|
};
|
|
279
267
|
const c = incoming.readUInt8(i);
|
|
280
268
|
if (c === 0x06) {
|
|
281
|
-
this.
|
|
282
|
-
this.
|
|
269
|
+
this.recvState.waitingForStart = true;
|
|
270
|
+
this.recvState.waitingForACK = false;
|
|
283
271
|
const remaining = getRemaining();
|
|
284
|
-
this.
|
|
272
|
+
this.recvState.data.enqueue({ type: 'ACK' });
|
|
285
273
|
if (remaining && remaining !== '' && depth < MAX_DEPTH)
|
|
286
274
|
return this.onData(remaining, depth + 1);
|
|
287
275
|
}
|
|
288
276
|
else if (c === 0x15) {
|
|
289
|
-
this.
|
|
290
|
-
this.
|
|
277
|
+
this.recvState.waitingForStart = true;
|
|
278
|
+
this.recvState.waitingForACK = false;
|
|
291
279
|
const remaining = getRemaining();
|
|
292
|
-
this.
|
|
280
|
+
this.recvState.data.enqueue({ type: 'NAK' });
|
|
293
281
|
if (remaining && remaining !== '' && depth < MAX_DEPTH)
|
|
294
282
|
return this.onData(remaining, depth + 1);
|
|
295
283
|
}
|
|
296
284
|
else if (c === 0x01) {
|
|
297
|
-
this.
|
|
285
|
+
this.recvState.waitingForStart = false;
|
|
286
|
+
this.recvState.waitingForEnd = true;
|
|
298
287
|
}
|
|
299
288
|
else if (c === 0x17) {
|
|
300
289
|
const remaining = getRemaining();
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
290
|
+
this.recvState.waitingForEnd = false;
|
|
291
|
+
const cmdStr = cmd.substring(0, cmd.length - 2);
|
|
292
|
+
const checksumExtracted = cmd.slice(-2);
|
|
293
|
+
const checksumCalculated = (0, utils_1.checkSum)((0, utils_1.getAsciiArrayFromStr)(cmdStr), []);
|
|
294
|
+
if (checksumExtracted === checksumCalculated) {
|
|
295
|
+
const payload = cmd.substring(3, cmd.length - 2);
|
|
296
|
+
this.recvState.data.enqueue({ type: 'Response', data: payload });
|
|
304
297
|
}
|
|
305
298
|
else {
|
|
306
|
-
|
|
307
|
-
this.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
if (checksumExtracted === checksumCalculated) {
|
|
312
|
-
yield this.sendACK();
|
|
313
|
-
if (this.state.sending && this.state.sending.responseCheckIv) {
|
|
314
|
-
clearInterval(this.state.sending.responseCheckIv);
|
|
315
|
-
}
|
|
316
|
-
this.state = {
|
|
317
|
-
sending: undefined,
|
|
318
|
-
busy: false,
|
|
319
|
-
writeBusy: false,
|
|
320
|
-
waitingForStart: false,
|
|
321
|
-
waitingForEnd: false,
|
|
322
|
-
waitingForACK: false,
|
|
323
|
-
};
|
|
324
|
-
const payload = cmd.substring(3, cmd.length - 2);
|
|
325
|
-
resolve(payload);
|
|
326
|
-
}
|
|
327
|
-
else {
|
|
328
|
-
yield this.sendNAK();
|
|
329
|
-
}
|
|
299
|
+
const error = new CheckSumError();
|
|
300
|
+
this.recvState.data.enqueue({ type: 'Error', error, data: cmd });
|
|
301
|
+
this.recvState.waitingForACK = false;
|
|
302
|
+
this.recvState.waitingForStart = true;
|
|
303
|
+
this.recvState.waitingForEnd = false;
|
|
330
304
|
}
|
|
331
305
|
cmd = '';
|
|
332
306
|
if (remaining && depth < 5)
|
|
333
307
|
return this.onData(remaining, depth + 1);
|
|
334
308
|
}
|
|
335
309
|
else {
|
|
336
|
-
if (this.
|
|
310
|
+
if (this.recvState.waitingForEnd)
|
|
337
311
|
cmd += String.fromCharCode(c);
|
|
338
312
|
}
|
|
339
313
|
}
|
|
340
|
-
if (this.
|
|
341
|
-
this.
|
|
314
|
+
if (this.recvState.waitingForEnd) {
|
|
315
|
+
this.recvState.partialCmd = cmd;
|
|
342
316
|
}
|
|
343
317
|
});
|
|
344
318
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
return
|
|
350
|
-
|
|
351
|
-
|
|
319
|
+
waitWithTimeout(promise, timeout, onTimeout) {
|
|
320
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
321
|
+
let to;
|
|
322
|
+
const toPromise = (ms) => {
|
|
323
|
+
return new Promise(resolve => { to = setTimeout(resolve, ms); });
|
|
324
|
+
};
|
|
325
|
+
let res;
|
|
326
|
+
try {
|
|
327
|
+
res = yield Promise.race([promise, toPromise(timeout).then(() => { if (onTimeout)
|
|
328
|
+
onTimeout(); })]);
|
|
352
329
|
}
|
|
353
|
-
|
|
354
|
-
|
|
330
|
+
catch (_a) {
|
|
331
|
+
}
|
|
332
|
+
clearTimeout(to);
|
|
333
|
+
return res;
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
sendDaum8iCommand(command, payload = '') {
|
|
337
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
338
|
+
const message = (0, utils_1.buildMessage)(command, payload);
|
|
339
|
+
const tsRequest = Date.now();
|
|
340
|
+
if (this.sendCmdPromise) {
|
|
355
341
|
this.logEvent({ message: 'sendCommand:waiting', port: this.path, cmd: command, hex: (0, utils_1.hexstr)(message) });
|
|
356
|
-
const
|
|
357
|
-
return new Promise((done) => {
|
|
358
|
-
let start = Date.now();
|
|
359
|
-
let timeout = start + 5000;
|
|
360
|
-
const iv = setInterval(() => {
|
|
361
|
-
if (this.state.busy) {
|
|
362
|
-
if (Date.now() > timeout) {
|
|
363
|
-
clearInterval(iv);
|
|
364
|
-
done(false);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
else {
|
|
368
|
-
clearInterval(iv);
|
|
369
|
-
done(true);
|
|
370
|
-
}
|
|
371
|
-
}, 10);
|
|
372
|
-
});
|
|
373
|
-
};
|
|
374
|
-
const res = yield busyWait();
|
|
375
|
-
if (!res) {
|
|
342
|
+
const onTimeout = () => {
|
|
376
343
|
this.logEvent({ message: 'sendCommand:busy timeout', port: this.path, cmd: command, hex: (0, utils_1.hexstr)(message), duration: Date.now() - tsRequest });
|
|
377
|
-
|
|
344
|
+
throw new Error('BUSY timeout');
|
|
345
|
+
};
|
|
346
|
+
this.waitWithTimeout(this.sendCmdPromise, 5000, onTimeout);
|
|
347
|
+
this.sendCmdPromise = null;
|
|
348
|
+
}
|
|
349
|
+
this.sendCmdPromise = new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
350
|
+
try {
|
|
351
|
+
this.logEvent({ message: "sendCommand:sending:", port: this.path, cmd: command, hex: (0, utils_1.hexstr)(message) });
|
|
352
|
+
if (!this.isConnected()) {
|
|
353
|
+
const connected = yield this.connect();
|
|
354
|
+
if (!connected) {
|
|
355
|
+
reject(new Error('not connected'));
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
let retryCnt = 0;
|
|
360
|
+
let ok = false;
|
|
361
|
+
do {
|
|
362
|
+
yield this.write(Buffer.from(message));
|
|
363
|
+
ok = yield this.waitForACK();
|
|
364
|
+
if (!ok) {
|
|
365
|
+
yield (0, utils_2.sleep)(1000);
|
|
366
|
+
retryCnt++;
|
|
367
|
+
}
|
|
368
|
+
} while (!ok && retryCnt < 5);
|
|
369
|
+
const res = yield this.waitForResponse();
|
|
370
|
+
this.sendCmdPromise = null;
|
|
371
|
+
resolve(res);
|
|
372
|
+
}
|
|
373
|
+
catch (err) {
|
|
374
|
+
this.logEvent({ message: "sendCommand:error:", port: this.path, error: err.message, stack: err.stack });
|
|
375
|
+
this.sendCmdPromise = null;
|
|
376
|
+
reject(err);
|
|
377
|
+
}
|
|
378
|
+
}));
|
|
379
|
+
return this.sendCmdPromise;
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
onIgnored(payload) {
|
|
383
|
+
this.logEvent({ message: 'onData:IGNORED', port: this.path, data: payload });
|
|
384
|
+
}
|
|
385
|
+
onACK() {
|
|
386
|
+
}
|
|
387
|
+
waitForACK() {
|
|
388
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
389
|
+
this.recvState.waitingForACK = true;
|
|
390
|
+
const timeout = this.getTimeoutValue();
|
|
391
|
+
let waitingForACK = true;
|
|
392
|
+
let start = Date.now();
|
|
393
|
+
let tsTimeout = start + timeout;
|
|
394
|
+
while (waitingForACK && Date.now() < tsTimeout) {
|
|
395
|
+
const response = this.recvState.data.dequeue();
|
|
396
|
+
if (!response) {
|
|
397
|
+
yield (0, utils_2.sleep)(5);
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
if (response.type === 'ACK' || response.type === 'NAK') {
|
|
401
|
+
this.logEvent({ message: `sendCommand:${response.type} received:`, port: this.path });
|
|
402
|
+
waitingForACK = false;
|
|
403
|
+
return (response.type === 'ACK');
|
|
404
|
+
}
|
|
378
405
|
}
|
|
379
|
-
this.state.busy = true;
|
|
380
406
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
407
|
+
throw new ACKTimeout();
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
waitForResponse() {
|
|
411
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
412
|
+
const timeout = this.getTimeoutValue();
|
|
413
|
+
let waitingForResponse = true;
|
|
414
|
+
let start = Date.now();
|
|
415
|
+
let tsTimeout = start + timeout;
|
|
416
|
+
let retry = 0;
|
|
417
|
+
while (waitingForResponse && Date.now() < tsTimeout && retry < 5) {
|
|
418
|
+
const response = this.recvState.data.dequeue();
|
|
419
|
+
if (!response) {
|
|
420
|
+
yield (0, utils_2.sleep)(5);
|
|
394
421
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
422
|
+
else {
|
|
423
|
+
if (response.type === 'Response') {
|
|
424
|
+
this.logEvent({ message: `sendCommand:received:`, port: this.path, cmd: response.data });
|
|
425
|
+
yield this.sendACK();
|
|
426
|
+
waitingForResponse = false;
|
|
427
|
+
return response.data;
|
|
428
|
+
}
|
|
429
|
+
if (response.type === 'Error') {
|
|
430
|
+
this.logEvent({ message: `sendCommand:received:ERROR`, port: this.path, error: response.error.message });
|
|
431
|
+
if (response.error instanceof CheckSumError && retry < 5) {
|
|
432
|
+
yield this.sendNAK();
|
|
433
|
+
retry++;
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
throw response.error;
|
|
437
|
+
}
|
|
406
438
|
}
|
|
407
|
-
}
|
|
408
|
-
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
throw new ResponseTimeout();
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
portWrite(buffer) {
|
|
445
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
446
|
+
if (!this.sp) {
|
|
447
|
+
this.logEvent({ message: 'write failed', error: 'port is not opened' });
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
try {
|
|
451
|
+
yield this.sp.write(buffer);
|
|
409
452
|
}
|
|
410
453
|
catch (err) {
|
|
411
|
-
this.logEvent({ message:
|
|
412
|
-
this.writeDone();
|
|
413
|
-
reject(err);
|
|
454
|
+
this.logEvent({ message: 'write failed', error: err.message });
|
|
414
455
|
}
|
|
415
|
-
})
|
|
416
|
-
}
|
|
417
|
-
writeDone() {
|
|
418
|
-
this.state.writeBusy = false;
|
|
419
|
-
this.state.busy = false;
|
|
420
|
-
if (this.state.sending && this.state.sending.responseCheckIv) {
|
|
421
|
-
clearInterval(this.state.sending.responseCheckIv);
|
|
422
|
-
}
|
|
423
|
-
this.state.sending = undefined;
|
|
424
|
-
this.state.waitingForStart = false;
|
|
425
|
-
this.state.waitingForEnd = false;
|
|
426
|
-
this.state.waitingForACK = false;
|
|
456
|
+
});
|
|
427
457
|
}
|
|
428
|
-
write(buffer) {
|
|
458
|
+
write(buffer, ackExpected = true) {
|
|
429
459
|
return __awaiter(this, void 0, void 0, function* () {
|
|
430
|
-
|
|
431
|
-
this.state.writeBusy = true;
|
|
460
|
+
if (this.writePromise) {
|
|
432
461
|
try {
|
|
433
|
-
yield this.
|
|
434
|
-
this.state.writeBusy = false;
|
|
435
|
-
done();
|
|
462
|
+
yield this.writePromise;
|
|
436
463
|
}
|
|
437
|
-
catch (
|
|
438
|
-
this.state.writeBusy = false;
|
|
439
|
-
done();
|
|
464
|
+
catch (_a) {
|
|
440
465
|
}
|
|
441
|
-
|
|
466
|
+
this.writePromise = null;
|
|
467
|
+
}
|
|
468
|
+
this.writePromise = this.portWrite(buffer);
|
|
469
|
+
if (ackExpected)
|
|
470
|
+
this.recvState.waitingForACK = true;
|
|
471
|
+
yield this.writePromise;
|
|
472
|
+
this.writePromise = null;
|
|
442
473
|
});
|
|
443
474
|
}
|
|
444
475
|
sendACK() {
|
|
445
476
|
return __awaiter(this, void 0, void 0, function* () {
|
|
446
|
-
this.logEvent({ message: "sendCommand:sending ACK", port: this.path
|
|
447
|
-
yield this.write(Buffer.from([0x06]));
|
|
477
|
+
this.logEvent({ message: "sendCommand:sending ACK", port: this.path });
|
|
478
|
+
yield this.write(Buffer.from([0x06]), false);
|
|
448
479
|
});
|
|
449
480
|
}
|
|
450
481
|
sendNAK() {
|
|
451
482
|
return __awaiter(this, void 0, void 0, function* () {
|
|
452
|
-
this.logEvent({ message: "sendCommand:sending NAK", port: this.path
|
|
453
|
-
yield this.write(Buffer.from([0x15]));
|
|
483
|
+
this.logEvent({ message: "sendCommand:sending NAK", port: this.path });
|
|
484
|
+
yield this.write(Buffer.from([0x15]), false);
|
|
454
485
|
});
|
|
455
486
|
}
|
|
456
487
|
sendReservedDaum8iCommand(command, data) {
|
|
@@ -512,7 +543,7 @@ class Daum8i {
|
|
|
512
543
|
else {
|
|
513
544
|
throw (new Error(`unknown actual device type ${typeof str === 'string' ? (0, utils_1.ascii)(str.charAt(0)) : str}`));
|
|
514
545
|
}
|
|
515
|
-
this.
|
|
546
|
+
this.actualBikeType = deviceType;
|
|
516
547
|
return deviceType;
|
|
517
548
|
});
|
|
518
549
|
}
|
|
@@ -545,7 +576,7 @@ class Daum8i {
|
|
|
545
576
|
deviceType = constants_1.ACTUAL_BIKE_TYPE.MOUNTAIN;
|
|
546
577
|
else
|
|
547
578
|
throw (new Error('unknown actual device type'));
|
|
548
|
-
this.
|
|
579
|
+
this.actualBikeType = deviceType;
|
|
549
580
|
return deviceType;
|
|
550
581
|
});
|
|
551
582
|
}
|
|
@@ -46,6 +46,7 @@ export default class KettlerSerialComms<T extends Command> extends EventEmitter
|
|
|
46
46
|
_setSendState(state: SendState): void;
|
|
47
47
|
_setCurrentCmd(cmd: T): void;
|
|
48
48
|
stopCurrentTimeoutCheck(): void;
|
|
49
|
+
getSerialInterface(): SerialInterface;
|
|
49
50
|
onPortOpen(): void;
|
|
50
51
|
onPortClose(): Promise<void>;
|
|
51
52
|
onPortError(err: any): void;
|
|
@@ -102,6 +102,9 @@ class KettlerSerialComms extends events_1.default {
|
|
|
102
102
|
this.currentTimeout = undefined;
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
|
+
getSerialInterface() {
|
|
106
|
+
return this.serial;
|
|
107
|
+
}
|
|
105
108
|
onPortOpen() {
|
|
106
109
|
this.logger.logEvent({ message: 'port opened', port: this.getPort() });
|
|
107
110
|
this.state = SerialCommsState.Connected;
|
|
@@ -5,6 +5,7 @@ import { Command } from "../../../types/command";
|
|
|
5
5
|
import CyclingMode, { IncyclistBikeData } from "../../../modes/cycling-mode";
|
|
6
6
|
import { SerialDeviceSettings, SerialIncyclistDevice } from "../../adapter";
|
|
7
7
|
import { DeviceData } from "../../../types/data";
|
|
8
|
+
import SerialInterface from "../../serial-interface";
|
|
8
9
|
export interface KettlerRacerCommand extends Command {
|
|
9
10
|
}
|
|
10
11
|
export interface KettlerExtendedBikeData {
|
|
@@ -44,6 +45,7 @@ export default class KettlerRacerAdapter extends SerialIncyclistDevice {
|
|
|
44
45
|
getID(): string;
|
|
45
46
|
getName(): string;
|
|
46
47
|
getPort(): string;
|
|
48
|
+
getSerialInterface(): SerialInterface;
|
|
47
49
|
_getComms(): SerialComms<KettlerRacerCommand>;
|
|
48
50
|
_setComms(comms: SerialComms<KettlerRacerCommand>): void;
|
|
49
51
|
getLogger(): EventLogger;
|
|
@@ -58,6 +58,10 @@ class KettlerRacerAdapter extends adapter_1.SerialIncyclistDevice {
|
|
|
58
58
|
const settings = this.settings;
|
|
59
59
|
return settings.port;
|
|
60
60
|
}
|
|
61
|
+
getSerialInterface() {
|
|
62
|
+
if (this.comms)
|
|
63
|
+
return this.comms.getSerialInterface();
|
|
64
|
+
}
|
|
61
65
|
_getComms() {
|
|
62
66
|
return this.comms;
|
|
63
67
|
}
|
|
@@ -30,6 +30,7 @@ export declare class SinglePathScanner {
|
|
|
30
30
|
isScanning: boolean;
|
|
31
31
|
props: SerialScannerProps;
|
|
32
32
|
logger: EventLogger;
|
|
33
|
+
isFound: boolean;
|
|
33
34
|
constructor(path: string, serial: SerialInterface, props: SerialScannerProps);
|
|
34
35
|
logEvent(event: any): void;
|
|
35
36
|
onStopRequest(resolve: any): Promise<void>;
|
|
@@ -45,6 +46,7 @@ export default class SerialInterface extends EventEmitter implements IncyclistIn
|
|
|
45
46
|
logger: EventLogger;
|
|
46
47
|
toScan: NodeJS.Timeout;
|
|
47
48
|
connected: boolean;
|
|
49
|
+
inUse: string[];
|
|
48
50
|
static _instances: SerialInterface[];
|
|
49
51
|
static getInstance(props: SerialInterfaceProps): SerialInterface;
|
|
50
52
|
static _add(instance: SerialInterface): void;
|
|
@@ -53,6 +55,8 @@ export default class SerialInterface extends EventEmitter implements IncyclistIn
|
|
|
53
55
|
setBinding(binding: BindingInterface): void;
|
|
54
56
|
getName(): string;
|
|
55
57
|
isConnected(): boolean;
|
|
58
|
+
setInUse(path: string): void;
|
|
59
|
+
releaseInUse(path: string): void;
|
|
56
60
|
connect(): Promise<boolean>;
|
|
57
61
|
disconnect(): Promise<boolean>;
|
|
58
62
|
openPort(path: string): Promise<SerialPortStream | null>;
|
|
@@ -18,6 +18,7 @@ const serialport_1 = __importDefault(require("./serialport"));
|
|
|
18
18
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
19
19
|
const utils_1 = require("../utils/utils");
|
|
20
20
|
const adapters_1 = __importDefault(require("../adapters"));
|
|
21
|
+
const adapter_factory_1 = __importDefault(require("./adapter-factory"));
|
|
21
22
|
const DEFAULT_SCAN_TIMEOUT = 10000;
|
|
22
23
|
exports.SerialInterfaceType = {
|
|
23
24
|
SERIAL: 'serial',
|
|
@@ -29,6 +30,7 @@ class SinglePathScanner {
|
|
|
29
30
|
this.serial = serial;
|
|
30
31
|
this.result = undefined;
|
|
31
32
|
this.isScanning = false;
|
|
33
|
+
this.isFound = false;
|
|
32
34
|
this.props = props;
|
|
33
35
|
this.logger = props.logger || new gd_eventlog_1.EventLogger('SerialScanner');
|
|
34
36
|
}
|
|
@@ -44,7 +46,8 @@ class SinglePathScanner {
|
|
|
44
46
|
onStopRequest(resolve) {
|
|
45
47
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
48
|
this.logEvent({ message: 'stopping scan', path: this.path });
|
|
47
|
-
|
|
49
|
+
if (!this.isFound)
|
|
50
|
+
yield this.serial.closePort(this.path);
|
|
48
51
|
this.isScanning = false;
|
|
49
52
|
resolve(this.result);
|
|
50
53
|
});
|
|
@@ -73,8 +76,8 @@ class SinglePathScanner {
|
|
|
73
76
|
const adapter = adapters_1.default.create(adapterSettings);
|
|
74
77
|
found = yield adapter.check();
|
|
75
78
|
if (found) {
|
|
79
|
+
this.isFound = true;
|
|
76
80
|
const name = adapter.getName();
|
|
77
|
-
yield this.serial.closePort(this.path).catch();
|
|
78
81
|
resolve(Object.assign(Object.assign({}, adapterSettings), { name }));
|
|
79
82
|
}
|
|
80
83
|
yield (0, utils_1.sleep)(100);
|
|
@@ -117,6 +120,7 @@ class SerialInterface extends events_1.default {
|
|
|
117
120
|
this.ifaceName = ifaceName;
|
|
118
121
|
this.binding = undefined;
|
|
119
122
|
this.ports = [];
|
|
123
|
+
this.inUse = [];
|
|
120
124
|
this.isScanning = false;
|
|
121
125
|
this.isStopScanRequested = false;
|
|
122
126
|
this.scanEvents = new events_1.default();
|
|
@@ -148,6 +152,18 @@ class SerialInterface extends events_1.default {
|
|
|
148
152
|
isConnected() {
|
|
149
153
|
return this.connected;
|
|
150
154
|
}
|
|
155
|
+
setInUse(path) {
|
|
156
|
+
this.logEvent({ message: 'block port for further scans', port: path });
|
|
157
|
+
if (!this.inUse.includes(path))
|
|
158
|
+
this.inUse.push(path);
|
|
159
|
+
}
|
|
160
|
+
releaseInUse(path) {
|
|
161
|
+
if (this.inUse.includes(path)) {
|
|
162
|
+
this.logEvent({ message: 're-enable port for further scans', port: path });
|
|
163
|
+
const idx = this.inUse.findIndex(r => r === path);
|
|
164
|
+
this.inUse.splice(idx, 1);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
151
167
|
connect() {
|
|
152
168
|
return __awaiter(this, void 0, void 0, function* () {
|
|
153
169
|
const binding = serialport_1.default.getInstance().getBinding(this.ifaceName);
|
|
@@ -255,13 +271,18 @@ class SerialInterface extends events_1.default {
|
|
|
255
271
|
this.scanEvents.emit('timeout');
|
|
256
272
|
}, timeout);
|
|
257
273
|
}
|
|
258
|
-
this.logEvent({ message: 'checking for ports' });
|
|
259
274
|
this.isScanning = true;
|
|
275
|
+
let attemptNo = 0;
|
|
260
276
|
do {
|
|
277
|
+
if (attemptNo === 0)
|
|
278
|
+
this.logEvent({ message: 'checking for ports', port, excludes: this.inUse });
|
|
279
|
+
else
|
|
280
|
+
this.logEvent({ message: 'checking for ports retry', retry: attemptNo });
|
|
281
|
+
attemptNo++;
|
|
261
282
|
try {
|
|
262
283
|
if (this.getName() === 'tcpip') {
|
|
263
284
|
const _binding = binding;
|
|
264
|
-
paths = (yield _binding.list(port)) || [];
|
|
285
|
+
paths = (yield _binding.list(port, this.inUse)) || [];
|
|
265
286
|
}
|
|
266
287
|
else {
|
|
267
288
|
paths = (yield binding.list()) || [];
|
|
@@ -277,6 +298,7 @@ class SerialInterface extends events_1.default {
|
|
|
277
298
|
if (Date.now() > toExpiresAt)
|
|
278
299
|
timeOutExpired = true;
|
|
279
300
|
} while (this.isScanning && !timeOutExpired && paths.length === 0);
|
|
301
|
+
paths = paths.filter(p => !this.inUse.includes(p.path));
|
|
280
302
|
if (paths.length === 0) {
|
|
281
303
|
this.logEvent({ message: 'nothing to scan ' });
|
|
282
304
|
if (this.toScan) {
|
|
@@ -291,6 +313,9 @@ class SerialInterface extends events_1.default {
|
|
|
291
313
|
yield Promise.all(scanners.map(s => s.scan()
|
|
292
314
|
.then(device => {
|
|
293
315
|
if (device) {
|
|
316
|
+
const adapter = adapter_factory_1.default.getInstance().createInstance(device);
|
|
317
|
+
const path = adapter.getPort();
|
|
318
|
+
this.inUse.push(path);
|
|
294
319
|
detected.push(device);
|
|
295
320
|
this.emit('device', device);
|
|
296
321
|
}
|