@v5x/serial 0.5.6 → 0.5.7
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/README.md +37 -4
- package/dist/Vex.d.ts +3 -1
- package/dist/VexConnection.d.ts +48 -3
- package/dist/VexDevice.d.ts +22 -1
- package/dist/VexDeviceState.d.ts +18 -5
- package/dist/VexError.d.ts +1 -0
- package/dist/VexEvent.d.ts +0 -1
- package/dist/VexFirmware.d.ts +1 -0
- package/dist/VexPacketCore.d.ts +5 -0
- package/dist/VexPacketEncoder.d.ts +2 -0
- package/dist/VexPacketModels.d.ts +1 -1
- package/dist/VexPacketRegistry.d.ts +3 -0
- package/dist/VexScreenCapture.d.ts +2 -0
- package/dist/VexTransfers.d.ts +1 -0
- package/dist/index.cjs +802 -963
- package/dist/index.cjs.map +14 -14
- package/dist/index.js +898 -1011
- package/dist/index.js.map +14 -14
- package/dist/packet-core.cjs +383 -0
- package/dist/packet-core.cjs.map +14 -0
- package/dist/packet-core.js +341 -0
- package/dist/packet-core.js.map +14 -0
- package/package.json +11 -4
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
3
1
|
var __defProp = Object.defineProperty;
|
|
4
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -7,30 +5,6 @@ var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
|
7
5
|
function __accessProp(key) {
|
|
8
6
|
return this[key];
|
|
9
7
|
}
|
|
10
|
-
var __toESMCache_node;
|
|
11
|
-
var __toESMCache_esm;
|
|
12
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
13
|
-
var canCache = mod != null && typeof mod === "object";
|
|
14
|
-
if (canCache) {
|
|
15
|
-
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
16
|
-
var cached = cache.get(mod);
|
|
17
|
-
if (cached)
|
|
18
|
-
return cached;
|
|
19
|
-
}
|
|
20
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
21
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
22
|
-
if (mod && typeof mod === "object" || typeof mod === "function") {
|
|
23
|
-
for (let key of __getOwnPropNames(mod))
|
|
24
|
-
if (!__hasOwnProp.call(to, key))
|
|
25
|
-
__defProp(to, key, {
|
|
26
|
-
get: __accessProp.bind(mod, key),
|
|
27
|
-
enumerable: true
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
if (canCache)
|
|
31
|
-
cache.set(mod, to);
|
|
32
|
-
return to;
|
|
33
|
-
};
|
|
34
8
|
var __toCommonJS = (from) => {
|
|
35
9
|
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
36
10
|
if (entry)
|
|
@@ -48,7 +22,6 @@ var __toCommonJS = (from) => {
|
|
|
48
22
|
return entry;
|
|
49
23
|
};
|
|
50
24
|
var __moduleCache;
|
|
51
|
-
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
52
25
|
var __returnValue = (v) => v;
|
|
53
26
|
function __exportSetter(name, newValue) {
|
|
54
27
|
this[name] = __returnValue.bind(null, newValue);
|
|
@@ -63,483 +36,6 @@ var __export = (target, all) => {
|
|
|
63
36
|
});
|
|
64
37
|
};
|
|
65
38
|
|
|
66
|
-
// ../../node_modules/.bun/neverthrow@8.2.0/node_modules/neverthrow/dist/index.cjs.js
|
|
67
|
-
var require_index_cjs = __commonJS(function(exports2) {
|
|
68
|
-
var defaultErrorConfig = {
|
|
69
|
-
withStackTrace: false
|
|
70
|
-
};
|
|
71
|
-
var createNeverThrowError = (message, result, config = defaultErrorConfig) => {
|
|
72
|
-
const data = result.isOk() ? { type: "Ok", value: result.value } : { type: "Err", value: result.error };
|
|
73
|
-
const maybeStack = config.withStackTrace ? new Error().stack : undefined;
|
|
74
|
-
return {
|
|
75
|
-
data,
|
|
76
|
-
message,
|
|
77
|
-
stack: maybeStack
|
|
78
|
-
};
|
|
79
|
-
};
|
|
80
|
-
function __awaiter(thisArg, _arguments, P, generator) {
|
|
81
|
-
function adopt(value) {
|
|
82
|
-
return value instanceof P ? value : new P(function(resolve) {
|
|
83
|
-
resolve(value);
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
return new (P || (P = Promise))(function(resolve, reject) {
|
|
87
|
-
function fulfilled(value) {
|
|
88
|
-
try {
|
|
89
|
-
step(generator.next(value));
|
|
90
|
-
} catch (e) {
|
|
91
|
-
reject(e);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
function rejected(value) {
|
|
95
|
-
try {
|
|
96
|
-
step(generator["throw"](value));
|
|
97
|
-
} catch (e) {
|
|
98
|
-
reject(e);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
function step(result) {
|
|
102
|
-
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
103
|
-
}
|
|
104
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
function __values(o) {
|
|
108
|
-
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
109
|
-
if (m)
|
|
110
|
-
return m.call(o);
|
|
111
|
-
if (o && typeof o.length === "number")
|
|
112
|
-
return {
|
|
113
|
-
next: function() {
|
|
114
|
-
if (o && i >= o.length)
|
|
115
|
-
o = undefined;
|
|
116
|
-
return { value: o && o[i++], done: !o };
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
120
|
-
}
|
|
121
|
-
function __await(v) {
|
|
122
|
-
return this instanceof __await ? (this.v = v, this) : new __await(v);
|
|
123
|
-
}
|
|
124
|
-
function __asyncGenerator(thisArg, _arguments, generator) {
|
|
125
|
-
if (!Symbol.asyncIterator)
|
|
126
|
-
throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
127
|
-
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
128
|
-
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function() {
|
|
129
|
-
return this;
|
|
130
|
-
}, i;
|
|
131
|
-
function awaitReturn(f) {
|
|
132
|
-
return function(v) {
|
|
133
|
-
return Promise.resolve(v).then(f, reject);
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
function verb(n, f) {
|
|
137
|
-
if (g[n]) {
|
|
138
|
-
i[n] = function(v) {
|
|
139
|
-
return new Promise(function(a, b) {
|
|
140
|
-
q.push([n, v, a, b]) > 1 || resume(n, v);
|
|
141
|
-
});
|
|
142
|
-
};
|
|
143
|
-
if (f)
|
|
144
|
-
i[n] = f(i[n]);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
function resume(n, v) {
|
|
148
|
-
try {
|
|
149
|
-
step(g[n](v));
|
|
150
|
-
} catch (e) {
|
|
151
|
-
settle(q[0][3], e);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
function step(r) {
|
|
155
|
-
r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r);
|
|
156
|
-
}
|
|
157
|
-
function fulfill(value) {
|
|
158
|
-
resume("next", value);
|
|
159
|
-
}
|
|
160
|
-
function reject(value) {
|
|
161
|
-
resume("throw", value);
|
|
162
|
-
}
|
|
163
|
-
function settle(f, v) {
|
|
164
|
-
if (f(v), q.shift(), q.length)
|
|
165
|
-
resume(q[0][0], q[0][1]);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
function __asyncDelegator(o) {
|
|
169
|
-
var i, p;
|
|
170
|
-
return i = {}, verb("next"), verb("throw", function(e) {
|
|
171
|
-
throw e;
|
|
172
|
-
}), verb("return"), i[Symbol.iterator] = function() {
|
|
173
|
-
return this;
|
|
174
|
-
}, i;
|
|
175
|
-
function verb(n, f) {
|
|
176
|
-
i[n] = o[n] ? function(v) {
|
|
177
|
-
return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v;
|
|
178
|
-
} : f;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
function __asyncValues(o) {
|
|
182
|
-
if (!Symbol.asyncIterator)
|
|
183
|
-
throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
184
|
-
var m = o[Symbol.asyncIterator], i;
|
|
185
|
-
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {
|
|
186
|
-
return this;
|
|
187
|
-
}, i);
|
|
188
|
-
function verb(n) {
|
|
189
|
-
i[n] = o[n] && function(v) {
|
|
190
|
-
return new Promise(function(resolve, reject) {
|
|
191
|
-
v = o[n](v), settle(resolve, reject, v.done, v.value);
|
|
192
|
-
});
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
function settle(resolve, reject, d, v) {
|
|
196
|
-
Promise.resolve(v).then(function(v2) {
|
|
197
|
-
resolve({ value: v2, done: d });
|
|
198
|
-
}, reject);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
class ResultAsync {
|
|
203
|
-
constructor(res) {
|
|
204
|
-
this._promise = res;
|
|
205
|
-
}
|
|
206
|
-
static fromSafePromise(promise) {
|
|
207
|
-
const newPromise = promise.then((value) => new Ok(value));
|
|
208
|
-
return new ResultAsync(newPromise);
|
|
209
|
-
}
|
|
210
|
-
static fromPromise(promise, errorFn) {
|
|
211
|
-
const newPromise = promise.then((value) => new Ok(value)).catch((e) => new Err(errorFn(e)));
|
|
212
|
-
return new ResultAsync(newPromise);
|
|
213
|
-
}
|
|
214
|
-
static fromThrowable(fn, errorFn) {
|
|
215
|
-
return (...args) => {
|
|
216
|
-
return new ResultAsync((() => __awaiter(this, undefined, undefined, function* () {
|
|
217
|
-
try {
|
|
218
|
-
return new Ok(yield fn(...args));
|
|
219
|
-
} catch (error) {
|
|
220
|
-
return new Err(errorFn ? errorFn(error) : error);
|
|
221
|
-
}
|
|
222
|
-
}))());
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
static combine(asyncResultList) {
|
|
226
|
-
return combineResultAsyncList(asyncResultList);
|
|
227
|
-
}
|
|
228
|
-
static combineWithAllErrors(asyncResultList) {
|
|
229
|
-
return combineResultAsyncListWithAllErrors(asyncResultList);
|
|
230
|
-
}
|
|
231
|
-
map(f) {
|
|
232
|
-
return new ResultAsync(this._promise.then((res) => __awaiter(this, undefined, undefined, function* () {
|
|
233
|
-
if (res.isErr()) {
|
|
234
|
-
return new Err(res.error);
|
|
235
|
-
}
|
|
236
|
-
return new Ok(yield f(res.value));
|
|
237
|
-
})));
|
|
238
|
-
}
|
|
239
|
-
andThrough(f) {
|
|
240
|
-
return new ResultAsync(this._promise.then((res) => __awaiter(this, undefined, undefined, function* () {
|
|
241
|
-
if (res.isErr()) {
|
|
242
|
-
return new Err(res.error);
|
|
243
|
-
}
|
|
244
|
-
const newRes = yield f(res.value);
|
|
245
|
-
if (newRes.isErr()) {
|
|
246
|
-
return new Err(newRes.error);
|
|
247
|
-
}
|
|
248
|
-
return new Ok(res.value);
|
|
249
|
-
})));
|
|
250
|
-
}
|
|
251
|
-
andTee(f) {
|
|
252
|
-
return new ResultAsync(this._promise.then((res) => __awaiter(this, undefined, undefined, function* () {
|
|
253
|
-
if (res.isErr()) {
|
|
254
|
-
return new Err(res.error);
|
|
255
|
-
}
|
|
256
|
-
try {
|
|
257
|
-
yield f(res.value);
|
|
258
|
-
} catch (e) {}
|
|
259
|
-
return new Ok(res.value);
|
|
260
|
-
})));
|
|
261
|
-
}
|
|
262
|
-
orTee(f) {
|
|
263
|
-
return new ResultAsync(this._promise.then((res) => __awaiter(this, undefined, undefined, function* () {
|
|
264
|
-
if (res.isOk()) {
|
|
265
|
-
return new Ok(res.value);
|
|
266
|
-
}
|
|
267
|
-
try {
|
|
268
|
-
yield f(res.error);
|
|
269
|
-
} catch (e) {}
|
|
270
|
-
return new Err(res.error);
|
|
271
|
-
})));
|
|
272
|
-
}
|
|
273
|
-
mapErr(f) {
|
|
274
|
-
return new ResultAsync(this._promise.then((res) => __awaiter(this, undefined, undefined, function* () {
|
|
275
|
-
if (res.isOk()) {
|
|
276
|
-
return new Ok(res.value);
|
|
277
|
-
}
|
|
278
|
-
return new Err(yield f(res.error));
|
|
279
|
-
})));
|
|
280
|
-
}
|
|
281
|
-
andThen(f) {
|
|
282
|
-
return new ResultAsync(this._promise.then((res) => {
|
|
283
|
-
if (res.isErr()) {
|
|
284
|
-
return new Err(res.error);
|
|
285
|
-
}
|
|
286
|
-
const newValue = f(res.value);
|
|
287
|
-
return newValue instanceof ResultAsync ? newValue._promise : newValue;
|
|
288
|
-
}));
|
|
289
|
-
}
|
|
290
|
-
orElse(f) {
|
|
291
|
-
return new ResultAsync(this._promise.then((res) => __awaiter(this, undefined, undefined, function* () {
|
|
292
|
-
if (res.isErr()) {
|
|
293
|
-
return f(res.error);
|
|
294
|
-
}
|
|
295
|
-
return new Ok(res.value);
|
|
296
|
-
})));
|
|
297
|
-
}
|
|
298
|
-
match(ok2, _err) {
|
|
299
|
-
return this._promise.then((res) => res.match(ok2, _err));
|
|
300
|
-
}
|
|
301
|
-
unwrapOr(t) {
|
|
302
|
-
return this._promise.then((res) => res.unwrapOr(t));
|
|
303
|
-
}
|
|
304
|
-
safeUnwrap() {
|
|
305
|
-
return __asyncGenerator(this, arguments, function* safeUnwrap_1() {
|
|
306
|
-
return yield __await(yield __await(yield* __asyncDelegator(__asyncValues(yield __await(this._promise.then((res) => res.safeUnwrap()))))));
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
then(successCallback, failureCallback) {
|
|
310
|
-
return this._promise.then(successCallback, failureCallback);
|
|
311
|
-
}
|
|
312
|
-
[Symbol.asyncIterator]() {
|
|
313
|
-
return __asyncGenerator(this, arguments, function* _a() {
|
|
314
|
-
const result = yield __await(this._promise);
|
|
315
|
-
if (result.isErr()) {
|
|
316
|
-
yield yield __await(errAsync(result.error));
|
|
317
|
-
}
|
|
318
|
-
return yield __await(result.value);
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
function okAsync(value) {
|
|
323
|
-
return new ResultAsync(Promise.resolve(new Ok(value)));
|
|
324
|
-
}
|
|
325
|
-
function errAsync(err2) {
|
|
326
|
-
return new ResultAsync(Promise.resolve(new Err(err2)));
|
|
327
|
-
}
|
|
328
|
-
var fromPromise = ResultAsync.fromPromise;
|
|
329
|
-
var fromSafePromise = ResultAsync.fromSafePromise;
|
|
330
|
-
var fromAsyncThrowable = ResultAsync.fromThrowable;
|
|
331
|
-
var combineResultList = (resultList) => {
|
|
332
|
-
let acc = ok([]);
|
|
333
|
-
for (const result of resultList) {
|
|
334
|
-
if (result.isErr()) {
|
|
335
|
-
acc = err(result.error);
|
|
336
|
-
break;
|
|
337
|
-
} else {
|
|
338
|
-
acc.map((list) => list.push(result.value));
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
return acc;
|
|
342
|
-
};
|
|
343
|
-
var combineResultAsyncList = (asyncResultList) => ResultAsync.fromSafePromise(Promise.all(asyncResultList)).andThen(combineResultList);
|
|
344
|
-
var combineResultListWithAllErrors = (resultList) => {
|
|
345
|
-
let acc = ok([]);
|
|
346
|
-
for (const result of resultList) {
|
|
347
|
-
if (result.isErr() && acc.isErr()) {
|
|
348
|
-
acc.error.push(result.error);
|
|
349
|
-
} else if (result.isErr() && acc.isOk()) {
|
|
350
|
-
acc = err([result.error]);
|
|
351
|
-
} else if (result.isOk() && acc.isOk()) {
|
|
352
|
-
acc.value.push(result.value);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
return acc;
|
|
356
|
-
};
|
|
357
|
-
var combineResultAsyncListWithAllErrors = (asyncResultList) => ResultAsync.fromSafePromise(Promise.all(asyncResultList)).andThen(combineResultListWithAllErrors);
|
|
358
|
-
exports2.Result = undefined;
|
|
359
|
-
(function(Result) {
|
|
360
|
-
function fromThrowable2(fn, errorFn) {
|
|
361
|
-
return (...args) => {
|
|
362
|
-
try {
|
|
363
|
-
const result = fn(...args);
|
|
364
|
-
return ok(result);
|
|
365
|
-
} catch (e) {
|
|
366
|
-
return err(errorFn ? errorFn(e) : e);
|
|
367
|
-
}
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
Result.fromThrowable = fromThrowable2;
|
|
371
|
-
function combine(resultList) {
|
|
372
|
-
return combineResultList(resultList);
|
|
373
|
-
}
|
|
374
|
-
Result.combine = combine;
|
|
375
|
-
function combineWithAllErrors(resultList) {
|
|
376
|
-
return combineResultListWithAllErrors(resultList);
|
|
377
|
-
}
|
|
378
|
-
Result.combineWithAllErrors = combineWithAllErrors;
|
|
379
|
-
})(exports2.Result || (exports2.Result = {}));
|
|
380
|
-
function ok(value) {
|
|
381
|
-
return new Ok(value);
|
|
382
|
-
}
|
|
383
|
-
function err(err2) {
|
|
384
|
-
return new Err(err2);
|
|
385
|
-
}
|
|
386
|
-
function safeTry(body) {
|
|
387
|
-
const n = body().next();
|
|
388
|
-
if (n instanceof Promise) {
|
|
389
|
-
return new ResultAsync(n.then((r) => r.value));
|
|
390
|
-
}
|
|
391
|
-
return n.value;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
class Ok {
|
|
395
|
-
constructor(value) {
|
|
396
|
-
this.value = value;
|
|
397
|
-
}
|
|
398
|
-
isOk() {
|
|
399
|
-
return true;
|
|
400
|
-
}
|
|
401
|
-
isErr() {
|
|
402
|
-
return !this.isOk();
|
|
403
|
-
}
|
|
404
|
-
map(f) {
|
|
405
|
-
return ok(f(this.value));
|
|
406
|
-
}
|
|
407
|
-
mapErr(_f) {
|
|
408
|
-
return ok(this.value);
|
|
409
|
-
}
|
|
410
|
-
andThen(f) {
|
|
411
|
-
return f(this.value);
|
|
412
|
-
}
|
|
413
|
-
andThrough(f) {
|
|
414
|
-
return f(this.value).map((_value) => this.value);
|
|
415
|
-
}
|
|
416
|
-
andTee(f) {
|
|
417
|
-
try {
|
|
418
|
-
f(this.value);
|
|
419
|
-
} catch (e) {}
|
|
420
|
-
return ok(this.value);
|
|
421
|
-
}
|
|
422
|
-
orTee(_f) {
|
|
423
|
-
return ok(this.value);
|
|
424
|
-
}
|
|
425
|
-
orElse(_f) {
|
|
426
|
-
return ok(this.value);
|
|
427
|
-
}
|
|
428
|
-
asyncAndThen(f) {
|
|
429
|
-
return f(this.value);
|
|
430
|
-
}
|
|
431
|
-
asyncAndThrough(f) {
|
|
432
|
-
return f(this.value).map(() => this.value);
|
|
433
|
-
}
|
|
434
|
-
asyncMap(f) {
|
|
435
|
-
return ResultAsync.fromSafePromise(f(this.value));
|
|
436
|
-
}
|
|
437
|
-
unwrapOr(_v) {
|
|
438
|
-
return this.value;
|
|
439
|
-
}
|
|
440
|
-
match(ok2, _err) {
|
|
441
|
-
return ok2(this.value);
|
|
442
|
-
}
|
|
443
|
-
safeUnwrap() {
|
|
444
|
-
const value = this.value;
|
|
445
|
-
return function* () {
|
|
446
|
-
return value;
|
|
447
|
-
}();
|
|
448
|
-
}
|
|
449
|
-
_unsafeUnwrap(_) {
|
|
450
|
-
return this.value;
|
|
451
|
-
}
|
|
452
|
-
_unsafeUnwrapErr(config) {
|
|
453
|
-
throw createNeverThrowError("Called `_unsafeUnwrapErr` on an Ok", this, config);
|
|
454
|
-
}
|
|
455
|
-
*[Symbol.iterator]() {
|
|
456
|
-
return this.value;
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
class Err {
|
|
461
|
-
constructor(error) {
|
|
462
|
-
this.error = error;
|
|
463
|
-
}
|
|
464
|
-
isOk() {
|
|
465
|
-
return false;
|
|
466
|
-
}
|
|
467
|
-
isErr() {
|
|
468
|
-
return !this.isOk();
|
|
469
|
-
}
|
|
470
|
-
map(_f) {
|
|
471
|
-
return err(this.error);
|
|
472
|
-
}
|
|
473
|
-
mapErr(f) {
|
|
474
|
-
return err(f(this.error));
|
|
475
|
-
}
|
|
476
|
-
andThrough(_f) {
|
|
477
|
-
return err(this.error);
|
|
478
|
-
}
|
|
479
|
-
andTee(_f) {
|
|
480
|
-
return err(this.error);
|
|
481
|
-
}
|
|
482
|
-
orTee(f) {
|
|
483
|
-
try {
|
|
484
|
-
f(this.error);
|
|
485
|
-
} catch (e) {}
|
|
486
|
-
return err(this.error);
|
|
487
|
-
}
|
|
488
|
-
andThen(_f) {
|
|
489
|
-
return err(this.error);
|
|
490
|
-
}
|
|
491
|
-
orElse(f) {
|
|
492
|
-
return f(this.error);
|
|
493
|
-
}
|
|
494
|
-
asyncAndThen(_f) {
|
|
495
|
-
return errAsync(this.error);
|
|
496
|
-
}
|
|
497
|
-
asyncAndThrough(_f) {
|
|
498
|
-
return errAsync(this.error);
|
|
499
|
-
}
|
|
500
|
-
asyncMap(_f) {
|
|
501
|
-
return errAsync(this.error);
|
|
502
|
-
}
|
|
503
|
-
unwrapOr(v) {
|
|
504
|
-
return v;
|
|
505
|
-
}
|
|
506
|
-
match(_ok, err2) {
|
|
507
|
-
return err2(this.error);
|
|
508
|
-
}
|
|
509
|
-
safeUnwrap() {
|
|
510
|
-
const error = this.error;
|
|
511
|
-
return function* () {
|
|
512
|
-
yield err(error);
|
|
513
|
-
throw new Error("Do not use this generator out of `safeTry`");
|
|
514
|
-
}();
|
|
515
|
-
}
|
|
516
|
-
_unsafeUnwrap(config) {
|
|
517
|
-
throw createNeverThrowError("Called `_unsafeUnwrap` on an Err", this, config);
|
|
518
|
-
}
|
|
519
|
-
_unsafeUnwrapErr(_) {
|
|
520
|
-
return this.error;
|
|
521
|
-
}
|
|
522
|
-
*[Symbol.iterator]() {
|
|
523
|
-
const self = this;
|
|
524
|
-
yield self;
|
|
525
|
-
return self;
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
var fromThrowable = exports2.Result.fromThrowable;
|
|
529
|
-
exports2.Err = Err;
|
|
530
|
-
exports2.Ok = Ok;
|
|
531
|
-
exports2.ResultAsync = ResultAsync;
|
|
532
|
-
exports2.err = err;
|
|
533
|
-
exports2.errAsync = errAsync;
|
|
534
|
-
exports2.fromAsyncThrowable = fromAsyncThrowable;
|
|
535
|
-
exports2.fromPromise = fromPromise;
|
|
536
|
-
exports2.fromSafePromise = fromSafePromise;
|
|
537
|
-
exports2.fromThrowable = fromThrowable;
|
|
538
|
-
exports2.ok = ok;
|
|
539
|
-
exports2.okAsync = okAsync;
|
|
540
|
-
exports2.safeTry = safeTry;
|
|
541
|
-
});
|
|
542
|
-
|
|
543
39
|
// src/index.ts
|
|
544
40
|
var exports_src = {};
|
|
545
41
|
__export(exports_src, {
|
|
@@ -757,6 +253,7 @@ var AckType;
|
|
|
757
253
|
AckType2[AckType2["CDC2_NACK_FILE_SYS_FULL"] = 220] = "CDC2_NACK_FILE_SYS_FULL";
|
|
758
254
|
AckType2[AckType2["TIMEOUT"] = 256] = "TIMEOUT";
|
|
759
255
|
AckType2[AckType2["WRITE_ERROR"] = 257] = "WRITE_ERROR";
|
|
256
|
+
AckType2[AckType2["NOT_CONNECTED"] = 258] = "NOT_CONNECTED";
|
|
760
257
|
})(AckType ||= {});
|
|
761
258
|
var SmartDeviceType;
|
|
762
259
|
((SmartDeviceType2) => {
|
|
@@ -939,8 +436,15 @@ class VexEventEmitter {
|
|
|
939
436
|
this.handlerMap.set(eventName, listeners);
|
|
940
437
|
}
|
|
941
438
|
emit(eventName, data) {
|
|
439
|
+
const listeners = this.handlerMap.get(eventName);
|
|
440
|
+
if (listeners === undefined || listeners.length === 0)
|
|
441
|
+
return;
|
|
442
|
+
if (listeners.length === 1) {
|
|
443
|
+
listeners[0](data);
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
942
446
|
const errors = [];
|
|
943
|
-
for (const callback of [...
|
|
447
|
+
for (const callback of [...listeners]) {
|
|
944
448
|
try {
|
|
945
449
|
callback(data);
|
|
946
450
|
} catch (error) {
|
|
@@ -964,24 +468,21 @@ class VexEventTarget {
|
|
|
964
468
|
this.emitter = new VexEventEmitter;
|
|
965
469
|
}
|
|
966
470
|
emit(eventName, data) {
|
|
967
|
-
this.emitter.emit(
|
|
471
|
+
this.emitter.emit(eventName, data);
|
|
968
472
|
}
|
|
969
473
|
on(eventName, listener) {
|
|
970
|
-
this.emitter.on(
|
|
474
|
+
this.emitter.on(eventName, listener);
|
|
971
475
|
}
|
|
972
476
|
remove(eventName, listener) {
|
|
973
|
-
this.emitter.remove(
|
|
477
|
+
this.emitter.remove(eventName, listener);
|
|
974
478
|
}
|
|
975
479
|
clearListeners() {
|
|
976
480
|
this.emitter.clearListeners();
|
|
977
481
|
}
|
|
978
|
-
normalizeEventName(eventName) {
|
|
979
|
-
return String(eventName);
|
|
980
|
-
}
|
|
981
482
|
}
|
|
982
483
|
|
|
983
484
|
// src/VexConnection.ts
|
|
984
|
-
var import_neverthrow =
|
|
485
|
+
var import_neverthrow = require("neverthrow");
|
|
985
486
|
|
|
986
487
|
// src/VexPacketBase.ts
|
|
987
488
|
var MATCH_STATUS_ALT_ACK = 167;
|
|
@@ -1076,79 +577,115 @@ class CrcGenerator {
|
|
|
1076
577
|
}
|
|
1077
578
|
}
|
|
1078
579
|
|
|
1079
|
-
// src/
|
|
1080
|
-
var
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
}
|
|
580
|
+
// src/VexPacketEncoder.ts
|
|
581
|
+
var textEncoder = new TextEncoder;
|
|
582
|
+
var HEADER_TO_DEVICE = Uint8Array.of(201, 54, 184, 71);
|
|
583
|
+
function encodeFixedText(value, field, maxBytes) {
|
|
584
|
+
const encoded = textEncoder.encode(value);
|
|
585
|
+
if (encoded.byteLength > maxBytes) {
|
|
586
|
+
throw new RangeError(`${field} must be at most ${maxBytes} UTF-8 bytes`);
|
|
587
|
+
}
|
|
588
|
+
return encoded;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
class PacketEncoder {
|
|
592
|
+
static HEADERS_LENGTH = 4;
|
|
593
|
+
static HEADER_TO_DEVICE = [201, 54, 184, 71];
|
|
594
|
+
static HEADER_TO_HOST = [170, 85];
|
|
595
|
+
static J2000_EPOCH = 946684800;
|
|
596
|
+
vexVersion = 0;
|
|
597
|
+
crcgen = new CrcGenerator;
|
|
598
|
+
allPacketsTable = new Map;
|
|
599
|
+
static getInstance() {
|
|
600
|
+
Packet.ENCODER ??= new PacketEncoder;
|
|
601
|
+
return Packet.ENCODER;
|
|
602
|
+
}
|
|
603
|
+
constructor() {}
|
|
604
|
+
registerPacketTypes(types) {
|
|
605
|
+
for (const type of types) {
|
|
606
|
+
let byExtendedId = this.allPacketsTable.get(type.COMMAND_ID);
|
|
607
|
+
if (byExtendedId === undefined) {
|
|
608
|
+
byExtendedId = new Map;
|
|
609
|
+
this.allPacketsTable.set(type.COMMAND_ID, byExtendedId);
|
|
610
|
+
}
|
|
611
|
+
byExtendedId.set(type.COMMAND_EXTENDED_ID, type);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
getPacketType(commandId, commandExtendedId) {
|
|
615
|
+
if (commandId === undefined)
|
|
616
|
+
return;
|
|
617
|
+
return this.allPacketsTable.get(commandId)?.get(commandExtendedId);
|
|
618
|
+
}
|
|
619
|
+
createHeader(buf) {
|
|
620
|
+
if (buf === undefined || buf.byteLength < PacketEncoder.HEADERS_LENGTH) {
|
|
621
|
+
buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH);
|
|
622
|
+
}
|
|
623
|
+
const h = new Uint8Array(buf);
|
|
624
|
+
h.set(HEADER_TO_DEVICE);
|
|
625
|
+
return h;
|
|
626
|
+
}
|
|
627
|
+
cdcCommand(cmd) {
|
|
628
|
+
const h = new Uint8Array(5);
|
|
629
|
+
h.set(HEADER_TO_DEVICE);
|
|
630
|
+
h[4] = cmd;
|
|
631
|
+
return h;
|
|
632
|
+
}
|
|
633
|
+
cdcCommandWithData(cmd, data) {
|
|
634
|
+
const h = new Uint8Array(6 + data.length);
|
|
635
|
+
h.set(HEADER_TO_DEVICE);
|
|
636
|
+
h[4] = cmd;
|
|
637
|
+
h[5] = data.length;
|
|
638
|
+
h.set(data, 6);
|
|
639
|
+
return h;
|
|
640
|
+
}
|
|
641
|
+
cdc2Command(cmd, ext) {
|
|
642
|
+
const h = new Uint8Array(9);
|
|
643
|
+
h.set(HEADER_TO_DEVICE);
|
|
644
|
+
h[4] = cmd;
|
|
645
|
+
h[5] = ext;
|
|
646
|
+
h[6] = 0;
|
|
647
|
+
this.appendCrc16(h);
|
|
648
|
+
return h;
|
|
649
|
+
}
|
|
650
|
+
cdc2CommandBufferLength(data) {
|
|
651
|
+
return PacketEncoder.HEADERS_LENGTH + data.length + 5 + (data.length > 127 ? 1 : 0);
|
|
652
|
+
}
|
|
653
|
+
cdc2CommandWithData(cmd, ext, data) {
|
|
654
|
+
const h = new Uint8Array(this.cdc2CommandBufferLength(data));
|
|
655
|
+
h.set(HEADER_TO_DEVICE);
|
|
656
|
+
h[4] = cmd;
|
|
657
|
+
h[5] = ext;
|
|
658
|
+
if (data.length < 128) {
|
|
659
|
+
h[6] = data.length;
|
|
660
|
+
h.set(data, 7);
|
|
661
|
+
} else {
|
|
662
|
+
h[6] = data.length >>> 8 | 128;
|
|
663
|
+
h[7] = data.length & 255;
|
|
664
|
+
h.set(data, 8);
|
|
665
|
+
}
|
|
666
|
+
this.appendCrc16(h);
|
|
667
|
+
return h;
|
|
668
|
+
}
|
|
669
|
+
appendCrc16(h) {
|
|
670
|
+
const crc = this.crcgen.crc16(h.subarray(0, h.length - 2), 0);
|
|
671
|
+
h[h.length - 2] = crc >>> 8;
|
|
672
|
+
h[h.length - 1] = crc & 255;
|
|
673
|
+
}
|
|
674
|
+
validateHeader(data) {
|
|
675
|
+
return data[0] === PacketEncoder.HEADER_TO_HOST[0] && data[1] === PacketEncoder.HEADER_TO_HOST[1];
|
|
676
|
+
}
|
|
677
|
+
validateMessageCdc(data) {
|
|
678
|
+
const crc = (data[data.byteLength - 2] << 8) + data[data.byteLength - 1];
|
|
679
|
+
return this.crcgen.crc16(data.subarray(0, data.byteLength - 2), 0) === crc;
|
|
680
|
+
}
|
|
681
|
+
getPayloadSize(data) {
|
|
682
|
+
const a = data[3];
|
|
683
|
+
return (a & 128) === 0 ? a : ((a & 127) << 8) + data[4];
|
|
684
|
+
}
|
|
685
|
+
getHostHeaderLength(data) {
|
|
686
|
+
return (data[3] & 128) === 0 ? 4 : 5;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
1152
689
|
|
|
1153
690
|
// src/VexFirmwareVersion.ts
|
|
1154
691
|
class VexFirmwareVersion {
|
|
@@ -1219,7 +756,7 @@ class PacketView extends DataView {
|
|
|
1219
756
|
super(buffer, offset, length);
|
|
1220
757
|
}
|
|
1221
758
|
static fromPacket(packet) {
|
|
1222
|
-
const view = new PacketView(packet.data.buffer, packet.data.byteOffset);
|
|
759
|
+
const view = new PacketView(packet.data.buffer, packet.data.byteOffset, packet.data.byteLength);
|
|
1223
760
|
view.position = packet.ackIndex + 1;
|
|
1224
761
|
return view;
|
|
1225
762
|
}
|
|
@@ -1281,12 +818,12 @@ class PacketView extends DataView {
|
|
|
1281
818
|
}
|
|
1282
819
|
|
|
1283
820
|
// src/VexPacketModels.ts
|
|
1284
|
-
var
|
|
821
|
+
var textEncoder2 = new TextEncoder;
|
|
1285
822
|
function filePayload(a, b, fileName) {
|
|
1286
823
|
const payload = new Uint8Array(26);
|
|
1287
824
|
payload[0] = a;
|
|
1288
825
|
payload[1] = b;
|
|
1289
|
-
payload.set(encodeFixedText(fileName, "Filename",
|
|
826
|
+
payload.set(encodeFixedText(fileName, "Filename", 24), 2);
|
|
1290
827
|
return payload;
|
|
1291
828
|
}
|
|
1292
829
|
var clamp100 = (value) => value !== undefined && value > 100 ? 100 : value;
|
|
@@ -1354,7 +891,7 @@ class InitFileTransferH2DPacket extends DeviceBoundPacket {
|
|
|
1354
891
|
const timestamp = (Date.now() / 1000 >>> 0) - PacketEncoder.J2000_EPOCH;
|
|
1355
892
|
view.setUint32(20, timestamp, true);
|
|
1356
893
|
payload.set(version.toUint8Array(), 24);
|
|
1357
|
-
payload.set(encodeFixedText(name, "Filename",
|
|
894
|
+
payload.set(encodeFixedText(name, "Filename", 24), 28);
|
|
1358
895
|
super(payload);
|
|
1359
896
|
}
|
|
1360
897
|
}
|
|
@@ -1549,7 +1086,7 @@ class WriteKeyValueH2DPacket extends DeviceBoundPacket {
|
|
|
1549
1086
|
static COMMAND_EXTENDED_ID = 47;
|
|
1550
1087
|
constructor(key, value) {
|
|
1551
1088
|
const strk = encodeFixedText(key, "Key", 31);
|
|
1552
|
-
const strv =
|
|
1089
|
+
const strv = textEncoder2.encode(value);
|
|
1553
1090
|
if (strk.byteLength + strv.byteLength + 20 > 32767) {
|
|
1554
1091
|
throw new RangeError("Key and value are too large for a protocol packet");
|
|
1555
1092
|
}
|
|
@@ -1712,7 +1249,7 @@ class ReadFileReplyD2HPacket extends HostBoundPacket {
|
|
|
1712
1249
|
const view = PacketView.fromPacket(this);
|
|
1713
1250
|
this.addr = view.nextUint32();
|
|
1714
1251
|
this.length = this.payloadSize - 8;
|
|
1715
|
-
this.buf = this.data.
|
|
1252
|
+
this.buf = this.data.subarray(view.position, view.position + this.length);
|
|
1716
1253
|
}
|
|
1717
1254
|
}
|
|
1718
1255
|
|
|
@@ -1994,203 +1531,113 @@ class GetRadioStatusReplyD2HPacket extends HostBoundPacket {
|
|
|
1994
1531
|
class ScreenCaptureReplyD2HPacket extends HostBoundPacket {
|
|
1995
1532
|
static COMMAND_ID = 86;
|
|
1996
1533
|
static COMMAND_EXTENDED_ID = 40;
|
|
1997
|
-
}
|
|
1998
|
-
|
|
1999
|
-
class SendDashTouchReplyD2HPacket extends HostBoundPacket {
|
|
2000
|
-
static COMMAND_ID = 86;
|
|
2001
|
-
static COMMAND_EXTENDED_ID = 42;
|
|
2002
|
-
}
|
|
2003
|
-
|
|
2004
|
-
class SelectDashReplyD2HPacket extends HostBoundPacket {
|
|
2005
|
-
static COMMAND_ID = 86;
|
|
2006
|
-
static COMMAND_EXTENDED_ID = 43;
|
|
2007
|
-
}
|
|
2008
|
-
|
|
2009
|
-
class ReadKeyValueReplyD2HPacket extends HostBoundPacket {
|
|
2010
|
-
static COMMAND_ID = 86;
|
|
2011
|
-
static COMMAND_EXTENDED_ID = 46;
|
|
2012
|
-
value;
|
|
2013
|
-
constructor(data) {
|
|
2014
|
-
super(data);
|
|
2015
|
-
this.value = PacketView.fromPacket(this).nextVarNTBS(255);
|
|
2016
|
-
}
|
|
2017
|
-
}
|
|
2018
|
-
|
|
2019
|
-
class WriteKeyValueReplyD2HPacket extends HostBoundPacket {
|
|
2020
|
-
static COMMAND_ID = 86;
|
|
2021
|
-
static COMMAND_EXTENDED_ID = 47;
|
|
2022
|
-
}
|
|
2023
|
-
|
|
2024
|
-
class GetSlot1to4InfoReplyD2HPacket extends HostBoundPacket {
|
|
2025
|
-
static COMMAND_ID = 86;
|
|
2026
|
-
static COMMAND_EXTENDED_ID = 49;
|
|
2027
|
-
slotFlags;
|
|
2028
|
-
slots;
|
|
2029
|
-
constructor(data, start = 1) {
|
|
2030
|
-
super(data);
|
|
2031
|
-
const view = PacketView.fromPacket(this);
|
|
2032
|
-
this.slotFlags = view.nextUint8();
|
|
2033
|
-
this.slots = [];
|
|
2034
|
-
for (let i = 0;i < 4; i++) {
|
|
2035
|
-
if ((this.slotFlags & 1 << start - 1 + i) === 0)
|
|
2036
|
-
continue;
|
|
2037
|
-
const icon = view.nextUint16();
|
|
2038
|
-
const nameLen = view.nextUint8();
|
|
2039
|
-
this.slots.push({
|
|
2040
|
-
slot: start + i,
|
|
2041
|
-
icon,
|
|
2042
|
-
name: view.nextString(nameLen)
|
|
2043
|
-
});
|
|
2044
|
-
}
|
|
2045
|
-
}
|
|
2046
|
-
}
|
|
2047
|
-
|
|
2048
|
-
class GetSlot5to8InfoReplyD2HPacket extends GetSlot1to4InfoReplyD2HPacket {
|
|
2049
|
-
static COMMAND_ID = 86;
|
|
2050
|
-
static COMMAND_EXTENDED_ID = 50;
|
|
2051
|
-
slotStartIndex = 5;
|
|
2052
|
-
constructor(data) {
|
|
2053
|
-
super(data, 5);
|
|
2054
|
-
}
|
|
2055
|
-
}
|
|
2056
|
-
|
|
2057
|
-
class FactoryStatusReplyD2HPacket extends HostBoundPacket {
|
|
2058
|
-
static COMMAND_ID = 86;
|
|
2059
|
-
static COMMAND_EXTENDED_ID = 241;
|
|
2060
|
-
status;
|
|
2061
|
-
percent;
|
|
2062
|
-
constructor(data) {
|
|
2063
|
-
super(data);
|
|
2064
|
-
const view = PacketView.fromPacket(this);
|
|
2065
|
-
this.status = view.nextUint8();
|
|
2066
|
-
this.percent = view.nextUint8();
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
|
|
2070
|
-
class FactoryEnableReplyD2HPacket extends HostBoundPacket {
|
|
2071
|
-
static COMMAND_ID = 86;
|
|
2072
|
-
static COMMAND_EXTENDED_ID = 255;
|
|
2073
|
-
}
|
|
2074
|
-
|
|
2075
|
-
// src/VexPacketEncoder.ts
|
|
2076
|
-
var textEncoder2 = new TextEncoder;
|
|
2077
|
-
var HEADER_TO_DEVICE = Uint8Array.of(201, 54, 184, 71);
|
|
2078
|
-
function encodeFixedText(value, field, maxBytes) {
|
|
2079
|
-
const encoded = textEncoder2.encode(value);
|
|
2080
|
-
if (encoded.byteLength > maxBytes) {
|
|
2081
|
-
throw new RangeError(`${field} must be at most ${maxBytes} UTF-8 bytes`);
|
|
2082
|
-
}
|
|
2083
|
-
return encoded;
|
|
2084
|
-
}
|
|
2085
|
-
|
|
2086
|
-
class PacketEncoder {
|
|
2087
|
-
static HEADERS_LENGTH = 4;
|
|
2088
|
-
static HEADER_TO_DEVICE = [201, 54, 184, 71];
|
|
2089
|
-
static HEADER_TO_HOST = [170, 85];
|
|
2090
|
-
static J2000_EPOCH = 946684800;
|
|
2091
|
-
vexVersion = 0;
|
|
2092
|
-
crcgen = new CrcGenerator;
|
|
2093
|
-
allPacketsTable = new Map;
|
|
2094
|
-
static getInstance() {
|
|
2095
|
-
Packet.ENCODER ??= new PacketEncoder;
|
|
2096
|
-
return Packet.ENCODER;
|
|
2097
|
-
}
|
|
2098
|
-
constructor() {
|
|
2099
|
-
for (const packet of Object.values(exports_VexPacketModels)) {
|
|
2100
|
-
if (typeof packet === "function" && packet.prototype instanceof HostBoundPacket) {
|
|
2101
|
-
const type = packet;
|
|
2102
|
-
let byExtendedId = this.allPacketsTable.get(type.COMMAND_ID);
|
|
2103
|
-
if (byExtendedId === undefined) {
|
|
2104
|
-
byExtendedId = new Map;
|
|
2105
|
-
this.allPacketsTable.set(type.COMMAND_ID, byExtendedId);
|
|
2106
|
-
}
|
|
2107
|
-
byExtendedId.set(type.COMMAND_EXTENDED_ID, type);
|
|
2108
|
-
}
|
|
2109
|
-
}
|
|
2110
|
-
}
|
|
2111
|
-
getPacketType(commandId, commandExtendedId) {
|
|
2112
|
-
if (commandId === undefined)
|
|
2113
|
-
return;
|
|
2114
|
-
return this.allPacketsTable.get(commandId)?.get(commandExtendedId);
|
|
2115
|
-
}
|
|
2116
|
-
createHeader(buf) {
|
|
2117
|
-
if (buf === undefined || buf.byteLength < PacketEncoder.HEADERS_LENGTH) {
|
|
2118
|
-
buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH);
|
|
2119
|
-
}
|
|
2120
|
-
const h = new Uint8Array(buf);
|
|
2121
|
-
h.set(HEADER_TO_DEVICE);
|
|
2122
|
-
return h;
|
|
2123
|
-
}
|
|
2124
|
-
cdcCommand(cmd) {
|
|
2125
|
-
const h = new Uint8Array(5);
|
|
2126
|
-
h.set(HEADER_TO_DEVICE);
|
|
2127
|
-
h[4] = cmd;
|
|
2128
|
-
return h;
|
|
2129
|
-
}
|
|
2130
|
-
cdcCommandWithData(cmd, data) {
|
|
2131
|
-
const h = new Uint8Array(6 + data.length);
|
|
2132
|
-
h.set(HEADER_TO_DEVICE);
|
|
2133
|
-
h[4] = cmd;
|
|
2134
|
-
h[5] = data.length;
|
|
2135
|
-
h.set(data, 6);
|
|
2136
|
-
return h;
|
|
2137
|
-
}
|
|
2138
|
-
cdc2Command(cmd, ext) {
|
|
2139
|
-
const h = new Uint8Array(9);
|
|
2140
|
-
h.set(HEADER_TO_DEVICE);
|
|
2141
|
-
h[4] = cmd;
|
|
2142
|
-
h[5] = ext;
|
|
2143
|
-
h[6] = 0;
|
|
2144
|
-
this.appendCrc16(h);
|
|
2145
|
-
return h;
|
|
2146
|
-
}
|
|
2147
|
-
cdc2CommandBufferLength(data) {
|
|
2148
|
-
return PacketEncoder.HEADERS_LENGTH + data.length + 5 + (data.length > 127 ? 1 : 0);
|
|
2149
|
-
}
|
|
2150
|
-
cdc2CommandWithData(cmd, ext, data) {
|
|
2151
|
-
const h = new Uint8Array(this.cdc2CommandBufferLength(data));
|
|
2152
|
-
h.set(HEADER_TO_DEVICE);
|
|
2153
|
-
h[4] = cmd;
|
|
2154
|
-
h[5] = ext;
|
|
2155
|
-
if (data.length < 128) {
|
|
2156
|
-
h[6] = data.length;
|
|
2157
|
-
h.set(data, 7);
|
|
2158
|
-
} else {
|
|
2159
|
-
h[6] = data.length >>> 8 | 128;
|
|
2160
|
-
h[7] = data.length & 255;
|
|
2161
|
-
h.set(data, 8);
|
|
2162
|
-
}
|
|
2163
|
-
this.appendCrc16(h);
|
|
2164
|
-
return h;
|
|
2165
|
-
}
|
|
2166
|
-
appendCrc16(h) {
|
|
2167
|
-
const crc = this.crcgen.crc16(h.subarray(0, h.length - 2), 0);
|
|
2168
|
-
h[h.length - 2] = crc >>> 8;
|
|
2169
|
-
h[h.length - 1] = crc & 255;
|
|
2170
|
-
}
|
|
2171
|
-
validateHeader(data) {
|
|
2172
|
-
return data[0] === PacketEncoder.HEADER_TO_HOST[0] && data[1] === PacketEncoder.HEADER_TO_HOST[1];
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
class SendDashTouchReplyD2HPacket extends HostBoundPacket {
|
|
1537
|
+
static COMMAND_ID = 86;
|
|
1538
|
+
static COMMAND_EXTENDED_ID = 42;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
class SelectDashReplyD2HPacket extends HostBoundPacket {
|
|
1542
|
+
static COMMAND_ID = 86;
|
|
1543
|
+
static COMMAND_EXTENDED_ID = 43;
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
class ReadKeyValueReplyD2HPacket extends HostBoundPacket {
|
|
1547
|
+
static COMMAND_ID = 86;
|
|
1548
|
+
static COMMAND_EXTENDED_ID = 46;
|
|
1549
|
+
value;
|
|
1550
|
+
constructor(data) {
|
|
1551
|
+
super(data);
|
|
1552
|
+
this.value = PacketView.fromPacket(this).nextVarNTBS(255);
|
|
2173
1553
|
}
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
class WriteKeyValueReplyD2HPacket extends HostBoundPacket {
|
|
1557
|
+
static COMMAND_ID = 86;
|
|
1558
|
+
static COMMAND_EXTENDED_ID = 47;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
class GetSlot1to4InfoReplyD2HPacket extends HostBoundPacket {
|
|
1562
|
+
static COMMAND_ID = 86;
|
|
1563
|
+
static COMMAND_EXTENDED_ID = 49;
|
|
1564
|
+
slotFlags;
|
|
1565
|
+
slots;
|
|
1566
|
+
constructor(data, start = 1) {
|
|
1567
|
+
super(data);
|
|
1568
|
+
const view = PacketView.fromPacket(this);
|
|
1569
|
+
this.slotFlags = view.nextUint8();
|
|
1570
|
+
this.slots = [];
|
|
1571
|
+
for (let i = 0;i < 4; i++) {
|
|
1572
|
+
if ((this.slotFlags & 1 << start - 1 + i) === 0)
|
|
1573
|
+
continue;
|
|
1574
|
+
const icon = view.nextUint16();
|
|
1575
|
+
const nameLen = view.nextUint8();
|
|
1576
|
+
this.slots.push({
|
|
1577
|
+
slot: start + i,
|
|
1578
|
+
icon,
|
|
1579
|
+
name: view.nextString(nameLen)
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
2177
1582
|
}
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
class GetSlot5to8InfoReplyD2HPacket extends GetSlot1to4InfoReplyD2HPacket {
|
|
1586
|
+
static COMMAND_ID = 86;
|
|
1587
|
+
static COMMAND_EXTENDED_ID = 50;
|
|
1588
|
+
slotStartIndex = 5;
|
|
1589
|
+
constructor(data) {
|
|
1590
|
+
super(data, 5);
|
|
2181
1591
|
}
|
|
2182
|
-
|
|
2183
|
-
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
class FactoryStatusReplyD2HPacket extends HostBoundPacket {
|
|
1595
|
+
static COMMAND_ID = 86;
|
|
1596
|
+
static COMMAND_EXTENDED_ID = 241;
|
|
1597
|
+
status;
|
|
1598
|
+
percent;
|
|
1599
|
+
constructor(data) {
|
|
1600
|
+
super(data);
|
|
1601
|
+
const view = PacketView.fromPacket(this);
|
|
1602
|
+
this.status = view.nextUint8();
|
|
1603
|
+
this.percent = view.nextUint8();
|
|
2184
1604
|
}
|
|
2185
1605
|
}
|
|
2186
1606
|
|
|
2187
|
-
|
|
2188
|
-
|
|
1607
|
+
class FactoryEnableReplyD2HPacket extends HostBoundPacket {
|
|
1608
|
+
static COMMAND_ID = 86;
|
|
1609
|
+
static COMMAND_EXTENDED_ID = 255;
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
// src/VexScreenCapture.ts
|
|
2189
1613
|
var SCREEN_CAPTURE_HEIGHT = 272;
|
|
2190
1614
|
var SCREEN_CAPTURE_WIDTH = 480;
|
|
2191
1615
|
var SCREEN_CAPTURE_CHANNELS = 3;
|
|
2192
1616
|
var SCREEN_CAPTURE_MESSAGE_WIDTH = 512;
|
|
2193
1617
|
var SCREEN_CAPTURE_MESSAGE_CHANNELS = 4;
|
|
1618
|
+
var SCREEN_CAPTURE_FRAMEBUFFER_SIZE = SCREEN_CAPTURE_MESSAGE_WIDTH * SCREEN_CAPTURE_HEIGHT * SCREEN_CAPTURE_MESSAGE_CHANNELS;
|
|
1619
|
+
function convertScreenCapture(framebuffer) {
|
|
1620
|
+
if (framebuffer.length !== SCREEN_CAPTURE_FRAMEBUFFER_SIZE) {
|
|
1621
|
+
throw new Error(`bad screen capture framebuffer size: ${framebuffer.length}; expected ${SCREEN_CAPTURE_FRAMEBUFFER_SIZE}`);
|
|
1622
|
+
}
|
|
1623
|
+
const pixels = new Uint8Array(SCREEN_CAPTURE_WIDTH * SCREEN_CAPTURE_HEIGHT * SCREEN_CAPTURE_CHANNELS);
|
|
1624
|
+
let source = 0;
|
|
1625
|
+
let target = 0;
|
|
1626
|
+
for (let row = 0;row < SCREEN_CAPTURE_HEIGHT; row++) {
|
|
1627
|
+
for (let column = 0;column < SCREEN_CAPTURE_WIDTH; column++) {
|
|
1628
|
+
pixels[target] = framebuffer[source + 2];
|
|
1629
|
+
pixels[target + 1] = framebuffer[source + 1];
|
|
1630
|
+
pixels[target + 2] = framebuffer[source];
|
|
1631
|
+
source += SCREEN_CAPTURE_MESSAGE_CHANNELS;
|
|
1632
|
+
target += SCREEN_CAPTURE_CHANNELS;
|
|
1633
|
+
}
|
|
1634
|
+
source += (SCREEN_CAPTURE_MESSAGE_WIDTH - SCREEN_CAPTURE_WIDTH) * SCREEN_CAPTURE_MESSAGE_CHANNELS;
|
|
1635
|
+
}
|
|
1636
|
+
return pixels;
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
// src/VexConnection.ts
|
|
1640
|
+
var thePacketEncoder = PacketEncoder.getInstance();
|
|
2194
1641
|
|
|
2195
1642
|
class VexSerialConnection extends VexEventTarget {
|
|
2196
1643
|
filters = [{ usbVendorId: 10376 }];
|
|
@@ -2198,12 +1645,31 @@ class VexSerialConnection extends VexEventTarget {
|
|
|
2198
1645
|
reader;
|
|
2199
1646
|
port;
|
|
2200
1647
|
serial;
|
|
2201
|
-
|
|
1648
|
+
pendingCallbacks = new Map;
|
|
1649
|
+
rawCallbacks = {
|
|
1650
|
+
head: undefined,
|
|
1651
|
+
tail: undefined
|
|
1652
|
+
};
|
|
1653
|
+
pendingCommandTails = new Map;
|
|
2202
1654
|
_onPortDisconnect = null;
|
|
2203
1655
|
_closePromise = null;
|
|
1656
|
+
_openPromise = null;
|
|
1657
|
+
_isClosing = false;
|
|
2204
1658
|
_wasConnected = false;
|
|
2205
1659
|
fileTransferTail = Promise.resolve();
|
|
2206
1660
|
fileTransferDepth = 0;
|
|
1661
|
+
get callbacksQueue() {
|
|
1662
|
+
const callbacks = [];
|
|
1663
|
+
for (const queue of this.pendingCallbacks.values()) {
|
|
1664
|
+
for (let callback = queue.head;callback; callback = callback.next) {
|
|
1665
|
+
callbacks.push(callback);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
for (let callback = this.rawCallbacks.head;callback; callback = callback.next) {
|
|
1669
|
+
callbacks.push(callback);
|
|
1670
|
+
}
|
|
1671
|
+
return callbacks;
|
|
1672
|
+
}
|
|
2207
1673
|
get isConnected() {
|
|
2208
1674
|
return this.port !== undefined && this.reader !== undefined && this.writer !== undefined;
|
|
2209
1675
|
}
|
|
@@ -2215,27 +1681,45 @@ class VexSerialConnection extends VexEventTarget {
|
|
|
2215
1681
|
this.serial = serial;
|
|
2216
1682
|
}
|
|
2217
1683
|
reportWarning(message, details) {
|
|
2218
|
-
this.
|
|
1684
|
+
this.emitSafely("warning", {
|
|
1685
|
+
message,
|
|
1686
|
+
details
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1689
|
+
emitSafely(eventName, data) {
|
|
1690
|
+
try {
|
|
1691
|
+
this.emit(eventName, data);
|
|
1692
|
+
} catch {}
|
|
2219
1693
|
}
|
|
2220
1694
|
async close() {
|
|
2221
1695
|
if (this._closePromise)
|
|
2222
1696
|
return this._closePromise;
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
this._closePromise =
|
|
1697
|
+
this._isClosing = true;
|
|
1698
|
+
const closing = this._closeAfterOpen();
|
|
1699
|
+
this._closePromise = closing;
|
|
2226
1700
|
try {
|
|
2227
|
-
await
|
|
1701
|
+
await closing;
|
|
2228
1702
|
} finally {
|
|
2229
|
-
this._closePromise
|
|
1703
|
+
if (this._closePromise === closing)
|
|
1704
|
+
this._closePromise = null;
|
|
1705
|
+
this._isClosing = false;
|
|
2230
1706
|
}
|
|
2231
1707
|
}
|
|
1708
|
+
async _closeAfterOpen() {
|
|
1709
|
+
const opening = this._openPromise;
|
|
1710
|
+
if (opening !== null)
|
|
1711
|
+
await opening;
|
|
1712
|
+
if (!this._hasOpenResources())
|
|
1713
|
+
return;
|
|
1714
|
+
await this._doClose();
|
|
1715
|
+
}
|
|
2232
1716
|
_hasOpenResources() {
|
|
2233
|
-
return this.port !== undefined || this.reader !== undefined || this.writer !== undefined || this._onPortDisconnect !== null || this.
|
|
1717
|
+
return this.port !== undefined || this.reader !== undefined || this.writer !== undefined || this._onPortDisconnect !== null || this.hasPendingCallbacks();
|
|
2234
1718
|
}
|
|
2235
1719
|
async _doClose() {
|
|
2236
|
-
for (const callback of this.
|
|
1720
|
+
for (const callback of this.drainPendingCallbacks()) {
|
|
2237
1721
|
clearTimeout(callback.timeout);
|
|
2238
|
-
callback.callback(
|
|
1722
|
+
callback.callback(258 /* NOT_CONNECTED */);
|
|
2239
1723
|
}
|
|
2240
1724
|
const onDisconnect = this._onPortDisconnect;
|
|
2241
1725
|
this._onPortDisconnect = null;
|
|
@@ -2284,11 +1768,22 @@ class VexSerialConnection extends VexEventTarget {
|
|
|
2284
1768
|
}
|
|
2285
1769
|
if (this._wasConnected) {
|
|
2286
1770
|
this._wasConnected = false;
|
|
2287
|
-
this.
|
|
1771
|
+
this.emitSafely("disconnected", undefined);
|
|
2288
1772
|
}
|
|
2289
1773
|
}
|
|
2290
1774
|
open(use = 0, askUser = true) {
|
|
2291
|
-
|
|
1775
|
+
if (this._openPromise !== null)
|
|
1776
|
+
return new import_neverthrow.ResultAsync(this._openPromise);
|
|
1777
|
+
const opening = this._open(use, askUser);
|
|
1778
|
+
this._openPromise = opening;
|
|
1779
|
+
opening.then(() => {
|
|
1780
|
+
if (this._openPromise === opening)
|
|
1781
|
+
this._openPromise = null;
|
|
1782
|
+
}, () => {
|
|
1783
|
+
if (this._openPromise === opening)
|
|
1784
|
+
this._openPromise = null;
|
|
1785
|
+
});
|
|
1786
|
+
return new import_neverthrow.ResultAsync(opening);
|
|
2292
1787
|
}
|
|
2293
1788
|
async _open(use, askUser) {
|
|
2294
1789
|
if (this._closePromise !== null)
|
|
@@ -2321,38 +1816,63 @@ class VexSerialConnection extends VexEventTarget {
|
|
|
2321
1816
|
this.reader = this.port.readable.getReader();
|
|
2322
1817
|
this.startReader();
|
|
2323
1818
|
this._wasConnected = true;
|
|
2324
|
-
this.
|
|
1819
|
+
this.emitSafely("connected", undefined);
|
|
2325
1820
|
return import_neverthrow.ok("opened");
|
|
2326
1821
|
} catch (e) {
|
|
2327
|
-
await this.
|
|
1822
|
+
await this._doClose();
|
|
2328
1823
|
return import_neverthrow.err(toVexSerialError(e, "io"));
|
|
2329
1824
|
}
|
|
2330
1825
|
}
|
|
2331
1826
|
async writeDataAsync(rawData, timeout = 1000) {
|
|
1827
|
+
if (rawData instanceof DeviceBoundPacket) {
|
|
1828
|
+
return this.serializeCommand(rawData.commandId, rawData.commandExtendedId, () => this.writeDataAsyncUnserialized(rawData, timeout));
|
|
1829
|
+
}
|
|
1830
|
+
return this.writeDataAsyncUnserialized(rawData, timeout);
|
|
1831
|
+
}
|
|
1832
|
+
async serializeCommand(commandId, commandExtendedId, operation) {
|
|
1833
|
+
const key = `${commandId}:${commandExtendedId ?? ""}`;
|
|
1834
|
+
const previous = this.pendingCommandTails.get(key) ?? Promise.resolve();
|
|
1835
|
+
let release = () => {};
|
|
1836
|
+
const current = new Promise((resolve) => {
|
|
1837
|
+
release = resolve;
|
|
1838
|
+
});
|
|
1839
|
+
this.pendingCommandTails.set(key, current);
|
|
1840
|
+
await previous;
|
|
1841
|
+
try {
|
|
1842
|
+
return await operation();
|
|
1843
|
+
} finally {
|
|
1844
|
+
release();
|
|
1845
|
+
if (this.pendingCommandTails.get(key) === current) {
|
|
1846
|
+
this.pendingCommandTails.delete(key);
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
async writeDataAsyncUnserialized(rawData, timeout) {
|
|
2332
1851
|
return new Promise((resolve) => {
|
|
2333
|
-
if (this.writer === undefined) {
|
|
2334
|
-
resolve(
|
|
1852
|
+
if (this.writer === undefined || this._isClosing) {
|
|
1853
|
+
resolve(258 /* NOT_CONNECTED */);
|
|
2335
1854
|
return;
|
|
2336
1855
|
}
|
|
2337
1856
|
const data = rawData instanceof DeviceBoundPacket ? rawData.data : rawData;
|
|
1857
|
+
const queue = rawData instanceof DeviceBoundPacket ? this.getPendingQueue(rawData.commandId, rawData.commandExtendedId, true) : this.rawCallbacks;
|
|
2338
1858
|
const cb = {
|
|
1859
|
+
active: true,
|
|
2339
1860
|
callback: resolve,
|
|
2340
1861
|
timeout: setTimeout(() => {
|
|
2341
|
-
|
|
2342
|
-
if (index === -1)
|
|
1862
|
+
if (!this.removePendingCallback(cb))
|
|
2343
1863
|
return;
|
|
2344
|
-
this.callbacksQueue.splice(index, 1);
|
|
2345
1864
|
cb.callback(256 /* TIMEOUT */);
|
|
2346
1865
|
}, timeout),
|
|
1866
|
+
next: undefined,
|
|
1867
|
+
previous: undefined,
|
|
1868
|
+
queue,
|
|
2347
1869
|
wantedCommandId: rawData instanceof DeviceBoundPacket ? rawData.commandId : undefined,
|
|
2348
1870
|
wantedCommandExId: rawData instanceof DeviceBoundPacket ? rawData.commandExtendedId : undefined
|
|
2349
1871
|
};
|
|
2350
|
-
this.
|
|
1872
|
+
this.enqueuePendingCallback(cb);
|
|
2351
1873
|
this.writer.write(data).catch(() => {
|
|
2352
|
-
|
|
2353
|
-
if (index === -1)
|
|
1874
|
+
if (!this.removePendingCallback(cb))
|
|
2354
1875
|
return;
|
|
2355
|
-
this.callbacksQueue.splice(index, 1);
|
|
2356
1876
|
clearTimeout(cb.timeout);
|
|
2357
1877
|
resolve(257 /* WRITE_ERROR */);
|
|
2358
1878
|
});
|
|
@@ -2363,6 +1883,9 @@ class VexSerialConnection extends VexEventTarget {
|
|
|
2363
1883
|
const result = await this.writeDataAsync(packet, timeout);
|
|
2364
1884
|
if (result instanceof ReplyType)
|
|
2365
1885
|
return import_neverthrow.ok(result);
|
|
1886
|
+
if (result === 258 /* NOT_CONNECTED */) {
|
|
1887
|
+
return import_neverthrow.err(new VexNotConnectedError);
|
|
1888
|
+
}
|
|
2366
1889
|
return import_neverthrow.err(new VexProtocolError(expectedReplyMessage(packet, ReplyType, result), typeof result === "number" ? result : undefined));
|
|
2367
1890
|
})());
|
|
2368
1891
|
}
|
|
@@ -2373,56 +1896,48 @@ class VexSerialConnection extends VexEventTarget {
|
|
|
2373
1896
|
const { value: readData, done: isDone } = await this.reader.read();
|
|
2374
1897
|
if (isDone)
|
|
2375
1898
|
throw new Error("No data");
|
|
2376
|
-
cache
|
|
1899
|
+
cache.append(readData);
|
|
2377
1900
|
}
|
|
2378
|
-
return cache;
|
|
2379
1901
|
}
|
|
2380
1902
|
async startReader() {
|
|
2381
|
-
|
|
1903
|
+
const cache = new ReceiveBuffer;
|
|
2382
1904
|
let sliceIdx = 0;
|
|
2383
1905
|
for (;; )
|
|
2384
1906
|
try {
|
|
2385
|
-
|
|
1907
|
+
await this.readData(cache, 5);
|
|
2386
1908
|
sliceIdx = 0;
|
|
2387
|
-
while (!thePacketEncoder.validateHeader(cache)) {
|
|
2388
|
-
const
|
|
1909
|
+
while (!thePacketEncoder.validateHeader(cache.bytes)) {
|
|
1910
|
+
const bytes = cache.bytes;
|
|
1911
|
+
const nextHeader = bytes.findIndex((byte, index) => index > 0 && byte === PacketEncoder.HEADER_TO_HOST[0] && bytes[index + 1] === PacketEncoder.HEADER_TO_HOST[1]);
|
|
2389
1912
|
if (nextHeader >= 0) {
|
|
2390
|
-
cache
|
|
1913
|
+
cache.discard(nextHeader);
|
|
2391
1914
|
} else {
|
|
2392
|
-
cache
|
|
1915
|
+
cache.discard(bytes.at(-1) === PacketEncoder.HEADER_TO_HOST[0] ? -1 : bytes.length);
|
|
2393
1916
|
}
|
|
2394
|
-
|
|
1917
|
+
await this.readData(cache, 5);
|
|
2395
1918
|
}
|
|
2396
|
-
const payloadExpectedSize = thePacketEncoder.getPayloadSize(cache);
|
|
2397
|
-
const n = thePacketEncoder.getHostHeaderLength(cache);
|
|
1919
|
+
const payloadExpectedSize = thePacketEncoder.getPayloadSize(cache.bytes);
|
|
1920
|
+
const n = thePacketEncoder.getHostHeaderLength(cache.bytes);
|
|
2398
1921
|
const totalSize = n + payloadExpectedSize;
|
|
2399
|
-
|
|
1922
|
+
await this.readData(cache, totalSize);
|
|
2400
1923
|
sliceIdx = totalSize;
|
|
2401
|
-
const
|
|
1924
|
+
const packet = cache.copy(totalSize);
|
|
1925
|
+
const cmdId = packet[2];
|
|
2402
1926
|
const hasExtId = cmdId === 88 || cmdId === 86;
|
|
2403
|
-
const cmdExId = hasExtId ?
|
|
2404
|
-
const ack =
|
|
1927
|
+
const cmdExId = hasExtId ? packet[n] : undefined;
|
|
1928
|
+
const ack = packet[n + 1];
|
|
2405
1929
|
if (hasExtId) {
|
|
2406
|
-
if (!thePacketEncoder.validateMessageCdc(
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
const candidate = this.callbacksQueue[i];
|
|
2413
|
-
if (candidate.wantedCommandId === undefined && candidate.wantedCommandExId === undefined) {
|
|
2414
|
-
if (untypedIdx === -1)
|
|
2415
|
-
untypedIdx = i;
|
|
1930
|
+
if (!thePacketEncoder.validateMessageCdc(packet)) {
|
|
1931
|
+
this.reportWarning("discarding a reply with an invalid CDC CRC", {
|
|
1932
|
+
commandId: cmdId,
|
|
1933
|
+
commandExtendedId: cmdExId,
|
|
1934
|
+
ack
|
|
1935
|
+
});
|
|
2416
1936
|
continue;
|
|
2417
1937
|
}
|
|
2418
|
-
if ((candidate.wantedCommandId === undefined || candidate.wantedCommandId === cmdId) && (candidate.wantedCommandExId === undefined || candidate.wantedCommandExId === cmdExId)) {
|
|
2419
|
-
matchIdx = i;
|
|
2420
|
-
break;
|
|
2421
|
-
}
|
|
2422
1938
|
}
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
if (matchIdx === -1) {
|
|
1939
|
+
const callbackInfo = this.shiftPendingCallback(cmdId, cmdExId) ?? this.shiftRawCallback();
|
|
1940
|
+
if (callbackInfo === undefined) {
|
|
2426
1941
|
this.reportWarning("received a reply with no matching request", {
|
|
2427
1942
|
commandId: cmdId,
|
|
2428
1943
|
commandExtendedId: cmdExId,
|
|
@@ -2430,38 +1945,117 @@ class VexSerialConnection extends VexEventTarget {
|
|
|
2430
1945
|
});
|
|
2431
1946
|
continue;
|
|
2432
1947
|
}
|
|
2433
|
-
const callbackInfo = this.callbacksQueue[matchIdx];
|
|
2434
1948
|
const wantedCmdId = callbackInfo.wantedCommandId;
|
|
2435
1949
|
const wantedCmdExId = callbackInfo.wantedCommandExId;
|
|
2436
|
-
const data = cache.slice(0, sliceIdx);
|
|
2437
1950
|
const PackageType = thePacketEncoder.getPacketType(wantedCmdId, wantedCmdExId);
|
|
2438
1951
|
if (wantedCmdId === undefined || PackageType === undefined) {
|
|
2439
1952
|
if (wantedCmdId !== undefined) {
|
|
2440
1953
|
this.reportWarning("no packet class is registered for the wanted command", { commandId: wantedCmdId, commandExtendedId: wantedCmdExId });
|
|
2441
1954
|
}
|
|
2442
|
-
callbackInfo.callback(
|
|
1955
|
+
callbackInfo.callback(packet.buffer);
|
|
2443
1956
|
} else {
|
|
2444
|
-
if (
|
|
2445
|
-
callbackInfo.callback(new PackageType(
|
|
1957
|
+
if (PackageType.isValidPacket(packet, n)) {
|
|
1958
|
+
callbackInfo.callback(new PackageType(packet));
|
|
2446
1959
|
} else {
|
|
2447
1960
|
this.reportWarning("reply failed packet validation; delivering its ack instead", { commandId: cmdId, commandExtendedId: cmdExId, ack });
|
|
2448
1961
|
callbackInfo.callback(ack);
|
|
2449
1962
|
}
|
|
2450
1963
|
}
|
|
2451
1964
|
clearTimeout(callbackInfo.timeout);
|
|
2452
|
-
this.callbacksQueue.splice(matchIdx, 1);
|
|
2453
1965
|
} catch (e) {
|
|
2454
1966
|
if (!(e instanceof Error && e.message === "No data")) {
|
|
2455
1967
|
this.reportWarning("reader loop stopped by a read error", {
|
|
2456
1968
|
error: e,
|
|
2457
|
-
pendingBytes: cache
|
|
1969
|
+
pendingBytes: cache.bytes
|
|
2458
1970
|
});
|
|
2459
1971
|
}
|
|
2460
1972
|
await this.close();
|
|
2461
1973
|
break;
|
|
2462
1974
|
} finally {
|
|
2463
|
-
cache
|
|
1975
|
+
cache.discard(sliceIdx);
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
pendingKey(commandId, commandExtendedId) {
|
|
1979
|
+
return `${commandId}:${commandExtendedId ?? ""}`;
|
|
1980
|
+
}
|
|
1981
|
+
getPendingQueue(commandId, commandExtendedId, create) {
|
|
1982
|
+
const key = this.pendingKey(commandId, commandExtendedId);
|
|
1983
|
+
let queue = this.pendingCallbacks.get(key);
|
|
1984
|
+
if (queue === undefined && create) {
|
|
1985
|
+
const created = { head: undefined, tail: undefined };
|
|
1986
|
+
this.pendingCallbacks.set(key, created);
|
|
1987
|
+
queue = created;
|
|
1988
|
+
}
|
|
1989
|
+
return queue ?? { head: undefined, tail: undefined };
|
|
1990
|
+
}
|
|
1991
|
+
enqueuePendingCallback(callback) {
|
|
1992
|
+
const tail = callback.queue.tail;
|
|
1993
|
+
callback.previous = tail;
|
|
1994
|
+
if (tail === undefined)
|
|
1995
|
+
callback.queue.head = callback;
|
|
1996
|
+
else
|
|
1997
|
+
tail.next = callback;
|
|
1998
|
+
callback.queue.tail = callback;
|
|
1999
|
+
}
|
|
2000
|
+
removePendingCallback(callback) {
|
|
2001
|
+
if (!callback.active)
|
|
2002
|
+
return false;
|
|
2003
|
+
callback.active = false;
|
|
2004
|
+
const { queue, previous, next } = callback;
|
|
2005
|
+
if (previous === undefined)
|
|
2006
|
+
queue.head = next;
|
|
2007
|
+
else
|
|
2008
|
+
previous.next = next;
|
|
2009
|
+
if (next === undefined)
|
|
2010
|
+
queue.tail = previous;
|
|
2011
|
+
else
|
|
2012
|
+
next.previous = previous;
|
|
2013
|
+
callback.previous = undefined;
|
|
2014
|
+
callback.next = undefined;
|
|
2015
|
+
if (queue !== this.rawCallbacks && queue.head === undefined && callback.wantedCommandId !== undefined) {
|
|
2016
|
+
this.pendingCallbacks.delete(this.pendingKey(callback.wantedCommandId, callback.wantedCommandExId));
|
|
2017
|
+
}
|
|
2018
|
+
return true;
|
|
2019
|
+
}
|
|
2020
|
+
shiftPendingCallback(commandId, commandExtendedId) {
|
|
2021
|
+
const queue = this.getPendingQueue(commandId, commandExtendedId, false);
|
|
2022
|
+
const callback = queue.head;
|
|
2023
|
+
if (callback !== undefined)
|
|
2024
|
+
this.removePendingCallback(callback);
|
|
2025
|
+
return callback;
|
|
2026
|
+
}
|
|
2027
|
+
shiftRawCallback() {
|
|
2028
|
+
const callback = this.rawCallbacks.head;
|
|
2029
|
+
if (callback !== undefined)
|
|
2030
|
+
this.removePendingCallback(callback);
|
|
2031
|
+
return callback;
|
|
2032
|
+
}
|
|
2033
|
+
hasPendingCallbacks() {
|
|
2034
|
+
return this.pendingCallbacks.size > 0 || this.rawCallbacks.head !== undefined;
|
|
2035
|
+
}
|
|
2036
|
+
drainPendingCallbacks() {
|
|
2037
|
+
const callbacks = [];
|
|
2038
|
+
for (const queue of this.pendingCallbacks.values()) {
|
|
2039
|
+
for (let callback = queue.head;callback; ) {
|
|
2040
|
+
const next = callback.next;
|
|
2041
|
+
callback.active = false;
|
|
2042
|
+
callback.previous = undefined;
|
|
2043
|
+
callback.next = undefined;
|
|
2044
|
+
callbacks.push(callback);
|
|
2045
|
+
callback = next;
|
|
2464
2046
|
}
|
|
2047
|
+
}
|
|
2048
|
+
for (let callback = this.rawCallbacks.head;callback; ) {
|
|
2049
|
+
const next = callback.next;
|
|
2050
|
+
callback.active = false;
|
|
2051
|
+
callback.previous = undefined;
|
|
2052
|
+
callback.next = undefined;
|
|
2053
|
+
callbacks.push(callback);
|
|
2054
|
+
callback = next;
|
|
2055
|
+
}
|
|
2056
|
+
this.pendingCallbacks.clear();
|
|
2057
|
+
this.rawCallbacks = { head: undefined, tail: undefined };
|
|
2058
|
+
return callbacks;
|
|
2465
2059
|
}
|
|
2466
2060
|
query1() {
|
|
2467
2061
|
return this.request(new Query1H2DPacket, Query1ReplyD2HPacket, 100);
|
|
@@ -2579,7 +2173,9 @@ class V5SerialConnection extends VexSerialConnection {
|
|
|
2579
2173
|
let bufferOffset = 0;
|
|
2580
2174
|
const fileBuf = new Uint8Array(fileSize);
|
|
2581
2175
|
while (bufferOffset < fileSize) {
|
|
2582
|
-
const
|
|
2176
|
+
const remainingSize = fileSize - bufferOffset;
|
|
2177
|
+
const chunkSize = Math.min(bufferChunkSize, remainingSize);
|
|
2178
|
+
const requestedSize = chunkSize + 3 & ~3;
|
|
2583
2179
|
const p2Result = await this.request(new ReadFileH2DPacket(nextAddress, requestedSize), ReadFileReplyD2HPacket, 3000);
|
|
2584
2180
|
if (p2Result.isErr())
|
|
2585
2181
|
throw p2Result.error;
|
|
@@ -2590,9 +2186,10 @@ class V5SerialConnection extends VexSerialConnection {
|
|
|
2590
2186
|
if (p2.length <= 0 || p2.length > requestedSize || p2.buf.byteLength !== p2.length) {
|
|
2591
2187
|
throw new VexTransferError(`ReadFileReplyD2HPacket returned invalid length ${p2.length}`);
|
|
2592
2188
|
}
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2189
|
+
const receivedSize = Math.min(p2.length, remainingSize);
|
|
2190
|
+
fileBuf.set(p2.buf.subarray(0, receivedSize), bufferOffset);
|
|
2191
|
+
bufferOffset += receivedSize;
|
|
2192
|
+
nextAddress += receivedSize;
|
|
2596
2193
|
progressCallback?.(bufferOffset, fileSize);
|
|
2597
2194
|
}
|
|
2598
2195
|
transferFailed = false;
|
|
@@ -2747,7 +2344,7 @@ class V5SerialConnection extends VexSerialConnection {
|
|
|
2747
2344
|
filename: "screen",
|
|
2748
2345
|
vendor: 15 /* SYS */,
|
|
2749
2346
|
loadAddress: 0,
|
|
2750
|
-
size:
|
|
2347
|
+
size: SCREEN_CAPTURE_FRAMEBUFFER_SIZE
|
|
2751
2348
|
}, 2 /* FILE_TARGET_CBUF */, progressCallback);
|
|
2752
2349
|
if (framebuffer.isErr())
|
|
2753
2350
|
return import_neverthrow.err(framebuffer.error);
|
|
@@ -2772,34 +2369,60 @@ class V5SerialConnection extends VexSerialConnection {
|
|
|
2772
2369
|
return this.request(new SelectDashH2DPacket(screen, port), SelectDashReplyD2HPacket);
|
|
2773
2370
|
}
|
|
2774
2371
|
}
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2372
|
+
|
|
2373
|
+
class ReceiveBuffer {
|
|
2374
|
+
storage = new Uint8Array(0);
|
|
2375
|
+
start = 0;
|
|
2376
|
+
end = 0;
|
|
2377
|
+
get byteLength() {
|
|
2378
|
+
return this.end - this.start;
|
|
2379
|
+
}
|
|
2380
|
+
get bytes() {
|
|
2381
|
+
return this.storage.subarray(this.start, this.end);
|
|
2382
|
+
}
|
|
2383
|
+
append(chunk) {
|
|
2384
|
+
this.reserve(chunk.byteLength);
|
|
2385
|
+
this.storage.set(chunk, this.end);
|
|
2386
|
+
this.end += chunk.byteLength;
|
|
2387
|
+
}
|
|
2388
|
+
copy(length) {
|
|
2389
|
+
return this.bytes.slice(0, length);
|
|
2390
|
+
}
|
|
2391
|
+
discard(length) {
|
|
2392
|
+
this.start += length < 0 ? this.byteLength + length : length;
|
|
2393
|
+
if (this.start < 0)
|
|
2394
|
+
this.start = 0;
|
|
2395
|
+
if (this.start > this.end)
|
|
2396
|
+
this.start = this.end;
|
|
2397
|
+
if (this.start === this.end) {
|
|
2398
|
+
this.start = 0;
|
|
2399
|
+
this.end = 0;
|
|
2400
|
+
} else if (this.start >= 4096 && this.start * 2 >= this.storage.length) {
|
|
2401
|
+
this.storage.copyWithin(0, this.start, this.end);
|
|
2402
|
+
this.end -= this.start;
|
|
2403
|
+
this.start = 0;
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
reserve(additional) {
|
|
2407
|
+
const required = this.byteLength + additional;
|
|
2408
|
+
if (this.storage.length - this.end >= additional)
|
|
2409
|
+
return;
|
|
2410
|
+
if (this.storage.length >= required) {
|
|
2411
|
+
this.storage.copyWithin(0, this.start, this.end);
|
|
2412
|
+
this.end = this.byteLength;
|
|
2413
|
+
this.start = 0;
|
|
2414
|
+
return;
|
|
2415
|
+
}
|
|
2416
|
+
const storage = new Uint8Array(Math.max(required, Math.max(64, this.storage.length * 2)));
|
|
2417
|
+
storage.set(this.bytes);
|
|
2418
|
+
this.end = this.byteLength;
|
|
2419
|
+
this.start = 0;
|
|
2420
|
+
this.storage = storage;
|
|
2421
|
+
}
|
|
2786
2422
|
}
|
|
2787
2423
|
function getTransferChunkSize(windowSize) {
|
|
2788
2424
|
return windowSize > 0 && windowSize <= USER_PROG_CHUNK_SIZE ? windowSize : USER_PROG_CHUNK_SIZE;
|
|
2789
2425
|
}
|
|
2790
|
-
function convertScreenCapture(framebuffer) {
|
|
2791
|
-
const pixels = new Uint8Array(SCREEN_CAPTURE_WIDTH * SCREEN_CAPTURE_HEIGHT * SCREEN_CAPTURE_CHANNELS);
|
|
2792
|
-
for (let row = 0;row < SCREEN_CAPTURE_HEIGHT; row++) {
|
|
2793
|
-
for (let column = 0;column < SCREEN_CAPTURE_WIDTH; column++) {
|
|
2794
|
-
const source = (row * SCREEN_CAPTURE_MESSAGE_WIDTH + column) * SCREEN_CAPTURE_MESSAGE_CHANNELS;
|
|
2795
|
-
const target = (row * SCREEN_CAPTURE_WIDTH + column) * SCREEN_CAPTURE_CHANNELS;
|
|
2796
|
-
pixels[target] = framebuffer[source + 2] ?? 0;
|
|
2797
|
-
pixels[target + 1] = framebuffer[source + 1] ?? 0;
|
|
2798
|
-
pixels[target + 2] = framebuffer[source] ?? 0;
|
|
2799
|
-
}
|
|
2800
|
-
}
|
|
2801
|
-
return pixels;
|
|
2802
|
-
}
|
|
2803
2426
|
function wrapTransfer(conn, operation) {
|
|
2804
2427
|
return new import_neverthrow.ResultAsync(conn.withFileTransfer(async () => {
|
|
2805
2428
|
try {
|
|
@@ -2823,10 +2446,10 @@ function ackTypeName(ackType) {
|
|
|
2823
2446
|
return `AckType.${AckType[ackType] ?? "UNKNOWN"} (${ackType})`;
|
|
2824
2447
|
}
|
|
2825
2448
|
// src/VexDeviceState.ts
|
|
2826
|
-
var import_neverthrow4 =
|
|
2449
|
+
var import_neverthrow4 = require("neverthrow");
|
|
2827
2450
|
|
|
2828
2451
|
// src/VexFirmware.ts
|
|
2829
|
-
var import_neverthrow2 =
|
|
2452
|
+
var import_neverthrow2 = require("neverthrow");
|
|
2830
2453
|
var MAX_CATALOG_BYTES = 4 * 1024;
|
|
2831
2454
|
var MAX_VEXOS_BYTES = 64 * 1024 * 1024;
|
|
2832
2455
|
var MAX_FIRMWARE_IMAGE_BYTES = 32 * 1024 * 1024;
|
|
@@ -2974,7 +2597,7 @@ async function flashFactoryImage(conn, options, pcb) {
|
|
|
2974
2597
|
autoRun: true,
|
|
2975
2598
|
linkedFile: undefined
|
|
2976
2599
|
};
|
|
2977
|
-
const upload = await conn.
|
|
2600
|
+
const upload = await conn.uploadFileToDeviceUnlocked(writeRequest, (c, t) => {
|
|
2978
2601
|
pcb(`UPLOAD ${label}`, c, t);
|
|
2979
2602
|
});
|
|
2980
2603
|
if (upload.isErr())
|
|
@@ -3101,34 +2724,40 @@ async function runUploadFirmware(state, publicUrl, usingVersion, progressCallbac
|
|
|
3101
2724
|
}
|
|
3102
2725
|
pcb("UNZIP VEXOS", 1, 1);
|
|
3103
2726
|
return state.withRefreshPaused(async () => {
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
2727
|
+
try {
|
|
2728
|
+
return await conn.withFileTransfer(async () => {
|
|
2729
|
+
const boot = images.find((image) => image.name.endsWith("BOOT.bin"));
|
|
2730
|
+
if (boot === undefined) {
|
|
2731
|
+
return import_neverthrow2.err(new VexFirmwareError("VEXos archive is missing BOOT.bin"));
|
|
2732
|
+
}
|
|
2733
|
+
const assertImage = images.find((image) => image.name.endsWith("assets.bin"));
|
|
2734
|
+
if (assertImage === undefined) {
|
|
2735
|
+
return import_neverthrow2.err(new VexFirmwareError("VEXos archive is missing assets.bin"));
|
|
2736
|
+
}
|
|
2737
|
+
const bootFlash = await flashFactoryImage(conn, {
|
|
2738
|
+
image: boot,
|
|
2739
|
+
label: "BOOT",
|
|
2740
|
+
downloadTarget: 14 /* FILE_TARGET_B1 */
|
|
2741
|
+
}, pcb);
|
|
2742
|
+
if (bootFlash.isErr())
|
|
2743
|
+
return import_neverthrow2.err(bootFlash.error);
|
|
2744
|
+
const assetsFlash = await flashFactoryImage(conn, {
|
|
2745
|
+
image: assertImage,
|
|
2746
|
+
label: "ASSETS",
|
|
2747
|
+
downloadTarget: 13 /* FILE_TARGET_A1 */
|
|
2748
|
+
}, pcb);
|
|
2749
|
+
if (assetsFlash.isErr())
|
|
2750
|
+
return import_neverthrow2.err(assetsFlash.error);
|
|
2751
|
+
return import_neverthrow2.ok(true);
|
|
2752
|
+
});
|
|
2753
|
+
} catch (e) {
|
|
2754
|
+
return import_neverthrow2.err(toVexSerialError(e, "firmware"));
|
|
3111
2755
|
}
|
|
3112
|
-
const bootFlash = await flashFactoryImage(conn, {
|
|
3113
|
-
image: boot,
|
|
3114
|
-
label: "BOOT",
|
|
3115
|
-
downloadTarget: 14 /* FILE_TARGET_B1 */
|
|
3116
|
-
}, pcb);
|
|
3117
|
-
if (bootFlash.isErr())
|
|
3118
|
-
return import_neverthrow2.err(bootFlash.error);
|
|
3119
|
-
const assetsFlash = await flashFactoryImage(conn, {
|
|
3120
|
-
image: assertImage,
|
|
3121
|
-
label: "ASSETS",
|
|
3122
|
-
downloadTarget: 13 /* FILE_TARGET_A1 */
|
|
3123
|
-
}, pcb);
|
|
3124
|
-
if (assetsFlash.isErr())
|
|
3125
|
-
return import_neverthrow2.err(assetsFlash.error);
|
|
3126
|
-
return import_neverthrow2.ok(true);
|
|
3127
2756
|
});
|
|
3128
2757
|
}
|
|
3129
2758
|
|
|
3130
2759
|
// src/VexTransfers.ts
|
|
3131
|
-
var import_neverthrow3 =
|
|
2760
|
+
var import_neverthrow3 = require("neverthrow");
|
|
3132
2761
|
function getValue(state, key) {
|
|
3133
2762
|
return new import_neverthrow3.ResultAsync((async () => {
|
|
3134
2763
|
const conn = state._instance.connection;
|
|
@@ -3662,7 +3291,7 @@ class V5Radio {
|
|
|
3662
3291
|
}
|
|
3663
3292
|
|
|
3664
3293
|
// src/VexDevice.ts
|
|
3665
|
-
var import_neverthrow5 =
|
|
3294
|
+
var import_neverthrow5 = require("neverthrow");
|
|
3666
3295
|
function unrefTimerIfPossible(timer) {
|
|
3667
3296
|
if (typeof timer !== "object" || timer === null || !("unref" in timer))
|
|
3668
3297
|
return;
|
|
@@ -3670,6 +3299,11 @@ function unrefTimerIfPossible(timer) {
|
|
|
3670
3299
|
if (typeof unref === "function")
|
|
3671
3300
|
unref.call(timer);
|
|
3672
3301
|
}
|
|
3302
|
+
function describePort(port) {
|
|
3303
|
+
const info = port.getInfo();
|
|
3304
|
+
const identifier = info.path ?? info.id ?? info.serialNumber;
|
|
3305
|
+
return typeof identifier === "string" ? identifier : undefined;
|
|
3306
|
+
}
|
|
3673
3307
|
|
|
3674
3308
|
class V5SerialDevice extends VexSerialDevice {
|
|
3675
3309
|
autoReconnect = true;
|
|
@@ -3679,8 +3313,11 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
3679
3313
|
_refreshInterval;
|
|
3680
3314
|
state = new V5SerialDeviceState(this);
|
|
3681
3315
|
_disposed = false;
|
|
3316
|
+
_lifecycleGeneration = 0;
|
|
3317
|
+
_disconnectListener;
|
|
3682
3318
|
_refreshGeneration = 0;
|
|
3683
3319
|
_autoRefresh = false;
|
|
3320
|
+
_refreshIntervalMs = 200;
|
|
3684
3321
|
_isLastRefreshComplete = true;
|
|
3685
3322
|
_brain = new V5Brain(this.state);
|
|
3686
3323
|
_controllers = [
|
|
@@ -3689,8 +3326,15 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
3689
3326
|
];
|
|
3690
3327
|
_radio = new V5Radio(this.state);
|
|
3691
3328
|
_deviceFacades = [];
|
|
3692
|
-
|
|
3329
|
+
_emitSafely(eventName, data) {
|
|
3330
|
+
try {
|
|
3331
|
+
this.emit(eventName, data);
|
|
3332
|
+
} catch {}
|
|
3333
|
+
}
|
|
3334
|
+
constructor(defaultSerial, options = false) {
|
|
3693
3335
|
super(defaultSerial);
|
|
3336
|
+
const autoRefresh = typeof options === "boolean" ? options : options.autoRefresh ?? false;
|
|
3337
|
+
this.refreshIntervalMs = typeof options === "boolean" ? 200 : options.refreshIntervalMs ?? 200;
|
|
3694
3338
|
this.autoRefresh = autoRefresh;
|
|
3695
3339
|
}
|
|
3696
3340
|
get autoRefresh() {
|
|
@@ -3706,6 +3350,21 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
3706
3350
|
this._stopRefreshInterval();
|
|
3707
3351
|
}
|
|
3708
3352
|
}
|
|
3353
|
+
get refreshIntervalMs() {
|
|
3354
|
+
return this._refreshIntervalMs;
|
|
3355
|
+
}
|
|
3356
|
+
set refreshIntervalMs(value) {
|
|
3357
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
3358
|
+
throw new VexInvalidArgumentError("refreshIntervalMs must be a positive finite number");
|
|
3359
|
+
}
|
|
3360
|
+
if (this._refreshIntervalMs === value)
|
|
3361
|
+
return;
|
|
3362
|
+
this._refreshIntervalMs = value;
|
|
3363
|
+
if (this._refreshInterval !== undefined) {
|
|
3364
|
+
this._stopRefreshInterval();
|
|
3365
|
+
this._startRefreshInterval();
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3709
3368
|
_startRefreshInterval() {
|
|
3710
3369
|
if (this._refreshInterval !== undefined || this._disposed)
|
|
3711
3370
|
return;
|
|
@@ -3723,16 +3382,16 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
3723
3382
|
try {
|
|
3724
3383
|
const r = await this.refresh();
|
|
3725
3384
|
if (r.isErr())
|
|
3726
|
-
this.
|
|
3385
|
+
this._emitSafely("error", r.error);
|
|
3727
3386
|
} catch (error) {
|
|
3728
|
-
this.
|
|
3387
|
+
this._emitSafely("error", error);
|
|
3729
3388
|
} finally {
|
|
3730
3389
|
this._isLastRefreshComplete = true;
|
|
3731
3390
|
}
|
|
3732
3391
|
})();
|
|
3733
3392
|
}
|
|
3734
3393
|
}
|
|
3735
|
-
},
|
|
3394
|
+
}, this._refreshIntervalMs);
|
|
3736
3395
|
unrefTimerIfPossible(this._refreshInterval);
|
|
3737
3396
|
}
|
|
3738
3397
|
_stopRefreshInterval() {
|
|
@@ -3795,58 +3454,125 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
3795
3454
|
})());
|
|
3796
3455
|
}
|
|
3797
3456
|
connect(conn) {
|
|
3798
|
-
|
|
3457
|
+
if (this._disposed) {
|
|
3458
|
+
return new import_neverthrow5.ResultAsync(Promise.resolve(this._staleLifecycleResult()));
|
|
3459
|
+
}
|
|
3460
|
+
if (this.isConnected)
|
|
3461
|
+
return new import_neverthrow5.ResultAsync(Promise.resolve(import_neverthrow5.ok(undefined)));
|
|
3462
|
+
const generation = ++this._lifecycleGeneration;
|
|
3463
|
+
return new import_neverthrow5.ResultAsync(this._connect(conn, generation));
|
|
3799
3464
|
}
|
|
3800
|
-
async _connect(conn) {
|
|
3465
|
+
async _connect(conn, generation = this._lifecycleGeneration) {
|
|
3466
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
3467
|
+
return this._staleLifecycleResult();
|
|
3468
|
+
}
|
|
3801
3469
|
if (this.isConnected)
|
|
3802
3470
|
return import_neverthrow5.ok(undefined);
|
|
3803
3471
|
if (conn != null) {
|
|
3804
3472
|
if (!conn.isConnected) {
|
|
3805
3473
|
const opened = await conn.open();
|
|
3474
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
3475
|
+
await conn.close();
|
|
3476
|
+
return this._staleLifecycleResult();
|
|
3477
|
+
}
|
|
3806
3478
|
if (opened.isErr() || opened.value !== "opened") {
|
|
3807
3479
|
return import_neverthrow5.err(new VexIoError("failed to open the supplied connection"));
|
|
3808
3480
|
}
|
|
3809
3481
|
}
|
|
3810
3482
|
const q = await conn.query1();
|
|
3483
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
3484
|
+
await conn.close();
|
|
3485
|
+
return this._staleLifecycleResult();
|
|
3486
|
+
}
|
|
3811
3487
|
if (q.isErr()) {
|
|
3812
3488
|
await conn.close();
|
|
3813
3489
|
return import_neverthrow5.err(q.error);
|
|
3814
3490
|
}
|
|
3815
|
-
this.
|
|
3491
|
+
if (!this._commitConnection(conn, generation)) {
|
|
3492
|
+
await conn.close();
|
|
3493
|
+
return this._staleLifecycleResult();
|
|
3494
|
+
}
|
|
3816
3495
|
} else {
|
|
3817
3496
|
let tryIdx = 0;
|
|
3497
|
+
let canRequestPort = true;
|
|
3498
|
+
const attemptedPorts = new Set;
|
|
3499
|
+
const attemptedPortNames = [];
|
|
3818
3500
|
while (true) {
|
|
3819
|
-
|
|
3820
|
-
|
|
3501
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
3502
|
+
return this._staleLifecycleResult();
|
|
3503
|
+
}
|
|
3504
|
+
const c = this.createConnection();
|
|
3505
|
+
let result = await c.open(tryIdx++, false);
|
|
3506
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
3507
|
+
await c.close();
|
|
3508
|
+
return this._staleLifecycleResult();
|
|
3509
|
+
}
|
|
3510
|
+
if (result.isOk() && result.value === "no-port" && canRequestPort) {
|
|
3511
|
+
canRequestPort = false;
|
|
3512
|
+
result = await c.open(tryIdx, true);
|
|
3513
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
3514
|
+
await c.close();
|
|
3515
|
+
return this._staleLifecycleResult();
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3821
3518
|
if (result.isErr()) {
|
|
3822
3519
|
await c.close();
|
|
3823
3520
|
return import_neverthrow5.err(result.error);
|
|
3824
3521
|
}
|
|
3825
3522
|
if (result.value === "no-port") {
|
|
3826
|
-
|
|
3523
|
+
const attempted = attemptedPortNames.length ? `; attempted ${attemptedPortNames.join(", ")}` : "";
|
|
3524
|
+
return import_neverthrow5.err(new VexNotConnectedError(`no responsive V5 device was found${attempted}`));
|
|
3827
3525
|
}
|
|
3828
3526
|
if (result.value === "busy") {
|
|
3829
3527
|
await c.close();
|
|
3830
|
-
|
|
3528
|
+
return import_neverthrow5.err(new VexNotConnectedError("the selected V5 serial port is busy"));
|
|
3529
|
+
}
|
|
3530
|
+
const port = c.port;
|
|
3531
|
+
if (port !== undefined && attemptedPorts.has(port)) {
|
|
3532
|
+
await c.close();
|
|
3533
|
+
const portName = describePort(port);
|
|
3534
|
+
return import_neverthrow5.err(new VexNotConnectedError(portName === undefined ? "the selected serial port did not respond as a V5 device" : `serial port ${portName} did not respond as a V5 device`));
|
|
3535
|
+
}
|
|
3536
|
+
if (port !== undefined) {
|
|
3537
|
+
attemptedPorts.add(port);
|
|
3538
|
+
const portName = describePort(port);
|
|
3539
|
+
if (portName !== undefined)
|
|
3540
|
+
attemptedPortNames.push(portName);
|
|
3831
3541
|
}
|
|
3832
3542
|
const q = await c.query1();
|
|
3543
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
3544
|
+
await c.close();
|
|
3545
|
+
return this._staleLifecycleResult();
|
|
3546
|
+
}
|
|
3833
3547
|
if (q.isErr()) {
|
|
3834
3548
|
await c.close();
|
|
3835
3549
|
continue;
|
|
3836
3550
|
}
|
|
3837
|
-
this.
|
|
3551
|
+
if (!this._commitConnection(c, generation)) {
|
|
3552
|
+
await c.close();
|
|
3553
|
+
return this._staleLifecycleResult();
|
|
3554
|
+
}
|
|
3838
3555
|
break;
|
|
3839
3556
|
}
|
|
3840
3557
|
}
|
|
3841
|
-
|
|
3558
|
+
const connection = this.connection;
|
|
3559
|
+
if (!this._isLifecycleCurrent(generation) || connection == null) {
|
|
3560
|
+
return this._staleLifecycleResult();
|
|
3561
|
+
}
|
|
3562
|
+
if (!connection.isConnected)
|
|
3842
3563
|
return import_neverthrow5.err(new VexNotConnectedError);
|
|
3843
|
-
await this.doAfterConnect();
|
|
3564
|
+
const initialized = await this.doAfterConnect(connection, generation);
|
|
3565
|
+
if (initialized.isErr())
|
|
3566
|
+
return initialized;
|
|
3844
3567
|
return import_neverthrow5.ok(undefined);
|
|
3845
3568
|
}
|
|
3846
3569
|
async disconnect() {
|
|
3570
|
+
this._lifecycleGeneration++;
|
|
3571
|
+
this._refreshGeneration++;
|
|
3847
3572
|
this._isDisconnecting = true;
|
|
3848
3573
|
const connection = this.connection;
|
|
3849
3574
|
this.connection = undefined;
|
|
3575
|
+
this._detachDisconnectListener();
|
|
3850
3576
|
try {
|
|
3851
3577
|
await connection?.close();
|
|
3852
3578
|
} finally {
|
|
@@ -3860,9 +3586,21 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
3860
3586
|
await this.disconnect();
|
|
3861
3587
|
}
|
|
3862
3588
|
reconnect(timeout = 0) {
|
|
3863
|
-
|
|
3589
|
+
if (this._disposed) {
|
|
3590
|
+
return new import_neverthrow5.ResultAsync(Promise.resolve(this._staleLifecycleResult()));
|
|
3591
|
+
}
|
|
3592
|
+
if (timeout < 0) {
|
|
3593
|
+
return new import_neverthrow5.ResultAsync(Promise.resolve(import_neverthrow5.err(new VexInvalidArgumentError("timeout must be non-negative"))));
|
|
3594
|
+
}
|
|
3595
|
+
if (this.isConnected)
|
|
3596
|
+
return new import_neverthrow5.ResultAsync(Promise.resolve(import_neverthrow5.ok(undefined)));
|
|
3597
|
+
const generation = this._isReconnecting ? this._lifecycleGeneration : ++this._lifecycleGeneration;
|
|
3598
|
+
return new import_neverthrow5.ResultAsync(this._reconnect(timeout, generation));
|
|
3864
3599
|
}
|
|
3865
|
-
async _reconnect(timeout) {
|
|
3600
|
+
async _reconnect(timeout, generation = this._lifecycleGeneration) {
|
|
3601
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
3602
|
+
return this._staleLifecycleResult();
|
|
3603
|
+
}
|
|
3866
3604
|
if (this.isConnected)
|
|
3867
3605
|
return import_neverthrow5.ok(undefined);
|
|
3868
3606
|
if (timeout < 0) {
|
|
@@ -3878,6 +3616,9 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
3878
3616
|
return import_neverthrow5.err(new VexNotConnectedError);
|
|
3879
3617
|
}
|
|
3880
3618
|
}
|
|
3619
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
3620
|
+
return this._staleLifecycleResult();
|
|
3621
|
+
}
|
|
3881
3622
|
if (this.isConnected)
|
|
3882
3623
|
return import_neverthrow5.ok(undefined);
|
|
3883
3624
|
}
|
|
@@ -3886,8 +3627,15 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
3886
3627
|
while (timeout === 0 || Date.now() < endTime) {
|
|
3887
3628
|
let tryIdx = 0;
|
|
3888
3629
|
while (true) {
|
|
3889
|
-
|
|
3630
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
3631
|
+
return this._staleLifecycleResult();
|
|
3632
|
+
}
|
|
3633
|
+
const c = this.createConnection();
|
|
3890
3634
|
const result = await c.open(tryIdx++, false);
|
|
3635
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
3636
|
+
await c.close();
|
|
3637
|
+
return this._staleLifecycleResult();
|
|
3638
|
+
}
|
|
3891
3639
|
if (result.isErr()) {
|
|
3892
3640
|
await c.close();
|
|
3893
3641
|
return import_neverthrow5.err(result.error);
|
|
@@ -3899,6 +3647,10 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
3899
3647
|
continue;
|
|
3900
3648
|
}
|
|
3901
3649
|
const status = await c.getSystemStatus(200);
|
|
3650
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
3651
|
+
await c.close();
|
|
3652
|
+
return this._staleLifecycleResult();
|
|
3653
|
+
}
|
|
3902
3654
|
if (status.isErr()) {
|
|
3903
3655
|
await c.close();
|
|
3904
3656
|
continue;
|
|
@@ -3907,23 +3659,38 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
3907
3659
|
await c.close();
|
|
3908
3660
|
continue;
|
|
3909
3661
|
}
|
|
3910
|
-
this.
|
|
3662
|
+
if (!this._commitConnection(c, generation)) {
|
|
3663
|
+
await c.close();
|
|
3664
|
+
return this._staleLifecycleResult();
|
|
3665
|
+
}
|
|
3911
3666
|
break;
|
|
3912
3667
|
}
|
|
3913
3668
|
if (this.isConnected)
|
|
3914
3669
|
break;
|
|
3915
3670
|
const getPortCount = async () => (await this.defaultSerial.getPorts()).length;
|
|
3916
3671
|
const portsCount = await getPortCount();
|
|
3672
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
3673
|
+
return this._staleLifecycleResult();
|
|
3674
|
+
}
|
|
3917
3675
|
await sleepUntilAsync(async () => await getPortCount() !== portsCount, 1000);
|
|
3676
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
3677
|
+
return this._staleLifecycleResult();
|
|
3678
|
+
}
|
|
3918
3679
|
}
|
|
3919
3680
|
} catch (e) {
|
|
3920
3681
|
return import_neverthrow5.err(toVexSerialError(e));
|
|
3921
3682
|
} finally {
|
|
3922
3683
|
this._isReconnecting = false;
|
|
3923
3684
|
}
|
|
3924
|
-
|
|
3685
|
+
const connection = this.connection;
|
|
3686
|
+
if (!this._isLifecycleCurrent(generation) || connection == null) {
|
|
3687
|
+
return this._staleLifecycleResult();
|
|
3688
|
+
}
|
|
3689
|
+
if (!connection.isConnected)
|
|
3925
3690
|
return import_neverthrow5.err(new VexNotConnectedError);
|
|
3926
|
-
await this.doAfterConnect();
|
|
3691
|
+
const initialized = await this.doAfterConnect(connection, generation);
|
|
3692
|
+
if (initialized.isErr())
|
|
3693
|
+
return initialized;
|
|
3927
3694
|
return import_neverthrow5.ok(undefined);
|
|
3928
3695
|
}
|
|
3929
3696
|
async waitForReconnectToFinish() {
|
|
@@ -3933,18 +3700,69 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
3933
3700
|
return;
|
|
3934
3701
|
}
|
|
3935
3702
|
}
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3703
|
+
createConnection() {
|
|
3704
|
+
return new V5SerialConnection(this.defaultSerial);
|
|
3705
|
+
}
|
|
3706
|
+
_isLifecycleCurrent(generation) {
|
|
3707
|
+
return generation === this._lifecycleGeneration && !this._disposed;
|
|
3708
|
+
}
|
|
3709
|
+
_staleLifecycleResult() {
|
|
3710
|
+
return import_neverthrow5.err(new VexNotConnectedError("connection attempt was superseded"));
|
|
3711
|
+
}
|
|
3712
|
+
_commitConnection(connection, generation) {
|
|
3713
|
+
if (!this._isLifecycleCurrent(generation))
|
|
3714
|
+
return false;
|
|
3715
|
+
this._detachDisconnectListener();
|
|
3716
|
+
this.connection = connection;
|
|
3717
|
+
return true;
|
|
3718
|
+
}
|
|
3719
|
+
_detachDisconnectListener() {
|
|
3720
|
+
const subscription = this._disconnectListener;
|
|
3721
|
+
this._disconnectListener = undefined;
|
|
3722
|
+
subscription?.connection.remove("disconnected", subscription.listener);
|
|
3723
|
+
}
|
|
3724
|
+
async doAfterConnect(connection, generation) {
|
|
3725
|
+
if (!this._isLifecycleCurrent(generation) || this.connection !== connection) {
|
|
3726
|
+
return this._staleLifecycleResult();
|
|
3727
|
+
}
|
|
3728
|
+
const listener = () => {
|
|
3729
|
+
if (this._isDisconnecting || !this._isLifecycleCurrent(generation) || this.connection !== connection) {
|
|
3941
3730
|
return;
|
|
3942
|
-
this.emit("disconnected", undefined);
|
|
3943
|
-
if (this.autoReconnect) {
|
|
3944
|
-
this.reconnect().mapErr((e) => this.emit("error", e));
|
|
3945
3731
|
}
|
|
3946
|
-
|
|
3947
|
-
|
|
3732
|
+
this._lifecycleGeneration++;
|
|
3733
|
+
this._refreshGeneration++;
|
|
3734
|
+
this.connection = undefined;
|
|
3735
|
+
this._detachDisconnectListener();
|
|
3736
|
+
this._emitSafely("disconnected", undefined);
|
|
3737
|
+
if (this.autoReconnect && !this._disposed) {
|
|
3738
|
+
this.reconnect().mapErr((error) => this._emitSafely("error", error));
|
|
3739
|
+
}
|
|
3740
|
+
};
|
|
3741
|
+
connection.on("disconnected", listener);
|
|
3742
|
+
this._disconnectListener = { connection, listener };
|
|
3743
|
+
const refreshed = await this.refresh();
|
|
3744
|
+
if (!this._isLifecycleCurrent(generation) || this.connection !== connection || !connection.isConnected) {
|
|
3745
|
+
return this._staleLifecycleResult();
|
|
3746
|
+
}
|
|
3747
|
+
if (refreshed.isErr()) {
|
|
3748
|
+
await this._discardConnection(connection, generation);
|
|
3749
|
+
return import_neverthrow5.err(refreshed.error);
|
|
3750
|
+
}
|
|
3751
|
+
if (!refreshed.value) {
|
|
3752
|
+
await this._discardConnection(connection, generation);
|
|
3753
|
+
return import_neverthrow5.err(new VexNotConnectedError("initial device refresh did not produce a current snapshot"));
|
|
3754
|
+
}
|
|
3755
|
+
return import_neverthrow5.ok(undefined);
|
|
3756
|
+
}
|
|
3757
|
+
async _discardConnection(connection, generation) {
|
|
3758
|
+
if (!this._isLifecycleCurrent(generation) || this.connection !== connection) {
|
|
3759
|
+
return;
|
|
3760
|
+
}
|
|
3761
|
+
this._lifecycleGeneration++;
|
|
3762
|
+
this._refreshGeneration++;
|
|
3763
|
+
this.connection = undefined;
|
|
3764
|
+
this._detachDisconnectListener();
|
|
3765
|
+
await connection.close();
|
|
3948
3766
|
}
|
|
3949
3767
|
refresh() {
|
|
3950
3768
|
return new import_neverthrow5.ResultAsync(this._refresh());
|
|
@@ -3958,31 +3776,15 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
3958
3776
|
this._applySnapshotIfCurrent(generation, { isAvailable: false });
|
|
3959
3777
|
return import_neverthrow5.ok(false);
|
|
3960
3778
|
}
|
|
3961
|
-
const ssPacket = await
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
}
|
|
3968
|
-
const sfPacket = await conn.getSystemFlags();
|
|
3969
|
-
if (generation !== this._refreshGeneration || this._disposed)
|
|
3970
|
-
return import_neverthrow5.ok(false);
|
|
3971
|
-
if (sfPacket.isErr()) {
|
|
3972
|
-
this._applySnapshotIfCurrent(generation, { isAvailable: false });
|
|
3973
|
-
return import_neverthrow5.ok(false);
|
|
3974
|
-
}
|
|
3975
|
-
const rdPacket = await conn.getRadioStatus();
|
|
3976
|
-
if (generation !== this._refreshGeneration || this._disposed)
|
|
3977
|
-
return import_neverthrow5.ok(false);
|
|
3978
|
-
if (rdPacket.isErr()) {
|
|
3979
|
-
this._applySnapshotIfCurrent(generation, { isAvailable: false });
|
|
3980
|
-
return import_neverthrow5.ok(false);
|
|
3981
|
-
}
|
|
3982
|
-
const dsPacket = await conn.getDeviceStatus();
|
|
3779
|
+
const [ssPacket, sfPacket, rdPacket, dsPacket] = await Promise.all([
|
|
3780
|
+
conn.getSystemStatus(),
|
|
3781
|
+
conn.getSystemFlags(),
|
|
3782
|
+
conn.getRadioStatus(),
|
|
3783
|
+
conn.getDeviceStatus()
|
|
3784
|
+
]);
|
|
3983
3785
|
if (generation !== this._refreshGeneration || this._disposed)
|
|
3984
3786
|
return import_neverthrow5.ok(false);
|
|
3985
|
-
if (dsPacket.isErr()) {
|
|
3787
|
+
if (ssPacket.isErr() || sfPacket.isErr() || rdPacket.isErr() || dsPacket.isErr()) {
|
|
3986
3788
|
this._applySnapshotIfCurrent(generation, { isAvailable: false });
|
|
3987
3789
|
return import_neverthrow5.ok(false);
|
|
3988
3790
|
}
|
|
@@ -4039,7 +3841,7 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
4039
3841
|
{
|
|
4040
3842
|
battery: controller1Battery,
|
|
4041
3843
|
isAvailable: controller1Available,
|
|
4042
|
-
isCharging:
|
|
3844
|
+
isCharging: undefined
|
|
4043
3845
|
}
|
|
4044
3846
|
],
|
|
4045
3847
|
radio: {
|
|
@@ -4066,7 +3868,26 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
4066
3868
|
}
|
|
4067
3869
|
this.state.matchMode = snapshot.matchMode;
|
|
4068
3870
|
this.state.isFieldControllerConnected = snapshot.isFieldControllerConnected;
|
|
4069
|
-
|
|
3871
|
+
const brain = this.state.brain;
|
|
3872
|
+
brain.activeProgram = snapshot.brain.activeProgram;
|
|
3873
|
+
brain.battery.batteryPercent = snapshot.brain.battery.batteryPercent;
|
|
3874
|
+
brain.battery.isCharging = snapshot.brain.battery.isCharging;
|
|
3875
|
+
brain.button.isPressed = snapshot.brain.button.isPressed;
|
|
3876
|
+
brain.button.isDoublePressed = snapshot.brain.button.isDoublePressed;
|
|
3877
|
+
if (brain.cpu0Version.compare(snapshot.brain.cpu0Version) !== 0) {
|
|
3878
|
+
brain.cpu0Version = snapshot.brain.cpu0Version;
|
|
3879
|
+
}
|
|
3880
|
+
if (brain.cpu1Version.compare(snapshot.brain.cpu1Version) !== 0) {
|
|
3881
|
+
brain.cpu1Version = snapshot.brain.cpu1Version;
|
|
3882
|
+
}
|
|
3883
|
+
brain.isAvailable = snapshot.brain.isAvailable;
|
|
3884
|
+
brain.settings.isScreenReversed = snapshot.brain.settings.isScreenReversed;
|
|
3885
|
+
brain.settings.isWhiteTheme = snapshot.brain.settings.isWhiteTheme;
|
|
3886
|
+
brain.settings.usingLanguage = snapshot.brain.settings.usingLanguage;
|
|
3887
|
+
if (brain.systemVersion.compare(snapshot.brain.systemVersion) !== 0) {
|
|
3888
|
+
brain.systemVersion = snapshot.brain.systemVersion;
|
|
3889
|
+
}
|
|
3890
|
+
brain.uniqueId = snapshot.brain.uniqueId;
|
|
4070
3891
|
Object.assign(this.state.controllers[0], snapshot.controllers[0]);
|
|
4071
3892
|
Object.assign(this.state.controllers[1], snapshot.controllers[1]);
|
|
4072
3893
|
Object.assign(this.state.radio, snapshot.radio);
|
|
@@ -4075,10 +3896,18 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
4075
3896
|
if (device != null)
|
|
4076
3897
|
next[device.port] = device;
|
|
4077
3898
|
}
|
|
4078
|
-
this.state.devices
|
|
3899
|
+
if (!sameSmartDeviceSlots(this.state.devices, next)) {
|
|
3900
|
+
this.state.devices = next;
|
|
3901
|
+
}
|
|
4079
3902
|
return true;
|
|
4080
3903
|
}
|
|
4081
3904
|
}
|
|
3905
|
+
function sameSmartDeviceSlots(left, right) {
|
|
3906
|
+
return left.length === right.length && left.every((device, index) => {
|
|
3907
|
+
const next = right[index];
|
|
3908
|
+
return device === next || device !== undefined && next !== undefined && device.port === next.port && device.type === next.type && device.status === next.status && device.betaversion === next.betaversion && device.version === next.version && device.bootversion === next.bootversion;
|
|
3909
|
+
});
|
|
3910
|
+
}
|
|
4082
3911
|
// src/VexIniConfig.ts
|
|
4083
3912
|
class BaseIniBuilder {
|
|
4084
3913
|
str = "";
|
|
@@ -4087,7 +3916,7 @@ class BaseIniBuilder {
|
|
|
4087
3916
|
`;
|
|
4088
3917
|
}
|
|
4089
3918
|
addComment(comment) {
|
|
4090
|
-
this.addLine("; " + comment);
|
|
3919
|
+
this.addLine(comment.length === 0 ? ";" : "; " + comment);
|
|
4091
3920
|
return this;
|
|
4092
3921
|
}
|
|
4093
3922
|
getContent() {
|
|
@@ -4105,18 +3934,23 @@ class IniSectionBuilder extends BaseIniBuilder {
|
|
|
4105
3934
|
this.object = object;
|
|
4106
3935
|
this.keyTransform = keyTransform;
|
|
4107
3936
|
}
|
|
4108
|
-
addSingleObjProperty(key, maxValueLength) {
|
|
4109
|
-
const
|
|
4110
|
-
if (
|
|
3937
|
+
addSingleObjProperty(key, maxValueLength, omitIfEmpty = false) {
|
|
3938
|
+
const rawValue = this.object[key];
|
|
3939
|
+
if (rawValue == null)
|
|
3940
|
+
return;
|
|
3941
|
+
const value = rawValue.toString();
|
|
3942
|
+
if (omitIfEmpty && value.length === 0)
|
|
4111
3943
|
return;
|
|
3944
|
+
if (/["\u0000-\u001f\u007f]/.test(value)) {
|
|
3945
|
+
throw new Error(`INI value for ${this.name}.${String(key)} contains an unsupported character`);
|
|
3946
|
+
}
|
|
4112
3947
|
const formattedKey = this.keyTransform(key).padEnd(12).slice(0, 12);
|
|
4113
|
-
const
|
|
4114
|
-
|
|
4115
|
-
this.addLine(`${formattedKey} = "${escapedVal}"`);
|
|
3948
|
+
const trimmedValue = value.slice(0, maxValueLength);
|
|
3949
|
+
this.addLine(`${formattedKey} = "${trimmedValue}"`);
|
|
4116
3950
|
}
|
|
4117
|
-
addObjProperty(key, maxValueLength) {
|
|
3951
|
+
addObjProperty(key, maxValueLength, omitIfEmpty = false) {
|
|
4118
3952
|
for (const k of Array.isArray(key) ? key : [key]) {
|
|
4119
|
-
this.addSingleObjProperty(k, maxValueLength);
|
|
3953
|
+
this.addSingleObjProperty(k, maxValueLength, omitIfEmpty);
|
|
4120
3954
|
}
|
|
4121
3955
|
return this;
|
|
4122
3956
|
}
|
|
@@ -4134,6 +3968,11 @@ class IniFileBuilder extends BaseIniBuilder {
|
|
|
4134
3968
|
this.str += section.getContent();
|
|
4135
3969
|
return this;
|
|
4136
3970
|
}
|
|
3971
|
+
addOptionalSection(section) {
|
|
3972
|
+
if (section.getContent().length === 0)
|
|
3973
|
+
return this;
|
|
3974
|
+
return this.addComment("").addSection(section);
|
|
3975
|
+
}
|
|
4137
3976
|
}
|
|
4138
3977
|
|
|
4139
3978
|
class ProgramIniConfig {
|
|
@@ -4164,12 +4003,12 @@ class ProgramIniConfig {
|
|
|
4164
4003
|
if (this.program.date.length === 0) {
|
|
4165
4004
|
this.setProgramDate(new Date);
|
|
4166
4005
|
}
|
|
4167
|
-
return new IniFileBuilder().addComment("").addComment("VEX program ini file").addComment("Generated by Vex V5 Serial Protocol Library").addComment("").addSection(new IniSectionBuilder("project", this.project).addObjProperty("ide", 16)).addComment("").addSection(new IniSectionBuilder("program", this.program).addObjProperty("name", 32).addObjProperty("
|
|
4006
|
+
return new IniFileBuilder().addComment("").addComment("VEX program ini file").addComment("Generated by Vex V5 Serial Protocol Library").addComment("").addSection(new IniSectionBuilder("project", this.project).addObjProperty("version").addObjProperty("ide", 16).addObjProperty("file")).addComment("").addSection(new IniSectionBuilder("program", this.program).addObjProperty("version").addObjProperty("name", 32).addObjProperty("slot").addObjProperty("icon", 16).addObjProperty("iconalt", 16, true).addObjProperty("description", 256).addObjProperty("date").addObjProperty("timezone")).addComment("").addSection(new IniSectionBuilder("config", this.config, (k) => "port_" + this.dec2(k)).addAllObjProps()).addOptionalSection(new IniSectionBuilder("controller_1", this.controller1).addAllObjProps()).addOptionalSection(new IniSectionBuilder("controller_2", this.controller2).addAllObjProps()).getContent();
|
|
4168
4007
|
}
|
|
4169
4008
|
dec2(value) {
|
|
4170
4009
|
return (value % 100).toString(10).padStart(2, "0").toUpperCase();
|
|
4171
4010
|
}
|
|
4172
4011
|
}
|
|
4173
4012
|
|
|
4174
|
-
//# debugId=
|
|
4013
|
+
//# debugId=60E9322CE95DA15264756E2164756E21
|
|
4175
4014
|
//# sourceMappingURL=index.cjs.map
|