@v5x/cli 0.0.16 → 0.0.17
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/dist/index.js +3800 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -31,6 +31,19 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
31
31
|
return to;
|
|
32
32
|
};
|
|
33
33
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
34
|
+
var __returnValue = (v) => v;
|
|
35
|
+
function __exportSetter(name, newValue) {
|
|
36
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
37
|
+
}
|
|
38
|
+
var __export = (target, all) => {
|
|
39
|
+
for (var name in all)
|
|
40
|
+
__defProp(target, name, {
|
|
41
|
+
get: all[name],
|
|
42
|
+
enumerable: true,
|
|
43
|
+
configurable: true,
|
|
44
|
+
set: __exportSetter.bind(all, name)
|
|
45
|
+
});
|
|
46
|
+
};
|
|
34
47
|
var __require = import.meta.require;
|
|
35
48
|
|
|
36
49
|
// ../../node_modules/.bun/commander@14.0.3/node_modules/commander/lib/error.js
|
|
@@ -2128,7 +2141,7 @@ var require_commander = __commonJS((exports) => {
|
|
|
2128
2141
|
// package.json
|
|
2129
2142
|
var package_default = {
|
|
2130
2143
|
name: "@v5x/cli",
|
|
2131
|
-
version: "0.0.
|
|
2144
|
+
version: "0.0.17",
|
|
2132
2145
|
description: "Command line interface for v5x.",
|
|
2133
2146
|
license: "MIT",
|
|
2134
2147
|
type: "module",
|
|
@@ -2189,6 +2202,8 @@ var {
|
|
|
2189
2202
|
|
|
2190
2203
|
// src/commands/build.ts
|
|
2191
2204
|
import { exists } from "fs/promises";
|
|
2205
|
+
|
|
2206
|
+
// src/utils/detect.ts
|
|
2192
2207
|
import { join } from "path";
|
|
2193
2208
|
async function detectProgramType(path) {
|
|
2194
2209
|
const prosFile = Bun.file(join(path, "project.pros"));
|
|
@@ -2213,6 +2228,8 @@ async function detectProgramType(path) {
|
|
|
2213
2228
|
}
|
|
2214
2229
|
return "unknown";
|
|
2215
2230
|
}
|
|
2231
|
+
|
|
2232
|
+
// src/commands/build.ts
|
|
2216
2233
|
var build = new Command("build").alias("b").description("build a program for the vex v5 brain").argument("[path]", "path to the program", process.cwd()).option("-t, --type <type>", "type of the program").action(async (path, options) => {
|
|
2217
2234
|
if (!await exists(path)) {
|
|
2218
2235
|
console.error(`path does not exist: ${path}`);
|
|
@@ -2232,7 +2249,15 @@ var build = new Command("build").alias("b").description("build a program for the
|
|
|
2232
2249
|
await makeProc.exited;
|
|
2233
2250
|
process.exit(makeProc.exitCode);
|
|
2234
2251
|
case "vexide":
|
|
2235
|
-
|
|
2252
|
+
const cargoProc = Bun.spawn({
|
|
2253
|
+
cmd: ["cargo", "v5", "build"],
|
|
2254
|
+
cwd: path,
|
|
2255
|
+
stdout: "inherit",
|
|
2256
|
+
stderr: "inherit",
|
|
2257
|
+
stdin: "inherit"
|
|
2258
|
+
});
|
|
2259
|
+
await cargoProc.exited;
|
|
2260
|
+
process.exit(cargoProc.exitCode ?? 1);
|
|
2236
2261
|
case "vexcode-py":
|
|
2237
2262
|
break;
|
|
2238
2263
|
case "unknown":
|
|
@@ -2244,6 +2269,3778 @@ var build = new Command("build").alias("b").description("build a program for the
|
|
|
2244
2269
|
}
|
|
2245
2270
|
});
|
|
2246
2271
|
|
|
2272
|
+
// src/commands/upload.ts
|
|
2273
|
+
import { exists as exists3 } from "fs/promises";
|
|
2274
|
+
import { join as join4 } from "path";
|
|
2275
|
+
|
|
2276
|
+
// ../serial/src/Vex.ts
|
|
2277
|
+
var USER_PROG_CHUNK_SIZE = 4096;
|
|
2278
|
+
var USER_FLASH_USR_CODE_START = 58720256;
|
|
2279
|
+
// ../serial/src/VexEvent.ts
|
|
2280
|
+
class VexEventEmitter {
|
|
2281
|
+
handlerMap;
|
|
2282
|
+
constructor() {
|
|
2283
|
+
this.handlerMap = new Map;
|
|
2284
|
+
}
|
|
2285
|
+
on(eventName, listener) {
|
|
2286
|
+
let listeners = this.handlerMap.get(eventName);
|
|
2287
|
+
listeners ??= [];
|
|
2288
|
+
listeners.push(listener);
|
|
2289
|
+
this.handlerMap.set(eventName, listeners);
|
|
2290
|
+
}
|
|
2291
|
+
remove(eventName, listener) {
|
|
2292
|
+
let listeners = this.handlerMap.get(eventName);
|
|
2293
|
+
listeners ??= [];
|
|
2294
|
+
const index = listeners.indexOf(listener);
|
|
2295
|
+
if (index > -1) {
|
|
2296
|
+
listeners.splice(index, 1);
|
|
2297
|
+
}
|
|
2298
|
+
this.handlerMap.set(eventName, listeners);
|
|
2299
|
+
}
|
|
2300
|
+
emit(eventName, data) {
|
|
2301
|
+
(this.handlerMap.get(eventName) ?? []).forEach((callback) => {
|
|
2302
|
+
callback(data);
|
|
2303
|
+
});
|
|
2304
|
+
}
|
|
2305
|
+
clearListeners() {
|
|
2306
|
+
this.handlerMap.clear();
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
class VexEventTarget {
|
|
2311
|
+
emitter;
|
|
2312
|
+
constructor() {
|
|
2313
|
+
this.emitter = new VexEventEmitter;
|
|
2314
|
+
}
|
|
2315
|
+
emit(eventName, data) {
|
|
2316
|
+
this.emitter.emit(String(eventName), data);
|
|
2317
|
+
}
|
|
2318
|
+
on(eventName, listener) {
|
|
2319
|
+
this.emitter.on(String(eventName), listener);
|
|
2320
|
+
}
|
|
2321
|
+
remove(eventName, listener) {
|
|
2322
|
+
this.emitter.remove(String(eventName), listener);
|
|
2323
|
+
}
|
|
2324
|
+
clearListeners() {
|
|
2325
|
+
this.emitter.clearListeners();
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
|
|
2329
|
+
// ../serial/src/VexPacket.ts
|
|
2330
|
+
var exports_VexPacket = {};
|
|
2331
|
+
__export(exports_VexPacket, {
|
|
2332
|
+
WriteKeyValueReplyD2HPacket: () => WriteKeyValueReplyD2HPacket,
|
|
2333
|
+
WriteKeyValueH2DPacket: () => WriteKeyValueH2DPacket,
|
|
2334
|
+
WriteFileReplyD2HPacket: () => WriteFileReplyD2HPacket,
|
|
2335
|
+
WriteFileH2DPacket: () => WriteFileH2DPacket,
|
|
2336
|
+
UpdateMatchModeH2DPacket: () => UpdateMatchModeH2DPacket,
|
|
2337
|
+
SystemVersionReplyD2HPacket: () => SystemVersionReplyD2HPacket,
|
|
2338
|
+
SystemVersionH2DPacket: () => SystemVersionH2DPacket,
|
|
2339
|
+
SetFileMetadataReplyD2HPacket: () => SetFileMetadataReplyD2HPacket,
|
|
2340
|
+
SetFileMetadataH2DPacket: () => SetFileMetadataH2DPacket,
|
|
2341
|
+
SendDashTouchReplyD2HPacket: () => SendDashTouchReplyD2HPacket,
|
|
2342
|
+
SendDashTouchH2DPacket: () => SendDashTouchH2DPacket,
|
|
2343
|
+
SelectDashReplyD2HPacket: () => SelectDashReplyD2HPacket,
|
|
2344
|
+
SelectDashH2DPacket: () => SelectDashH2DPacket,
|
|
2345
|
+
ScreenCaptureReplyD2HPacket: () => ScreenCaptureReplyD2HPacket,
|
|
2346
|
+
ScreenCaptureH2DPacket: () => ScreenCaptureH2DPacket,
|
|
2347
|
+
ReadLogPageReplyD2HPacket: () => ReadLogPageReplyD2HPacket,
|
|
2348
|
+
ReadLogPageH2DPacket: () => ReadLogPageH2DPacket,
|
|
2349
|
+
ReadKeyValueReplyD2HPacket: () => ReadKeyValueReplyD2HPacket,
|
|
2350
|
+
ReadKeyValueH2DPacket: () => ReadKeyValueH2DPacket,
|
|
2351
|
+
ReadFileReplyD2HPacket: () => ReadFileReplyD2HPacket,
|
|
2352
|
+
ReadFileH2DPacket: () => ReadFileH2DPacket,
|
|
2353
|
+
Query1ReplyD2HPacket: () => Query1ReplyD2HPacket,
|
|
2354
|
+
Query1H2DPacket: () => Query1H2DPacket,
|
|
2355
|
+
PacketEncoder: () => PacketEncoder,
|
|
2356
|
+
Packet: () => Packet,
|
|
2357
|
+
MatchStatusReplyD2HPacket: () => MatchStatusReplyD2HPacket,
|
|
2358
|
+
MatchModeReplyD2HPacket: () => MatchModeReplyD2HPacket,
|
|
2359
|
+
LoadFileActionReplyD2HPacket: () => LoadFileActionReplyD2HPacket,
|
|
2360
|
+
LoadFileActionH2DPacket: () => LoadFileActionH2DPacket,
|
|
2361
|
+
LinkFileReplyD2HPacket: () => LinkFileReplyD2HPacket,
|
|
2362
|
+
LinkFileH2DPacket: () => LinkFileH2DPacket,
|
|
2363
|
+
InitFileTransferReplyD2HPacket: () => InitFileTransferReplyD2HPacket,
|
|
2364
|
+
InitFileTransferH2DPacket: () => InitFileTransferH2DPacket,
|
|
2365
|
+
HostBoundPacket: () => HostBoundPacket,
|
|
2366
|
+
GetUserDataReplyD2HPacket: () => GetUserDataReplyD2HPacket,
|
|
2367
|
+
GetUserDataH2DPacket: () => GetUserDataH2DPacket,
|
|
2368
|
+
GetSystemStatusReplyD2HPacket: () => GetSystemStatusReplyD2HPacket,
|
|
2369
|
+
GetSystemStatusH2DPacket: () => GetSystemStatusH2DPacket,
|
|
2370
|
+
GetSystemFlagsReplyD2HPacket: () => GetSystemFlagsReplyD2HPacket,
|
|
2371
|
+
GetSystemFlagsH2DPacket: () => GetSystemFlagsH2DPacket,
|
|
2372
|
+
GetSlot5to8InfoReplyD2HPacket: () => GetSlot5to8InfoReplyD2HPacket,
|
|
2373
|
+
GetSlot5to8InfoH2DPacket: () => GetSlot5to8InfoH2DPacket,
|
|
2374
|
+
GetSlot1to4InfoReplyD2HPacket: () => GetSlot1to4InfoReplyD2HPacket,
|
|
2375
|
+
GetSlot1to4InfoH2DPacket: () => GetSlot1to4InfoH2DPacket,
|
|
2376
|
+
GetRadioStatusReplyD2HPacket: () => GetRadioStatusReplyD2HPacket,
|
|
2377
|
+
GetRadioStatusH2DPacket: () => GetRadioStatusH2DPacket,
|
|
2378
|
+
GetRadioModeH2DPacket: () => GetRadioModeH2DPacket,
|
|
2379
|
+
GetProgramSlotInfoReplyD2HPacket: () => GetProgramSlotInfoReplyD2HPacket,
|
|
2380
|
+
GetProgramSlotInfoH2DPacket: () => GetProgramSlotInfoH2DPacket,
|
|
2381
|
+
GetMatchStatusH2DPacket: () => GetMatchStatusH2DPacket,
|
|
2382
|
+
GetLogCountReplyD2HPacket: () => GetLogCountReplyD2HPacket,
|
|
2383
|
+
GetLogCountH2DPacket: () => GetLogCountH2DPacket,
|
|
2384
|
+
GetFileMetadataReplyD2HPacket: () => GetFileMetadataReplyD2HPacket,
|
|
2385
|
+
GetFileMetadataH2DPacket: () => GetFileMetadataH2DPacket,
|
|
2386
|
+
GetFdtStatusReplyD2HPacket: () => GetFdtStatusReplyD2HPacket,
|
|
2387
|
+
GetFdtStatusH2DPacket: () => GetFdtStatusH2DPacket,
|
|
2388
|
+
GetDirectoryFileCountReplyD2HPacket: () => GetDirectoryFileCountReplyD2HPacket,
|
|
2389
|
+
GetDirectoryFileCountH2DPacket: () => GetDirectoryFileCountH2DPacket,
|
|
2390
|
+
GetDirectoryEntryReplyD2HPacket: () => GetDirectoryEntryReplyD2HPacket,
|
|
2391
|
+
GetDirectoryEntryH2DPacket: () => GetDirectoryEntryH2DPacket,
|
|
2392
|
+
GetDeviceStatusReplyD2HPacket: () => GetDeviceStatusReplyD2HPacket,
|
|
2393
|
+
GetDeviceStatusH2DPacket: () => GetDeviceStatusH2DPacket,
|
|
2394
|
+
FileFormatReplyD2HPacket: () => FileFormatReplyD2HPacket,
|
|
2395
|
+
FileFormatH2DPacket: () => FileFormatH2DPacket,
|
|
2396
|
+
FileControlReplyD2HPacket: () => FileControlReplyD2HPacket,
|
|
2397
|
+
FileControlH2DPacket: () => FileControlH2DPacket,
|
|
2398
|
+
FileClearUpReplyD2HPacket: () => FileClearUpReplyD2HPacket,
|
|
2399
|
+
FileClearUpH2DPacket: () => FileClearUpH2DPacket,
|
|
2400
|
+
FactoryStatusReplyD2HPacket: () => FactoryStatusReplyD2HPacket,
|
|
2401
|
+
FactoryStatusH2DPacket: () => FactoryStatusH2DPacket,
|
|
2402
|
+
FactoryEnableReplyD2HPacket: () => FactoryEnableReplyD2HPacket,
|
|
2403
|
+
FactoryEnableH2DPacket: () => FactoryEnableH2DPacket,
|
|
2404
|
+
ExitFileTransferReplyD2HPacket: () => ExitFileTransferReplyD2HPacket,
|
|
2405
|
+
ExitFileTransferH2DPacket: () => ExitFileTransferH2DPacket,
|
|
2406
|
+
EraseFileReplyD2HPacket: () => EraseFileReplyD2HPacket,
|
|
2407
|
+
EraseFileH2DPacket: () => EraseFileH2DPacket,
|
|
2408
|
+
EnableDashReplyD2HPacket: () => EnableDashReplyD2HPacket,
|
|
2409
|
+
EnableDashH2DPacket: () => EnableDashH2DPacket,
|
|
2410
|
+
DisableDashReplyD2HPacket: () => DisableDashReplyD2HPacket,
|
|
2411
|
+
DisableDashH2DPacket: () => DisableDashH2DPacket,
|
|
2412
|
+
DeviceBoundPacket: () => DeviceBoundPacket
|
|
2413
|
+
});
|
|
2414
|
+
|
|
2415
|
+
// ../serial/src/VexFirmwareVersion.ts
|
|
2416
|
+
class VexFirmwareVersion {
|
|
2417
|
+
major;
|
|
2418
|
+
minor;
|
|
2419
|
+
build;
|
|
2420
|
+
beta;
|
|
2421
|
+
constructor(major, minor, build2, beta) {
|
|
2422
|
+
this.major = major;
|
|
2423
|
+
this.minor = minor;
|
|
2424
|
+
this.build = build2;
|
|
2425
|
+
this.beta = beta;
|
|
2426
|
+
}
|
|
2427
|
+
static fromString(version) {
|
|
2428
|
+
const parts = version.toLowerCase().replace(/b/g, "").split(".").map((x) => parseInt(x, 10));
|
|
2429
|
+
while (parts.length < 4) {
|
|
2430
|
+
parts.push(0);
|
|
2431
|
+
}
|
|
2432
|
+
return new VexFirmwareVersion(parts[0], parts[1], parts[2], parts[3]);
|
|
2433
|
+
}
|
|
2434
|
+
static fromUint8Array(data, offset = 0, reverse = false) {
|
|
2435
|
+
return new VexFirmwareVersion(data[offset + (reverse ? 3 : 0)], data[offset + (reverse ? 2 : 1)], data[offset + (reverse ? 1 : 2)], data[offset + (reverse ? 0 : 3)]);
|
|
2436
|
+
}
|
|
2437
|
+
static allZero() {
|
|
2438
|
+
return new VexFirmwareVersion(0, 0, 0, 0);
|
|
2439
|
+
}
|
|
2440
|
+
static fromCatalogString(version) {
|
|
2441
|
+
return VexFirmwareVersion.fromString(version.replace(/_/g, "."));
|
|
2442
|
+
}
|
|
2443
|
+
isBeta() {
|
|
2444
|
+
return this.beta !== 0;
|
|
2445
|
+
}
|
|
2446
|
+
toUint8Array(reverse = false) {
|
|
2447
|
+
const data = new Uint8Array(4);
|
|
2448
|
+
data[reverse ? 3 : 0] = this.major;
|
|
2449
|
+
data[reverse ? 2 : 1] = this.minor;
|
|
2450
|
+
data[reverse ? 1 : 2] = this.build;
|
|
2451
|
+
data[reverse ? 0 : 3] = this.beta;
|
|
2452
|
+
return data;
|
|
2453
|
+
}
|
|
2454
|
+
toUserString() {
|
|
2455
|
+
return `${this.major}.${this.minor}.${this.build}`;
|
|
2456
|
+
}
|
|
2457
|
+
toInternalString() {
|
|
2458
|
+
return `${this.toUserString()}.b${this.beta}`;
|
|
2459
|
+
}
|
|
2460
|
+
compare(that) {
|
|
2461
|
+
const majorComp = this.major - that.major;
|
|
2462
|
+
const minorComp = this.minor - that.minor;
|
|
2463
|
+
const buildComp = this.build - that.build;
|
|
2464
|
+
const betaComp = this.beta - that.beta;
|
|
2465
|
+
if (majorComp !== 0) {
|
|
2466
|
+
return majorComp;
|
|
2467
|
+
} else if (minorComp !== 0) {
|
|
2468
|
+
return minorComp;
|
|
2469
|
+
} else if (buildComp !== 0) {
|
|
2470
|
+
return buildComp;
|
|
2471
|
+
} else if (betaComp !== 0) {
|
|
2472
|
+
return betaComp;
|
|
2473
|
+
}
|
|
2474
|
+
return 0;
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
// ../serial/src/VexPacketView.ts
|
|
2479
|
+
class PacketView extends DataView {
|
|
2480
|
+
position = 0;
|
|
2481
|
+
littleEndianDefault = true;
|
|
2482
|
+
constructor(buffer, offset = 0, length = buffer.byteLength - offset) {
|
|
2483
|
+
super(buffer, offset, length);
|
|
2484
|
+
}
|
|
2485
|
+
static fromPacket(packet) {
|
|
2486
|
+
const view = new PacketView(packet.data.buffer, packet.data.byteOffset);
|
|
2487
|
+
view.position = packet.ackIndex + 1;
|
|
2488
|
+
return view;
|
|
2489
|
+
}
|
|
2490
|
+
nextInt8() {
|
|
2491
|
+
const result = this.getInt8(this.position);
|
|
2492
|
+
this.position += 1;
|
|
2493
|
+
return result;
|
|
2494
|
+
}
|
|
2495
|
+
nextUint8() {
|
|
2496
|
+
const result = this.getUint8(this.position);
|
|
2497
|
+
this.position += 1;
|
|
2498
|
+
return result;
|
|
2499
|
+
}
|
|
2500
|
+
nextInt16(littleEndian = this.littleEndianDefault) {
|
|
2501
|
+
const result = this.getInt16(this.position, littleEndian);
|
|
2502
|
+
this.position += 2;
|
|
2503
|
+
return result;
|
|
2504
|
+
}
|
|
2505
|
+
nextUint16(littleEndian = this.littleEndianDefault) {
|
|
2506
|
+
const result = this.getUint16(this.position, littleEndian);
|
|
2507
|
+
this.position += 2;
|
|
2508
|
+
return result;
|
|
2509
|
+
}
|
|
2510
|
+
nextInt32(littleEndian = this.littleEndianDefault) {
|
|
2511
|
+
const result = this.getInt32(this.position, littleEndian);
|
|
2512
|
+
this.position += 4;
|
|
2513
|
+
return result;
|
|
2514
|
+
}
|
|
2515
|
+
nextUint32(littleEndian = this.littleEndianDefault) {
|
|
2516
|
+
const result = this.getUint32(this.position, littleEndian);
|
|
2517
|
+
this.position += 4;
|
|
2518
|
+
return result;
|
|
2519
|
+
}
|
|
2520
|
+
nextString(length) {
|
|
2521
|
+
let result = "";
|
|
2522
|
+
for (let i = 0;i < length; i++) {
|
|
2523
|
+
result += String.fromCharCode(this.nextUint8());
|
|
2524
|
+
}
|
|
2525
|
+
return result;
|
|
2526
|
+
}
|
|
2527
|
+
nextNTBS(length) {
|
|
2528
|
+
let result = "";
|
|
2529
|
+
const lastPosition = this.position;
|
|
2530
|
+
for (let i = 0;i < length; i++) {
|
|
2531
|
+
if (this.byteLength <= this.position)
|
|
2532
|
+
break;
|
|
2533
|
+
const g = this.nextUint8();
|
|
2534
|
+
if (g === 0)
|
|
2535
|
+
break;
|
|
2536
|
+
result += String.fromCharCode(g);
|
|
2537
|
+
}
|
|
2538
|
+
this.position = lastPosition + length;
|
|
2539
|
+
return result;
|
|
2540
|
+
}
|
|
2541
|
+
nextVarNTBS(length) {
|
|
2542
|
+
let result = "";
|
|
2543
|
+
for (let i = 0;i < length; i++) {
|
|
2544
|
+
if (this.byteLength <= this.position)
|
|
2545
|
+
break;
|
|
2546
|
+
const g = this.nextUint8();
|
|
2547
|
+
if (g === 0)
|
|
2548
|
+
break;
|
|
2549
|
+
result += String.fromCharCode(g);
|
|
2550
|
+
}
|
|
2551
|
+
return result;
|
|
2552
|
+
}
|
|
2553
|
+
nextVersion(reverse = false) {
|
|
2554
|
+
const result = VexFirmwareVersion.fromUint8Array(new Uint8Array(this.buffer), this.position, reverse);
|
|
2555
|
+
this.position += 4;
|
|
2556
|
+
return result;
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
|
|
2560
|
+
// ../serial/src/VexCRC.ts
|
|
2561
|
+
var CRC16TABLE = [
|
|
2562
|
+
0,
|
|
2563
|
+
4129,
|
|
2564
|
+
8258,
|
|
2565
|
+
12387,
|
|
2566
|
+
16516,
|
|
2567
|
+
20645,
|
|
2568
|
+
24774,
|
|
2569
|
+
28903,
|
|
2570
|
+
33032,
|
|
2571
|
+
37161,
|
|
2572
|
+
41290,
|
|
2573
|
+
45419,
|
|
2574
|
+
49548,
|
|
2575
|
+
53677,
|
|
2576
|
+
57806,
|
|
2577
|
+
61935,
|
|
2578
|
+
4657,
|
|
2579
|
+
528,
|
|
2580
|
+
12915,
|
|
2581
|
+
8786,
|
|
2582
|
+
21173,
|
|
2583
|
+
17044,
|
|
2584
|
+
29431,
|
|
2585
|
+
25302,
|
|
2586
|
+
37689,
|
|
2587
|
+
33560,
|
|
2588
|
+
45947,
|
|
2589
|
+
41818,
|
|
2590
|
+
54205,
|
|
2591
|
+
50076,
|
|
2592
|
+
62463,
|
|
2593
|
+
58334,
|
|
2594
|
+
9314,
|
|
2595
|
+
13379,
|
|
2596
|
+
1056,
|
|
2597
|
+
5121,
|
|
2598
|
+
25830,
|
|
2599
|
+
29895,
|
|
2600
|
+
17572,
|
|
2601
|
+
21637,
|
|
2602
|
+
42346,
|
|
2603
|
+
46411,
|
|
2604
|
+
34088,
|
|
2605
|
+
38153,
|
|
2606
|
+
58862,
|
|
2607
|
+
62927,
|
|
2608
|
+
50604,
|
|
2609
|
+
54669,
|
|
2610
|
+
13907,
|
|
2611
|
+
9842,
|
|
2612
|
+
5649,
|
|
2613
|
+
1584,
|
|
2614
|
+
30423,
|
|
2615
|
+
26358,
|
|
2616
|
+
22165,
|
|
2617
|
+
18100,
|
|
2618
|
+
46939,
|
|
2619
|
+
42874,
|
|
2620
|
+
38681,
|
|
2621
|
+
34616,
|
|
2622
|
+
63455,
|
|
2623
|
+
59390,
|
|
2624
|
+
55197,
|
|
2625
|
+
51132,
|
|
2626
|
+
18628,
|
|
2627
|
+
22757,
|
|
2628
|
+
26758,
|
|
2629
|
+
30887,
|
|
2630
|
+
2112,
|
|
2631
|
+
6241,
|
|
2632
|
+
10242,
|
|
2633
|
+
14371,
|
|
2634
|
+
51660,
|
|
2635
|
+
55789,
|
|
2636
|
+
59790,
|
|
2637
|
+
63919,
|
|
2638
|
+
35144,
|
|
2639
|
+
39273,
|
|
2640
|
+
43274,
|
|
2641
|
+
47403,
|
|
2642
|
+
23285,
|
|
2643
|
+
19156,
|
|
2644
|
+
31415,
|
|
2645
|
+
27286,
|
|
2646
|
+
6769,
|
|
2647
|
+
2640,
|
|
2648
|
+
14899,
|
|
2649
|
+
10770,
|
|
2650
|
+
56317,
|
|
2651
|
+
52188,
|
|
2652
|
+
64447,
|
|
2653
|
+
60318,
|
|
2654
|
+
39801,
|
|
2655
|
+
35672,
|
|
2656
|
+
47931,
|
|
2657
|
+
43802,
|
|
2658
|
+
27814,
|
|
2659
|
+
31879,
|
|
2660
|
+
19684,
|
|
2661
|
+
23749,
|
|
2662
|
+
11298,
|
|
2663
|
+
15363,
|
|
2664
|
+
3168,
|
|
2665
|
+
7233,
|
|
2666
|
+
60846,
|
|
2667
|
+
64911,
|
|
2668
|
+
52716,
|
|
2669
|
+
56781,
|
|
2670
|
+
44330,
|
|
2671
|
+
48395,
|
|
2672
|
+
36200,
|
|
2673
|
+
40265,
|
|
2674
|
+
32407,
|
|
2675
|
+
28342,
|
|
2676
|
+
24277,
|
|
2677
|
+
20212,
|
|
2678
|
+
15891,
|
|
2679
|
+
11826,
|
|
2680
|
+
7761,
|
|
2681
|
+
3696,
|
|
2682
|
+
65439,
|
|
2683
|
+
61374,
|
|
2684
|
+
57309,
|
|
2685
|
+
53244,
|
|
2686
|
+
48923,
|
|
2687
|
+
44858,
|
|
2688
|
+
40793,
|
|
2689
|
+
36728,
|
|
2690
|
+
37256,
|
|
2691
|
+
33193,
|
|
2692
|
+
45514,
|
|
2693
|
+
41451,
|
|
2694
|
+
53516,
|
|
2695
|
+
49453,
|
|
2696
|
+
61774,
|
|
2697
|
+
57711,
|
|
2698
|
+
4224,
|
|
2699
|
+
161,
|
|
2700
|
+
12482,
|
|
2701
|
+
8419,
|
|
2702
|
+
20484,
|
|
2703
|
+
16421,
|
|
2704
|
+
28742,
|
|
2705
|
+
24679,
|
|
2706
|
+
33721,
|
|
2707
|
+
37784,
|
|
2708
|
+
41979,
|
|
2709
|
+
46042,
|
|
2710
|
+
49981,
|
|
2711
|
+
54044,
|
|
2712
|
+
58239,
|
|
2713
|
+
62302,
|
|
2714
|
+
689,
|
|
2715
|
+
4752,
|
|
2716
|
+
8947,
|
|
2717
|
+
13010,
|
|
2718
|
+
16949,
|
|
2719
|
+
21012,
|
|
2720
|
+
25207,
|
|
2721
|
+
29270,
|
|
2722
|
+
46570,
|
|
2723
|
+
42443,
|
|
2724
|
+
38312,
|
|
2725
|
+
34185,
|
|
2726
|
+
62830,
|
|
2727
|
+
58703,
|
|
2728
|
+
54572,
|
|
2729
|
+
50445,
|
|
2730
|
+
13538,
|
|
2731
|
+
9411,
|
|
2732
|
+
5280,
|
|
2733
|
+
1153,
|
|
2734
|
+
29798,
|
|
2735
|
+
25671,
|
|
2736
|
+
21540,
|
|
2737
|
+
17413,
|
|
2738
|
+
42971,
|
|
2739
|
+
47098,
|
|
2740
|
+
34713,
|
|
2741
|
+
38840,
|
|
2742
|
+
59231,
|
|
2743
|
+
63358,
|
|
2744
|
+
50973,
|
|
2745
|
+
55100,
|
|
2746
|
+
9939,
|
|
2747
|
+
14066,
|
|
2748
|
+
1681,
|
|
2749
|
+
5808,
|
|
2750
|
+
26199,
|
|
2751
|
+
30326,
|
|
2752
|
+
17941,
|
|
2753
|
+
22068,
|
|
2754
|
+
55628,
|
|
2755
|
+
51565,
|
|
2756
|
+
63758,
|
|
2757
|
+
59695,
|
|
2758
|
+
39368,
|
|
2759
|
+
35305,
|
|
2760
|
+
47498,
|
|
2761
|
+
43435,
|
|
2762
|
+
22596,
|
|
2763
|
+
18533,
|
|
2764
|
+
30726,
|
|
2765
|
+
26663,
|
|
2766
|
+
6336,
|
|
2767
|
+
2273,
|
|
2768
|
+
14466,
|
|
2769
|
+
10403,
|
|
2770
|
+
52093,
|
|
2771
|
+
56156,
|
|
2772
|
+
60223,
|
|
2773
|
+
64286,
|
|
2774
|
+
35833,
|
|
2775
|
+
39896,
|
|
2776
|
+
43963,
|
|
2777
|
+
48026,
|
|
2778
|
+
19061,
|
|
2779
|
+
23124,
|
|
2780
|
+
27191,
|
|
2781
|
+
31254,
|
|
2782
|
+
2801,
|
|
2783
|
+
6864,
|
|
2784
|
+
10931,
|
|
2785
|
+
14994,
|
|
2786
|
+
64814,
|
|
2787
|
+
60687,
|
|
2788
|
+
56684,
|
|
2789
|
+
52557,
|
|
2790
|
+
48554,
|
|
2791
|
+
44427,
|
|
2792
|
+
40424,
|
|
2793
|
+
36297,
|
|
2794
|
+
31782,
|
|
2795
|
+
27655,
|
|
2796
|
+
23652,
|
|
2797
|
+
19525,
|
|
2798
|
+
15522,
|
|
2799
|
+
11395,
|
|
2800
|
+
7392,
|
|
2801
|
+
3265,
|
|
2802
|
+
61215,
|
|
2803
|
+
65342,
|
|
2804
|
+
53085,
|
|
2805
|
+
57212,
|
|
2806
|
+
44955,
|
|
2807
|
+
49082,
|
|
2808
|
+
36825,
|
|
2809
|
+
40952,
|
|
2810
|
+
28183,
|
|
2811
|
+
32310,
|
|
2812
|
+
20053,
|
|
2813
|
+
24180,
|
|
2814
|
+
11923,
|
|
2815
|
+
16050,
|
|
2816
|
+
3793,
|
|
2817
|
+
7920
|
|
2818
|
+
];
|
|
2819
|
+
|
|
2820
|
+
class CrcGenerator {
|
|
2821
|
+
crc16Table;
|
|
2822
|
+
crc32Table;
|
|
2823
|
+
static POLYNOMIAL_CRC32 = 79764919;
|
|
2824
|
+
static POLYNOMIAL_CRC16 = 4129;
|
|
2825
|
+
constructor() {
|
|
2826
|
+
this.crc32Table = new Uint32Array(256);
|
|
2827
|
+
this.crc32GenTable();
|
|
2828
|
+
}
|
|
2829
|
+
crc16(buf, initValue) {
|
|
2830
|
+
const numberOfBytes = buf.byteLength;
|
|
2831
|
+
let accumulator = initValue;
|
|
2832
|
+
let i;
|
|
2833
|
+
let j;
|
|
2834
|
+
for (j = 0;j < numberOfBytes; j++) {
|
|
2835
|
+
i = (accumulator >>> 8 ^ buf[j]) & 255;
|
|
2836
|
+
accumulator = (accumulator << 8 ^ CRC16TABLE[i]) >>> 0;
|
|
2837
|
+
}
|
|
2838
|
+
return (accumulator & 65535) >>> 0;
|
|
2839
|
+
}
|
|
2840
|
+
crc32GenTable() {
|
|
2841
|
+
let i;
|
|
2842
|
+
let j;
|
|
2843
|
+
let crcAccumulator;
|
|
2844
|
+
for (i = 0;i < 256; i++) {
|
|
2845
|
+
crcAccumulator = i << 24;
|
|
2846
|
+
for (j = 0;j < 8; j++) {
|
|
2847
|
+
if ((crcAccumulator & 2147483648) !== 0)
|
|
2848
|
+
crcAccumulator = crcAccumulator << 1 ^ CrcGenerator.POLYNOMIAL_CRC32;
|
|
2849
|
+
else
|
|
2850
|
+
crcAccumulator = crcAccumulator << 1;
|
|
2851
|
+
}
|
|
2852
|
+
this.crc32Table[i] = crcAccumulator;
|
|
2853
|
+
}
|
|
2854
|
+
}
|
|
2855
|
+
crc32(buf, initValue) {
|
|
2856
|
+
const numberOfBytes = buf.byteLength;
|
|
2857
|
+
let crcAccumulator = initValue;
|
|
2858
|
+
let i;
|
|
2859
|
+
let j;
|
|
2860
|
+
for (j = 0;j < numberOfBytes; j++) {
|
|
2861
|
+
i = (crcAccumulator >>> 24 ^ buf[j]) & 255;
|
|
2862
|
+
crcAccumulator = (crcAccumulator << 8 ^ this.crc32Table[i]) >>> 0;
|
|
2863
|
+
}
|
|
2864
|
+
return (crcAccumulator & 4294967295) >>> 0;
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2868
|
+
// ../serial/src/VexPacket.ts
|
|
2869
|
+
class PacketEncoder {
|
|
2870
|
+
static HEADERS_LENGTH = 4;
|
|
2871
|
+
static HEADER_TO_DEVICE = [201, 54, 184, 71];
|
|
2872
|
+
static HEADER_TO_HOST = [170, 85];
|
|
2873
|
+
static J2000_EPOCH = 946684800;
|
|
2874
|
+
vexVersion;
|
|
2875
|
+
crcgen;
|
|
2876
|
+
allPacketsTable = {};
|
|
2877
|
+
static getInstance() {
|
|
2878
|
+
if (Packet.ENCODER === undefined) {
|
|
2879
|
+
Packet.ENCODER = new PacketEncoder;
|
|
2880
|
+
}
|
|
2881
|
+
return Packet.ENCODER;
|
|
2882
|
+
}
|
|
2883
|
+
constructor() {
|
|
2884
|
+
this.vexVersion = 0;
|
|
2885
|
+
this.crcgen = new CrcGenerator;
|
|
2886
|
+
Object.values(exports_VexPacket).forEach((packet) => {
|
|
2887
|
+
if (packet.prototype instanceof HostBoundPacket) {
|
|
2888
|
+
this.allPacketsTable[packet.COMMAND_ID + " " + packet.COMMAND_EXTENDED_ID] = packet;
|
|
2889
|
+
}
|
|
2890
|
+
});
|
|
2891
|
+
}
|
|
2892
|
+
createHeader(buf) {
|
|
2893
|
+
if (buf === undefined || buf.byteLength < PacketEncoder.HEADERS_LENGTH) {
|
|
2894
|
+
buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH);
|
|
2895
|
+
}
|
|
2896
|
+
const h = new Uint8Array(buf);
|
|
2897
|
+
h.set(PacketEncoder.HEADER_TO_DEVICE);
|
|
2898
|
+
return h;
|
|
2899
|
+
}
|
|
2900
|
+
cdcCommand(cmd) {
|
|
2901
|
+
const buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH + 1);
|
|
2902
|
+
const h = this.createHeader(buf);
|
|
2903
|
+
h.set([cmd], PacketEncoder.HEADERS_LENGTH);
|
|
2904
|
+
return h;
|
|
2905
|
+
}
|
|
2906
|
+
cdcCommandWithData(cmd, data) {
|
|
2907
|
+
const buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH + 2 + data.length);
|
|
2908
|
+
const h = this.createHeader(buf);
|
|
2909
|
+
h.set([cmd, data.length], PacketEncoder.HEADERS_LENGTH);
|
|
2910
|
+
h.set(data, PacketEncoder.HEADERS_LENGTH + 2);
|
|
2911
|
+
return h;
|
|
2912
|
+
}
|
|
2913
|
+
cdc2Command(cmd, ext) {
|
|
2914
|
+
const buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH + 5);
|
|
2915
|
+
const h = this.createHeader(buf);
|
|
2916
|
+
h.set([cmd, ext, 0], PacketEncoder.HEADERS_LENGTH);
|
|
2917
|
+
const crc = this.crcgen.crc16(h.subarray(0, buf.byteLength - 2), 0) >>> 0;
|
|
2918
|
+
h.set([crc >>> 8, crc & 255], buf.byteLength - 2);
|
|
2919
|
+
return h;
|
|
2920
|
+
}
|
|
2921
|
+
cdc2CommandBufferLength(data) {
|
|
2922
|
+
let length = PacketEncoder.HEADERS_LENGTH + data.length + 3 + 2;
|
|
2923
|
+
if (data.length > 127)
|
|
2924
|
+
length += 1;
|
|
2925
|
+
return length;
|
|
2926
|
+
}
|
|
2927
|
+
cdc2CommandWithData(cmd, ext, data) {
|
|
2928
|
+
const buf = new ArrayBuffer(this.cdc2CommandBufferLength(data));
|
|
2929
|
+
const h = this.createHeader(buf);
|
|
2930
|
+
if (data.length < 128) {
|
|
2931
|
+
h.set([cmd, ext, data.length], PacketEncoder.HEADERS_LENGTH);
|
|
2932
|
+
h.set(data, PacketEncoder.HEADERS_LENGTH + 3);
|
|
2933
|
+
} else {
|
|
2934
|
+
const lengthMsb = (data.length >>> 8 | 128) >>> 0;
|
|
2935
|
+
const lengthLsb = (data.length & 255) >>> 0;
|
|
2936
|
+
h.set([cmd, ext, lengthMsb, lengthLsb], PacketEncoder.HEADERS_LENGTH);
|
|
2937
|
+
h.set(data, PacketEncoder.HEADERS_LENGTH + 4);
|
|
2938
|
+
}
|
|
2939
|
+
const crc = this.crcgen.crc16(h.subarray(0, buf.byteLength - 2), 0);
|
|
2940
|
+
h.set([crc >>> 8, crc & 255], buf.byteLength - 2);
|
|
2941
|
+
return h;
|
|
2942
|
+
}
|
|
2943
|
+
validateHeader(data) {
|
|
2944
|
+
return !(data[0] !== PacketEncoder.HEADER_TO_HOST[0] || data[1] !== PacketEncoder.HEADER_TO_HOST[1]);
|
|
2945
|
+
}
|
|
2946
|
+
validateMessageCdc(data) {
|
|
2947
|
+
const message = data.subarray(0, data.byteLength - 2);
|
|
2948
|
+
const lastTwoBytes = (data[data.byteLength - 2] << 8) + data[data.byteLength - 1];
|
|
2949
|
+
return this.crcgen.crc16(message, 0) === lastTwoBytes;
|
|
2950
|
+
}
|
|
2951
|
+
getPayloadSize(data) {
|
|
2952
|
+
let t = 0;
|
|
2953
|
+
let a = data[3];
|
|
2954
|
+
if ((128 & a) !== 0) {
|
|
2955
|
+
t = 127 & a;
|
|
2956
|
+
a = data[4];
|
|
2957
|
+
}
|
|
2958
|
+
return (t << 8) + a;
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
|
|
2962
|
+
class Packet {
|
|
2963
|
+
data;
|
|
2964
|
+
static ENCODER;
|
|
2965
|
+
constructor(rawData) {
|
|
2966
|
+
this.data = rawData instanceof ArrayBuffer ? new Uint8Array(rawData) : rawData;
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
|
|
2970
|
+
class DeviceBoundPacket extends Packet {
|
|
2971
|
+
constructor(payload) {
|
|
2972
|
+
super(new Uint8Array);
|
|
2973
|
+
const me = this.__proto__.constructor;
|
|
2974
|
+
if (me.COMMAND_EXTENDED_ID === undefined) {
|
|
2975
|
+
if (payload === undefined) {
|
|
2976
|
+
this.data = Packet.ENCODER.cdcCommand(me.COMMAND_ID);
|
|
2977
|
+
} else {
|
|
2978
|
+
this.data = Packet.ENCODER.cdcCommandWithData(me.COMMAND_ID, payload);
|
|
2979
|
+
}
|
|
2980
|
+
} else {
|
|
2981
|
+
if (payload === undefined) {
|
|
2982
|
+
this.data = Packet.ENCODER.cdc2Command(me.COMMAND_ID, me.COMMAND_EXTENDED_ID);
|
|
2983
|
+
} else {
|
|
2984
|
+
this.data = Packet.ENCODER.cdc2CommandWithData(me.COMMAND_ID, me.COMMAND_EXTENDED_ID, payload);
|
|
2985
|
+
}
|
|
2986
|
+
}
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
|
|
2990
|
+
class Query1H2DPacket extends DeviceBoundPacket {
|
|
2991
|
+
static COMMAND_ID = 33;
|
|
2992
|
+
static COMMAND_EXTENDED_ID = undefined;
|
|
2993
|
+
constructor() {
|
|
2994
|
+
super(undefined);
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
|
|
2998
|
+
class SystemVersionH2DPacket extends DeviceBoundPacket {
|
|
2999
|
+
static COMMAND_ID = 164;
|
|
3000
|
+
static COMMAND_EXTENDED_ID = undefined;
|
|
3001
|
+
constructor() {
|
|
3002
|
+
super(undefined);
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
3005
|
+
|
|
3006
|
+
class UpdateMatchModeH2DPacket extends DeviceBoundPacket {
|
|
3007
|
+
static COMMAND_ID = 88;
|
|
3008
|
+
static COMMAND_EXTENDED_ID = 193;
|
|
3009
|
+
constructor(mode, matchClock) {
|
|
3010
|
+
let bit1;
|
|
3011
|
+
switch (mode) {
|
|
3012
|
+
case "autonomous":
|
|
3013
|
+
bit1 = 10;
|
|
3014
|
+
break;
|
|
3015
|
+
case "driver":
|
|
3016
|
+
bit1 = 8;
|
|
3017
|
+
break;
|
|
3018
|
+
case "disabled":
|
|
3019
|
+
bit1 = 11;
|
|
3020
|
+
}
|
|
3021
|
+
const payload = new Uint8Array(5);
|
|
3022
|
+
const view = new DataView(payload.buffer);
|
|
3023
|
+
payload[0] = (15 & bit1) >>> 0;
|
|
3024
|
+
view.setUint32(1, matchClock, true);
|
|
3025
|
+
super(payload);
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
|
|
3029
|
+
class GetMatchStatusH2DPacket extends DeviceBoundPacket {
|
|
3030
|
+
static COMMAND_ID = 88;
|
|
3031
|
+
static COMMAND_EXTENDED_ID = 194;
|
|
3032
|
+
constructor() {
|
|
3033
|
+
super(undefined);
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
|
|
3037
|
+
class GetRadioModeH2DPacket extends DeviceBoundPacket {
|
|
3038
|
+
static COMMAND_ID = 88;
|
|
3039
|
+
static COMMAND_EXTENDED_ID = 65;
|
|
3040
|
+
constructor(mode) {
|
|
3041
|
+
const payload = new Uint8Array(1);
|
|
3042
|
+
payload[0] = mode;
|
|
3043
|
+
super(payload);
|
|
3044
|
+
}
|
|
3045
|
+
}
|
|
3046
|
+
|
|
3047
|
+
class FileControlH2DPacket extends DeviceBoundPacket {
|
|
3048
|
+
static COMMAND_ID = 86;
|
|
3049
|
+
static COMMAND_EXTENDED_ID = 16;
|
|
3050
|
+
constructor(a, b) {
|
|
3051
|
+
const payload = new Uint8Array(2);
|
|
3052
|
+
payload.set([a, b], 0);
|
|
3053
|
+
super(payload);
|
|
3054
|
+
}
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
class InitFileTransferH2DPacket extends DeviceBoundPacket {
|
|
3058
|
+
static COMMAND_ID = 86;
|
|
3059
|
+
static COMMAND_EXTENDED_ID = 17;
|
|
3060
|
+
constructor(operation, target, vendor, options, binary, addr, name, type, version = new VexFirmwareVersion(1, 0, 0, 0)) {
|
|
3061
|
+
const payload = new Uint8Array(52);
|
|
3062
|
+
const view = new DataView(payload.buffer);
|
|
3063
|
+
view.setUint8(0, operation);
|
|
3064
|
+
view.setUint8(1, target);
|
|
3065
|
+
view.setUint8(2, vendor);
|
|
3066
|
+
view.setUint8(3, options);
|
|
3067
|
+
view.setUint32(4, binary.length, true);
|
|
3068
|
+
view.setUint32(8, addr, true);
|
|
3069
|
+
view.setUint32(12, operation === 1 /* WRITE */ ? Packet.ENCODER.crcgen.crc32(binary, 0) : 0, true);
|
|
3070
|
+
const re = /(?:\.([^.]+))?$/;
|
|
3071
|
+
const reResult = re.exec(name);
|
|
3072
|
+
let ext = reResult != null ? reResult[1] : undefined;
|
|
3073
|
+
ext ??= "";
|
|
3074
|
+
ext = ext === "gz" ? "bin" : ext;
|
|
3075
|
+
payload.set(new TextEncoder().encode(type ?? ext), 16);
|
|
3076
|
+
const timestamp = (Date.now() / 1000 >>> 0) - PacketEncoder.J2000_EPOCH;
|
|
3077
|
+
view.setUint32(20, timestamp, true);
|
|
3078
|
+
payload.set(version.toUint8Array(), 24);
|
|
3079
|
+
const nameEncoded = new TextEncoder().encode(name);
|
|
3080
|
+
let offset = nameEncoded.length - 23;
|
|
3081
|
+
if (offset < 0)
|
|
3082
|
+
offset = 0;
|
|
3083
|
+
payload.set(nameEncoded.subarray(offset, offset + 23), 28);
|
|
3084
|
+
view.setUint8(51, 0);
|
|
3085
|
+
super(payload);
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
class ExitFileTransferH2DPacket extends DeviceBoundPacket {
|
|
3090
|
+
static COMMAND_ID = 86;
|
|
3091
|
+
static COMMAND_EXTENDED_ID = 18;
|
|
3092
|
+
constructor(action) {
|
|
3093
|
+
const payload = new Uint8Array(1);
|
|
3094
|
+
payload[0] = action;
|
|
3095
|
+
super(payload);
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
|
|
3099
|
+
class WriteFileH2DPacket extends DeviceBoundPacket {
|
|
3100
|
+
static COMMAND_ID = 86;
|
|
3101
|
+
static COMMAND_EXTENDED_ID = 19;
|
|
3102
|
+
constructor(addr, buf) {
|
|
3103
|
+
const payload = new Uint8Array(4 + buf.length);
|
|
3104
|
+
const view = new DataView(payload.buffer);
|
|
3105
|
+
view.setUint32(0, addr, true);
|
|
3106
|
+
payload.set(buf, 4);
|
|
3107
|
+
super(payload);
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3111
|
+
class ReadFileH2DPacket extends DeviceBoundPacket {
|
|
3112
|
+
static COMMAND_ID = 86;
|
|
3113
|
+
static COMMAND_EXTENDED_ID = 20;
|
|
3114
|
+
constructor(addr, size) {
|
|
3115
|
+
const payload = new Uint8Array(6);
|
|
3116
|
+
const view = new DataView(payload.buffer);
|
|
3117
|
+
view.setUint32(0, addr, true);
|
|
3118
|
+
view.setUint16(4, size, true);
|
|
3119
|
+
super(payload);
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3122
|
+
|
|
3123
|
+
class LinkFileH2DPacket extends DeviceBoundPacket {
|
|
3124
|
+
static COMMAND_ID = 86;
|
|
3125
|
+
static COMMAND_EXTENDED_ID = 21;
|
|
3126
|
+
constructor(vendor, fileName, options) {
|
|
3127
|
+
const str = new TextEncoder().encode(fileName);
|
|
3128
|
+
const payload = new Uint8Array(26);
|
|
3129
|
+
payload.set([vendor, options], 0);
|
|
3130
|
+
payload.set(str.subarray(0, 23), 2);
|
|
3131
|
+
super(payload);
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3134
|
+
|
|
3135
|
+
class GetDirectoryFileCountH2DPacket extends DeviceBoundPacket {
|
|
3136
|
+
static COMMAND_ID = 86;
|
|
3137
|
+
static COMMAND_EXTENDED_ID = 22;
|
|
3138
|
+
constructor(vendor) {
|
|
3139
|
+
const payload = new Uint8Array(2);
|
|
3140
|
+
payload.set([vendor, 0], 0);
|
|
3141
|
+
super(payload);
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
|
|
3145
|
+
class GetDirectoryEntryH2DPacket extends DeviceBoundPacket {
|
|
3146
|
+
static COMMAND_ID = 86;
|
|
3147
|
+
static COMMAND_EXTENDED_ID = 23;
|
|
3148
|
+
constructor(index) {
|
|
3149
|
+
const payload = new Uint8Array(2);
|
|
3150
|
+
payload.set([index, 0], 0);
|
|
3151
|
+
super(payload);
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
|
|
3155
|
+
class LoadFileActionH2DPacket extends DeviceBoundPacket {
|
|
3156
|
+
static COMMAND_ID = 86;
|
|
3157
|
+
static COMMAND_EXTENDED_ID = 24;
|
|
3158
|
+
constructor(vendor, actionId, fileNameOrSlotNumber) {
|
|
3159
|
+
let fileName;
|
|
3160
|
+
if (typeof fileNameOrSlotNumber === "string") {
|
|
3161
|
+
fileName = fileNameOrSlotNumber;
|
|
3162
|
+
} else {
|
|
3163
|
+
fileName = "___s_" + (fileNameOrSlotNumber - 1) + ".bin";
|
|
3164
|
+
}
|
|
3165
|
+
const encodedName = new TextEncoder().encode(fileName);
|
|
3166
|
+
const payload = new Uint8Array(26);
|
|
3167
|
+
payload.set([vendor, actionId], 0);
|
|
3168
|
+
payload.set(encodedName.subarray(0, 23), 2);
|
|
3169
|
+
super(payload);
|
|
3170
|
+
}
|
|
3171
|
+
}
|
|
3172
|
+
|
|
3173
|
+
class GetFileMetadataH2DPacket extends DeviceBoundPacket {
|
|
3174
|
+
static COMMAND_ID = 86;
|
|
3175
|
+
static COMMAND_EXTENDED_ID = 25;
|
|
3176
|
+
constructor(vendor, fileName, options) {
|
|
3177
|
+
const encodedName = new TextEncoder().encode(fileName);
|
|
3178
|
+
const payload = new Uint8Array(26);
|
|
3179
|
+
payload.set([vendor, options], 0);
|
|
3180
|
+
payload.set(encodedName.subarray(0, 23), 2);
|
|
3181
|
+
super(payload);
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
|
|
3185
|
+
class SetFileMetadataH2DPacket extends DeviceBoundPacket {
|
|
3186
|
+
static COMMAND_ID = 86;
|
|
3187
|
+
static COMMAND_EXTENDED_ID = 26;
|
|
3188
|
+
constructor(vendor, fileName, fileInfo, options) {
|
|
3189
|
+
const encodedName = new TextEncoder().encode(fileName);
|
|
3190
|
+
const encodedType = new TextEncoder().encode(fileInfo.type);
|
|
3191
|
+
const payload = new Uint8Array(42);
|
|
3192
|
+
const view = new DataView(payload.buffer);
|
|
3193
|
+
view.setUint8(0, vendor);
|
|
3194
|
+
view.setUint8(1, options);
|
|
3195
|
+
view.setUint32(2, fileInfo.loadAddress, true);
|
|
3196
|
+
payload.set(encodedType.subarray(0, 4), 6);
|
|
3197
|
+
const timestamp = fileInfo.timestamp - PacketEncoder.J2000_EPOCH + 100;
|
|
3198
|
+
view.setUint32(10, timestamp, true);
|
|
3199
|
+
payload.set(fileInfo.version.toUint8Array(), 14);
|
|
3200
|
+
payload.set(encodedName.subarray(0, 23), 18);
|
|
3201
|
+
super(payload);
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
|
|
3205
|
+
class EraseFileH2DPacket extends DeviceBoundPacket {
|
|
3206
|
+
static COMMAND_ID = 86;
|
|
3207
|
+
static COMMAND_EXTENDED_ID = 27;
|
|
3208
|
+
constructor(vendor, fileName) {
|
|
3209
|
+
const encodedName = new TextEncoder().encode(fileName);
|
|
3210
|
+
const payload = new Uint8Array(26);
|
|
3211
|
+
payload.set([vendor, 128], 0);
|
|
3212
|
+
payload.set(encodedName.subarray(0, 23), 2);
|
|
3213
|
+
super(payload);
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
3216
|
+
|
|
3217
|
+
class GetProgramSlotInfoH2DPacket extends DeviceBoundPacket {
|
|
3218
|
+
static COMMAND_ID = 86;
|
|
3219
|
+
static COMMAND_EXTENDED_ID = 28;
|
|
3220
|
+
constructor(vendor, fileName) {
|
|
3221
|
+
const encodedName = new TextEncoder().encode(fileName);
|
|
3222
|
+
const payload = new Uint8Array(26);
|
|
3223
|
+
payload.set([vendor, 0], 0);
|
|
3224
|
+
payload.set(encodedName.subarray(0, 23), 2);
|
|
3225
|
+
super(payload);
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
|
|
3229
|
+
class FileClearUpH2DPacket extends DeviceBoundPacket {
|
|
3230
|
+
static COMMAND_ID = 86;
|
|
3231
|
+
static COMMAND_EXTENDED_ID = 30;
|
|
3232
|
+
constructor(vendor) {
|
|
3233
|
+
const payload = new Uint8Array(2);
|
|
3234
|
+
payload.set([vendor, 0], 0);
|
|
3235
|
+
super(payload);
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
|
|
3239
|
+
class FileFormatH2DPacket extends DeviceBoundPacket {
|
|
3240
|
+
static COMMAND_ID = 86;
|
|
3241
|
+
static COMMAND_EXTENDED_ID = 31;
|
|
3242
|
+
constructor() {
|
|
3243
|
+
const payload = new Uint8Array(4);
|
|
3244
|
+
payload.set([68, 67, 66, 65], 0);
|
|
3245
|
+
super(payload);
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
|
|
3249
|
+
class GetSystemFlagsH2DPacket extends DeviceBoundPacket {
|
|
3250
|
+
static COMMAND_ID = 86;
|
|
3251
|
+
static COMMAND_EXTENDED_ID = 32;
|
|
3252
|
+
}
|
|
3253
|
+
|
|
3254
|
+
class GetDeviceStatusH2DPacket extends DeviceBoundPacket {
|
|
3255
|
+
static COMMAND_ID = 86;
|
|
3256
|
+
static COMMAND_EXTENDED_ID = 33;
|
|
3257
|
+
constructor() {
|
|
3258
|
+
super(undefined);
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
|
|
3262
|
+
class GetSystemStatusH2DPacket extends DeviceBoundPacket {
|
|
3263
|
+
static COMMAND_ID = 86;
|
|
3264
|
+
static COMMAND_EXTENDED_ID = 34;
|
|
3265
|
+
constructor() {
|
|
3266
|
+
super(undefined);
|
|
3267
|
+
}
|
|
3268
|
+
}
|
|
3269
|
+
|
|
3270
|
+
class GetFdtStatusH2DPacket extends DeviceBoundPacket {
|
|
3271
|
+
static COMMAND_ID = 86;
|
|
3272
|
+
static COMMAND_EXTENDED_ID = 35;
|
|
3273
|
+
constructor() {
|
|
3274
|
+
super(undefined);
|
|
3275
|
+
}
|
|
3276
|
+
}
|
|
3277
|
+
|
|
3278
|
+
class GetLogCountH2DPacket extends DeviceBoundPacket {
|
|
3279
|
+
static COMMAND_ID = 86;
|
|
3280
|
+
static COMMAND_EXTENDED_ID = 36;
|
|
3281
|
+
constructor() {
|
|
3282
|
+
super(undefined);
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
|
|
3286
|
+
class ReadLogPageH2DPacket extends DeviceBoundPacket {
|
|
3287
|
+
static COMMAND_ID = 86;
|
|
3288
|
+
static COMMAND_EXTENDED_ID = 37;
|
|
3289
|
+
constructor(offset, count) {
|
|
3290
|
+
const payload = new Uint8Array(8);
|
|
3291
|
+
const view = new DataView(payload.buffer);
|
|
3292
|
+
view.setUint32(0, offset, true);
|
|
3293
|
+
view.setUint32(4, count, true);
|
|
3294
|
+
super(payload);
|
|
3295
|
+
}
|
|
3296
|
+
}
|
|
3297
|
+
|
|
3298
|
+
class GetRadioStatusH2DPacket extends DeviceBoundPacket {
|
|
3299
|
+
static COMMAND_ID = 86;
|
|
3300
|
+
static COMMAND_EXTENDED_ID = 38;
|
|
3301
|
+
constructor() {
|
|
3302
|
+
super(undefined);
|
|
3303
|
+
}
|
|
3304
|
+
}
|
|
3305
|
+
|
|
3306
|
+
class GetUserDataH2DPacket extends DeviceBoundPacket {
|
|
3307
|
+
static COMMAND_ID = 86;
|
|
3308
|
+
static COMMAND_EXTENDED_ID = 39;
|
|
3309
|
+
constructor(e) {
|
|
3310
|
+
let len = e?.length ?? 0;
|
|
3311
|
+
if (len > 244)
|
|
3312
|
+
len = 244;
|
|
3313
|
+
const payload = new Uint8Array(2 + len);
|
|
3314
|
+
payload[0] = 1;
|
|
3315
|
+
payload[1] = len;
|
|
3316
|
+
payload.set(e ?? new Uint8Array(0), 2);
|
|
3317
|
+
super(payload);
|
|
3318
|
+
}
|
|
3319
|
+
}
|
|
3320
|
+
|
|
3321
|
+
class ScreenCaptureH2DPacket extends DeviceBoundPacket {
|
|
3322
|
+
static COMMAND_ID = 86;
|
|
3323
|
+
static COMMAND_EXTENDED_ID = 40;
|
|
3324
|
+
constructor(e) {
|
|
3325
|
+
const payload = new Uint8Array(1);
|
|
3326
|
+
payload[0] = e;
|
|
3327
|
+
super(payload);
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3330
|
+
|
|
3331
|
+
class SendDashTouchH2DPacket extends DeviceBoundPacket {
|
|
3332
|
+
static COMMAND_ID = 86;
|
|
3333
|
+
static COMMAND_EXTENDED_ID = 42;
|
|
3334
|
+
constructor(x, y, press) {
|
|
3335
|
+
const payload = new Uint8Array(6);
|
|
3336
|
+
const view = new DataView(payload.buffer);
|
|
3337
|
+
view.setUint16(0, x, true);
|
|
3338
|
+
view.setUint16(2, y, true);
|
|
3339
|
+
view.setUint16(4, press ? 1 : 0, true);
|
|
3340
|
+
super(payload);
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
|
|
3344
|
+
class SelectDashH2DPacket extends DeviceBoundPacket {
|
|
3345
|
+
static COMMAND_ID = 86;
|
|
3346
|
+
static COMMAND_EXTENDED_ID = 43;
|
|
3347
|
+
constructor(screen, port) {
|
|
3348
|
+
const payload = new Uint8Array(2);
|
|
3349
|
+
payload[0] = screen;
|
|
3350
|
+
payload[1] = port;
|
|
3351
|
+
super(payload);
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
3354
|
+
|
|
3355
|
+
class EnableDashH2DPacket extends DeviceBoundPacket {
|
|
3356
|
+
static COMMAND_ID = 86;
|
|
3357
|
+
static COMMAND_EXTENDED_ID = 44;
|
|
3358
|
+
constructor(unknown1) {
|
|
3359
|
+
if (unknown1 === undefined) {
|
|
3360
|
+
super(undefined);
|
|
3361
|
+
} else {
|
|
3362
|
+
const payload = new Uint8Array(1);
|
|
3363
|
+
payload[0] = unknown1;
|
|
3364
|
+
super(payload);
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
|
|
3369
|
+
class DisableDashH2DPacket extends DeviceBoundPacket {
|
|
3370
|
+
static COMMAND_ID = 86;
|
|
3371
|
+
static COMMAND_EXTENDED_ID = 45;
|
|
3372
|
+
constructor() {
|
|
3373
|
+
super(undefined);
|
|
3374
|
+
}
|
|
3375
|
+
}
|
|
3376
|
+
|
|
3377
|
+
class ReadKeyValueH2DPacket extends DeviceBoundPacket {
|
|
3378
|
+
static COMMAND_ID = 86;
|
|
3379
|
+
static COMMAND_EXTENDED_ID = 46;
|
|
3380
|
+
constructor(key) {
|
|
3381
|
+
const payload = new Uint8Array(32);
|
|
3382
|
+
payload.set(new TextEncoder().encode(key), 0);
|
|
3383
|
+
super(payload);
|
|
3384
|
+
}
|
|
3385
|
+
}
|
|
3386
|
+
|
|
3387
|
+
class WriteKeyValueH2DPacket extends DeviceBoundPacket {
|
|
3388
|
+
static COMMAND_ID = 86;
|
|
3389
|
+
static COMMAND_EXTENDED_ID = 47;
|
|
3390
|
+
constructor(key, value) {
|
|
3391
|
+
let strk = new TextEncoder().encode(key);
|
|
3392
|
+
const strv = new TextEncoder().encode(value);
|
|
3393
|
+
if (strk.byteLength > 31)
|
|
3394
|
+
strk = strk.subarray(0, 31);
|
|
3395
|
+
const payload = new Uint8Array(strk.length + strv.length + 20);
|
|
3396
|
+
payload.set(strk, 0);
|
|
3397
|
+
payload.set(strv, strk.length + 1);
|
|
3398
|
+
super(payload);
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
|
|
3402
|
+
class GetSlot1to4InfoH2DPacket extends DeviceBoundPacket {
|
|
3403
|
+
static COMMAND_ID = 86;
|
|
3404
|
+
static COMMAND_EXTENDED_ID = 49;
|
|
3405
|
+
constructor() {
|
|
3406
|
+
super(undefined);
|
|
3407
|
+
}
|
|
3408
|
+
}
|
|
3409
|
+
|
|
3410
|
+
class GetSlot5to8InfoH2DPacket extends DeviceBoundPacket {
|
|
3411
|
+
static COMMAND_ID = 86;
|
|
3412
|
+
static COMMAND_EXTENDED_ID = 50;
|
|
3413
|
+
constructor() {
|
|
3414
|
+
super(undefined);
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
|
|
3418
|
+
class FactoryStatusH2DPacket extends DeviceBoundPacket {
|
|
3419
|
+
static COMMAND_ID = 86;
|
|
3420
|
+
static COMMAND_EXTENDED_ID = 241;
|
|
3421
|
+
}
|
|
3422
|
+
|
|
3423
|
+
class FactoryEnableH2DPacket extends DeviceBoundPacket {
|
|
3424
|
+
static COMMAND_ID = 86;
|
|
3425
|
+
static COMMAND_EXTENDED_ID = 255;
|
|
3426
|
+
constructor() {
|
|
3427
|
+
const payload = new Uint8Array(4);
|
|
3428
|
+
payload.set([77, 76, 75, 74], 0);
|
|
3429
|
+
super(payload);
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
|
|
3433
|
+
class HostBoundPacket extends Packet {
|
|
3434
|
+
ack = 255 /* CDC2_NACK */;
|
|
3435
|
+
payloadSize;
|
|
3436
|
+
ackIndex;
|
|
3437
|
+
constructor(data) {
|
|
3438
|
+
super(data);
|
|
3439
|
+
this.payloadSize = Packet.ENCODER.getPayloadSize(this.data);
|
|
3440
|
+
const n = this.payloadSize > 128 ? 5 : 4;
|
|
3441
|
+
this.ack = this.data[this.ackIndex = n + 1];
|
|
3442
|
+
}
|
|
3443
|
+
static isValidPacket(data, n) {
|
|
3444
|
+
const ack = data[n + 1];
|
|
3445
|
+
return ack === 118 /* CDC2_ACK */ || ack === 167;
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3448
|
+
|
|
3449
|
+
class Query1ReplyD2HPacket extends HostBoundPacket {
|
|
3450
|
+
static COMMAND_ID = 33;
|
|
3451
|
+
static COMMAND_EXTENDED_ID = undefined;
|
|
3452
|
+
joystickFlag1;
|
|
3453
|
+
joystickFlag2;
|
|
3454
|
+
brainFlag1;
|
|
3455
|
+
brainFlag2;
|
|
3456
|
+
bootloadFlag1;
|
|
3457
|
+
bootloadFlag2;
|
|
3458
|
+
constructor(data) {
|
|
3459
|
+
super(data);
|
|
3460
|
+
this.joystickFlag1 = this.data[4];
|
|
3461
|
+
this.joystickFlag2 = this.data[5];
|
|
3462
|
+
this.brainFlag1 = this.data[6];
|
|
3463
|
+
this.brainFlag2 = this.data[7];
|
|
3464
|
+
this.bootloadFlag1 = this.data[10];
|
|
3465
|
+
this.bootloadFlag2 = this.data[11];
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3469
|
+
class SystemVersionReplyD2HPacket extends HostBoundPacket {
|
|
3470
|
+
static COMMAND_ID = 164;
|
|
3471
|
+
static COMMAND_EXTENDED_ID = undefined;
|
|
3472
|
+
version;
|
|
3473
|
+
hardware;
|
|
3474
|
+
constructor(data) {
|
|
3475
|
+
super(data);
|
|
3476
|
+
this.version = new VexFirmwareVersion(this.data[4], this.data[5], this.data[6], this.data[8]);
|
|
3477
|
+
this.hardware = this.data[7];
|
|
3478
|
+
}
|
|
3479
|
+
}
|
|
3480
|
+
|
|
3481
|
+
class MatchModeReplyD2HPacket extends HostBoundPacket {
|
|
3482
|
+
static COMMAND_ID = 88;
|
|
3483
|
+
static COMMAND_EXTENDED_ID = 193;
|
|
3484
|
+
modebit;
|
|
3485
|
+
constructor(data) {
|
|
3486
|
+
super(data);
|
|
3487
|
+
const dataView = PacketView.fromPacket(this);
|
|
3488
|
+
this.modebit = dataView.nextUint8();
|
|
3489
|
+
}
|
|
3490
|
+
}
|
|
3491
|
+
|
|
3492
|
+
class MatchStatusReplyD2HPacket extends HostBoundPacket {
|
|
3493
|
+
static COMMAND_ID = 88;
|
|
3494
|
+
static COMMAND_EXTENDED_ID = 194;
|
|
3495
|
+
rssi;
|
|
3496
|
+
systemStatusBits;
|
|
3497
|
+
radioStatusBits;
|
|
3498
|
+
fieldStatusBits;
|
|
3499
|
+
matchClock;
|
|
3500
|
+
brainBatteryPercent;
|
|
3501
|
+
controllerBatteryPercent;
|
|
3502
|
+
partnerControllerBatteryPercent;
|
|
3503
|
+
pad;
|
|
3504
|
+
buttons;
|
|
3505
|
+
activeProgram;
|
|
3506
|
+
radioType;
|
|
3507
|
+
radioChannel;
|
|
3508
|
+
radioSlot;
|
|
3509
|
+
robotName;
|
|
3510
|
+
controllerFlags;
|
|
3511
|
+
rxSignalQuality;
|
|
3512
|
+
constructor(data) {
|
|
3513
|
+
super(data);
|
|
3514
|
+
const dataView = PacketView.fromPacket(this);
|
|
3515
|
+
const n = this.ackIndex;
|
|
3516
|
+
this.rssi = dataView.nextInt8();
|
|
3517
|
+
this.systemStatusBits = dataView.nextUint16();
|
|
3518
|
+
this.radioStatusBits = dataView.nextUint16();
|
|
3519
|
+
this.fieldStatusBits = dataView.nextUint8();
|
|
3520
|
+
this.matchClock = dataView.nextUint8();
|
|
3521
|
+
this.brainBatteryPercent = dataView.nextUint8();
|
|
3522
|
+
this.controllerBatteryPercent = dataView.nextUint8();
|
|
3523
|
+
this.partnerControllerBatteryPercent = dataView.nextUint8();
|
|
3524
|
+
this.pad = dataView.nextUint8();
|
|
3525
|
+
this.buttons = dataView.nextUint16();
|
|
3526
|
+
this.activeProgram = dataView.nextUint8();
|
|
3527
|
+
this.radioType = dataView.nextUint8();
|
|
3528
|
+
this.radioChannel = dataView.nextUint8();
|
|
3529
|
+
this.radioSlot = dataView.nextUint8();
|
|
3530
|
+
this.robotName = dataView.nextNTBS(10);
|
|
3531
|
+
this.controllerFlags = dataView.getUint8(n + 28);
|
|
3532
|
+
this.rxSignalQuality = dataView.getUint8(n + 29);
|
|
3533
|
+
let rawStr = new TextDecoder("UTF-8").decode(data.slice(n + 18, n + this.payloadSize + 28));
|
|
3534
|
+
const endIdx = rawStr.indexOf("\x00");
|
|
3535
|
+
if (endIdx > -1) {
|
|
3536
|
+
rawStr = rawStr.substr(0, endIdx);
|
|
3537
|
+
}
|
|
3538
|
+
this.robotName = rawStr;
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
|
|
3542
|
+
class FileControlReplyD2HPacket extends HostBoundPacket {
|
|
3543
|
+
static COMMAND_ID = 86;
|
|
3544
|
+
static COMMAND_EXTENDED_ID = 16;
|
|
3545
|
+
}
|
|
3546
|
+
|
|
3547
|
+
class InitFileTransferReplyD2HPacket extends HostBoundPacket {
|
|
3548
|
+
static COMMAND_ID = 86;
|
|
3549
|
+
static COMMAND_EXTENDED_ID = 17;
|
|
3550
|
+
windowSize;
|
|
3551
|
+
fileSize;
|
|
3552
|
+
crc32;
|
|
3553
|
+
constructor(data) {
|
|
3554
|
+
super(data);
|
|
3555
|
+
const dataView = PacketView.fromPacket(this);
|
|
3556
|
+
this.windowSize = dataView.nextUint16();
|
|
3557
|
+
this.fileSize = dataView.nextUint32();
|
|
3558
|
+
this.crc32 = dataView.nextUint32();
|
|
3559
|
+
}
|
|
3560
|
+
}
|
|
3561
|
+
|
|
3562
|
+
class ExitFileTransferReplyD2HPacket extends HostBoundPacket {
|
|
3563
|
+
static COMMAND_ID = 86;
|
|
3564
|
+
static COMMAND_EXTENDED_ID = 18;
|
|
3565
|
+
}
|
|
3566
|
+
|
|
3567
|
+
class WriteFileReplyD2HPacket extends HostBoundPacket {
|
|
3568
|
+
static COMMAND_ID = 86;
|
|
3569
|
+
static COMMAND_EXTENDED_ID = 19;
|
|
3570
|
+
}
|
|
3571
|
+
|
|
3572
|
+
class ReadFileReplyD2HPacket extends HostBoundPacket {
|
|
3573
|
+
static COMMAND_ID = 86;
|
|
3574
|
+
static COMMAND_EXTENDED_ID = 20;
|
|
3575
|
+
addr;
|
|
3576
|
+
length;
|
|
3577
|
+
buf;
|
|
3578
|
+
constructor(data) {
|
|
3579
|
+
super(data);
|
|
3580
|
+
const dataView = PacketView.fromPacket(this);
|
|
3581
|
+
const n = this.ackIndex;
|
|
3582
|
+
this.addr = dataView.getUint32(n, true);
|
|
3583
|
+
this.length = this.payloadSize - 7;
|
|
3584
|
+
this.buf = data.slice(n + 4, n + 4 + this.length);
|
|
3585
|
+
}
|
|
3586
|
+
static isValidPacket(data, n) {
|
|
3587
|
+
return data[4] === 4 ? data[n + 1] === 118 /* CDC2_ACK */ : true;
|
|
3588
|
+
}
|
|
3589
|
+
}
|
|
3590
|
+
|
|
3591
|
+
class LinkFileReplyD2HPacket extends HostBoundPacket {
|
|
3592
|
+
static COMMAND_ID = 86;
|
|
3593
|
+
static COMMAND_EXTENDED_ID = 21;
|
|
3594
|
+
}
|
|
3595
|
+
|
|
3596
|
+
class GetDirectoryFileCountReplyD2HPacket extends HostBoundPacket {
|
|
3597
|
+
static COMMAND_ID = 86;
|
|
3598
|
+
static COMMAND_EXTENDED_ID = 22;
|
|
3599
|
+
count;
|
|
3600
|
+
constructor(data) {
|
|
3601
|
+
super(data);
|
|
3602
|
+
const dataView = PacketView.fromPacket(this);
|
|
3603
|
+
this.count = dataView.nextUint16();
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
|
|
3607
|
+
class GetDirectoryEntryReplyD2HPacket extends HostBoundPacket {
|
|
3608
|
+
static COMMAND_ID = 86;
|
|
3609
|
+
static COMMAND_EXTENDED_ID = 23;
|
|
3610
|
+
file;
|
|
3611
|
+
constructor(data) {
|
|
3612
|
+
super(data);
|
|
3613
|
+
const dataView = PacketView.fromPacket(this);
|
|
3614
|
+
if (this.payloadSize > 4) {
|
|
3615
|
+
this.file = {
|
|
3616
|
+
index: dataView.nextUint8(),
|
|
3617
|
+
size: dataView.nextUint32(),
|
|
3618
|
+
loadAddress: dataView.nextUint32(),
|
|
3619
|
+
crc32: dataView.nextUint32(),
|
|
3620
|
+
type: dataView.nextString(4),
|
|
3621
|
+
timestamp: dataView.nextUint32() + PacketEncoder.J2000_EPOCH,
|
|
3622
|
+
version: dataView.nextVersion(),
|
|
3623
|
+
filename: dataView.nextNTBS(32)
|
|
3624
|
+
};
|
|
3625
|
+
}
|
|
3626
|
+
}
|
|
3627
|
+
}
|
|
3628
|
+
|
|
3629
|
+
class LoadFileActionReplyD2HPacket extends HostBoundPacket {
|
|
3630
|
+
static COMMAND_ID = 86;
|
|
3631
|
+
static COMMAND_EXTENDED_ID = 24;
|
|
3632
|
+
}
|
|
3633
|
+
|
|
3634
|
+
class GetFileMetadataReplyD2HPacket extends HostBoundPacket {
|
|
3635
|
+
static COMMAND_ID = 86;
|
|
3636
|
+
static COMMAND_EXTENDED_ID = 25;
|
|
3637
|
+
file;
|
|
3638
|
+
constructor(data) {
|
|
3639
|
+
super(data);
|
|
3640
|
+
const dataView = PacketView.fromPacket(this);
|
|
3641
|
+
dataView.nextUint8();
|
|
3642
|
+
if (this.payloadSize > 4) {
|
|
3643
|
+
this.file = {
|
|
3644
|
+
size: dataView.nextUint32(),
|
|
3645
|
+
loadAddress: dataView.nextUint32(),
|
|
3646
|
+
crc32: dataView.nextUint32(),
|
|
3647
|
+
type: dataView.nextString(4),
|
|
3648
|
+
timestamp: dataView.nextUint32() + PacketEncoder.J2000_EPOCH,
|
|
3649
|
+
version: dataView.nextVersion()
|
|
3650
|
+
};
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
}
|
|
3654
|
+
|
|
3655
|
+
class SetFileMetadataReplyD2HPacket extends HostBoundPacket {
|
|
3656
|
+
static COMMAND_ID = 86;
|
|
3657
|
+
static COMMAND_EXTENDED_ID = 26;
|
|
3658
|
+
}
|
|
3659
|
+
|
|
3660
|
+
class EraseFileReplyD2HPacket extends HostBoundPacket {
|
|
3661
|
+
static COMMAND_ID = 86;
|
|
3662
|
+
static COMMAND_EXTENDED_ID = 27;
|
|
3663
|
+
}
|
|
3664
|
+
|
|
3665
|
+
class GetProgramSlotInfoReplyD2HPacket extends HostBoundPacket {
|
|
3666
|
+
static COMMAND_ID = 86;
|
|
3667
|
+
static COMMAND_EXTENDED_ID = 28;
|
|
3668
|
+
requestedSlot;
|
|
3669
|
+
slot;
|
|
3670
|
+
constructor(data) {
|
|
3671
|
+
super(data);
|
|
3672
|
+
const dataView = PacketView.fromPacket(this);
|
|
3673
|
+
this.slot = dataView.nextUint8();
|
|
3674
|
+
this.requestedSlot = dataView.nextUint8();
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
|
|
3678
|
+
class FileClearUpReplyD2HPacket extends HostBoundPacket {
|
|
3679
|
+
static COMMAND_ID = 86;
|
|
3680
|
+
static COMMAND_EXTENDED_ID = 30;
|
|
3681
|
+
}
|
|
3682
|
+
|
|
3683
|
+
class FileFormatReplyD2HPacket extends HostBoundPacket {
|
|
3684
|
+
static COMMAND_ID = 86;
|
|
3685
|
+
static COMMAND_EXTENDED_ID = 31;
|
|
3686
|
+
}
|
|
3687
|
+
|
|
3688
|
+
class GetSystemFlagsReplyD2HPacket extends HostBoundPacket {
|
|
3689
|
+
static COMMAND_ID = 86;
|
|
3690
|
+
static COMMAND_EXTENDED_ID = 32;
|
|
3691
|
+
flags;
|
|
3692
|
+
radioSearching;
|
|
3693
|
+
radioQuality;
|
|
3694
|
+
controllerBatteryPercent;
|
|
3695
|
+
partnerControllerBatteryPercent;
|
|
3696
|
+
battery;
|
|
3697
|
+
currentProgram;
|
|
3698
|
+
constructor(data) {
|
|
3699
|
+
super(data);
|
|
3700
|
+
const dataView = PacketView.fromPacket(this);
|
|
3701
|
+
this.radioSearching = false;
|
|
3702
|
+
this.currentProgram = 0;
|
|
3703
|
+
this.flags = dataView.nextUint32();
|
|
3704
|
+
const hasPartner = (8192 & this.flags) !== 0;
|
|
3705
|
+
const hasRadio = (1536 & this.flags) === 1536;
|
|
3706
|
+
const byte1 = dataView.nextUint8();
|
|
3707
|
+
const byte2 = dataView.nextUint8();
|
|
3708
|
+
if (this.payloadSize === 11) {
|
|
3709
|
+
this.battery = 8 * (byte1 & 15);
|
|
3710
|
+
if ((this.flags & 256) !== 0 || hasRadio)
|
|
3711
|
+
this.controllerBatteryPercent = 8 * (byte1 >> 4 & 15);
|
|
3712
|
+
if (hasRadio)
|
|
3713
|
+
this.radioQuality = 8 * (byte2 & 15);
|
|
3714
|
+
this.radioSearching = (this.flags & 1536) === 512;
|
|
3715
|
+
if (hasPartner)
|
|
3716
|
+
this.partnerControllerBatteryPercent = 8 * (byte2 >> 4 & 15);
|
|
3717
|
+
this.currentProgram = dataView.nextUint8();
|
|
3718
|
+
if (this.battery != null && this.battery > 100)
|
|
3719
|
+
this.battery = 100;
|
|
3720
|
+
if (this.controllerBatteryPercent != null && this.controllerBatteryPercent > 100)
|
|
3721
|
+
this.controllerBatteryPercent = 100;
|
|
3722
|
+
if (this.radioQuality != null && this.radioQuality > 100)
|
|
3723
|
+
this.radioQuality = 100;
|
|
3724
|
+
if (this.partnerControllerBatteryPercent != null && this.partnerControllerBatteryPercent > 100)
|
|
3725
|
+
this.partnerControllerBatteryPercent = 100;
|
|
3726
|
+
}
|
|
3727
|
+
}
|
|
3728
|
+
}
|
|
3729
|
+
|
|
3730
|
+
class GetDeviceStatusReplyD2HPacket extends HostBoundPacket {
|
|
3731
|
+
static COMMAND_ID = 86;
|
|
3732
|
+
static COMMAND_EXTENDED_ID = 33;
|
|
3733
|
+
count;
|
|
3734
|
+
devices;
|
|
3735
|
+
constructor(data) {
|
|
3736
|
+
super(data);
|
|
3737
|
+
const dataView = PacketView.fromPacket(this);
|
|
3738
|
+
this.count = dataView.nextUint8();
|
|
3739
|
+
this.devices = [];
|
|
3740
|
+
for (let i = 0;i < this.count; i++) {
|
|
3741
|
+
this.devices.push({
|
|
3742
|
+
port: dataView.nextUint8(),
|
|
3743
|
+
type: dataView.nextUint8(),
|
|
3744
|
+
status: dataView.nextUint8(),
|
|
3745
|
+
betaversion: dataView.nextUint8(),
|
|
3746
|
+
version: dataView.nextUint16(),
|
|
3747
|
+
bootversion: dataView.nextUint16()
|
|
3748
|
+
});
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
}
|
|
3752
|
+
|
|
3753
|
+
class GetSystemStatusReplyD2HPacket extends HostBoundPacket {
|
|
3754
|
+
static COMMAND_ID = 86;
|
|
3755
|
+
static COMMAND_EXTENDED_ID = 34;
|
|
3756
|
+
systemVersion;
|
|
3757
|
+
cpu0Version;
|
|
3758
|
+
cpu1Version;
|
|
3759
|
+
nxpVersion;
|
|
3760
|
+
touchVersion;
|
|
3761
|
+
uniqueId;
|
|
3762
|
+
sysflags;
|
|
3763
|
+
eventBrain;
|
|
3764
|
+
romBootloaderActive;
|
|
3765
|
+
ramBootloaderActive;
|
|
3766
|
+
goldenVersion;
|
|
3767
|
+
constructor(data) {
|
|
3768
|
+
super(data);
|
|
3769
|
+
const dataView = PacketView.fromPacket(this);
|
|
3770
|
+
dataView.nextUint8();
|
|
3771
|
+
this.systemVersion = dataView.nextVersion();
|
|
3772
|
+
this.cpu0Version = dataView.nextVersion();
|
|
3773
|
+
this.cpu1Version = dataView.nextVersion();
|
|
3774
|
+
this.touchVersion = dataView.nextVersion(true);
|
|
3775
|
+
this.uniqueId = 1234;
|
|
3776
|
+
this.sysflags = [0, 0, 0, 0, 0, 0, 0];
|
|
3777
|
+
this.goldenVersion = VexFirmwareVersion.allZero();
|
|
3778
|
+
this.nxpVersion = VexFirmwareVersion.allZero();
|
|
3779
|
+
this.eventBrain = false;
|
|
3780
|
+
this.romBootloaderActive = false;
|
|
3781
|
+
this.ramBootloaderActive = false;
|
|
3782
|
+
if (this.payloadSize > 25) {
|
|
3783
|
+
this.uniqueId = dataView.nextUint32();
|
|
3784
|
+
this.sysflags = [
|
|
3785
|
+
dataView.nextUint8(),
|
|
3786
|
+
dataView.nextUint8(),
|
|
3787
|
+
dataView.nextUint8(),
|
|
3788
|
+
dataView.nextUint8(),
|
|
3789
|
+
dataView.nextUint8(),
|
|
3790
|
+
0,
|
|
3791
|
+
dataView.nextUint8()
|
|
3792
|
+
];
|
|
3793
|
+
this.eventBrain = (1 & this.sysflags[6]) !== 0;
|
|
3794
|
+
this.romBootloaderActive = (2 & this.sysflags[6]) !== 0;
|
|
3795
|
+
this.ramBootloaderActive = (4 & this.sysflags[6]) !== 0;
|
|
3796
|
+
dataView.nextUint16();
|
|
3797
|
+
this.goldenVersion = dataView.nextVersion();
|
|
3798
|
+
}
|
|
3799
|
+
if (this.payloadSize > 37) {
|
|
3800
|
+
this.nxpVersion = dataView.nextVersion();
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
}
|
|
3804
|
+
|
|
3805
|
+
class GetFdtStatusReplyD2HPacket extends HostBoundPacket {
|
|
3806
|
+
static COMMAND_ID = 86;
|
|
3807
|
+
static COMMAND_EXTENDED_ID = 35;
|
|
3808
|
+
count;
|
|
3809
|
+
status;
|
|
3810
|
+
constructor(data) {
|
|
3811
|
+
super(data);
|
|
3812
|
+
const dataView = PacketView.fromPacket(this);
|
|
3813
|
+
this.count = dataView.nextUint8();
|
|
3814
|
+
this.status = [];
|
|
3815
|
+
for (let i = 0;i < this.count; i++) {
|
|
3816
|
+
this.status.push({
|
|
3817
|
+
index: dataView.nextUint8(),
|
|
3818
|
+
type: dataView.nextUint8(),
|
|
3819
|
+
status: dataView.nextUint8(),
|
|
3820
|
+
betaversion: dataView.nextUint8(),
|
|
3821
|
+
version: dataView.nextUint16(),
|
|
3822
|
+
bootversion: dataView.nextUint16()
|
|
3823
|
+
});
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
|
|
3828
|
+
class GetLogCountReplyD2HPacket extends HostBoundPacket {
|
|
3829
|
+
static COMMAND_ID = 86;
|
|
3830
|
+
static COMMAND_EXTENDED_ID = 36;
|
|
3831
|
+
count;
|
|
3832
|
+
constructor(data) {
|
|
3833
|
+
super(data);
|
|
3834
|
+
const dataView = PacketView.fromPacket(this);
|
|
3835
|
+
dataView.nextUint8();
|
|
3836
|
+
this.count = dataView.nextUint32();
|
|
3837
|
+
}
|
|
3838
|
+
}
|
|
3839
|
+
|
|
3840
|
+
class ReadLogPageReplyD2HPacket extends HostBoundPacket {
|
|
3841
|
+
static COMMAND_ID = 86;
|
|
3842
|
+
static COMMAND_EXTENDED_ID = 37;
|
|
3843
|
+
offset;
|
|
3844
|
+
count;
|
|
3845
|
+
entries;
|
|
3846
|
+
constructor(data) {
|
|
3847
|
+
super(data);
|
|
3848
|
+
const dataView = PacketView.fromPacket(this);
|
|
3849
|
+
const n = this.ackIndex;
|
|
3850
|
+
const size = dataView.nextUint8();
|
|
3851
|
+
this.offset = dataView.nextUint32();
|
|
3852
|
+
this.count = dataView.nextUint16();
|
|
3853
|
+
this.entries = [];
|
|
3854
|
+
let j = n + 8;
|
|
3855
|
+
for (let i = 0;i < this.count; i++) {
|
|
3856
|
+
this.entries.push({
|
|
3857
|
+
code: dataView.getUint8(j),
|
|
3858
|
+
type: dataView.getUint8(j + 1),
|
|
3859
|
+
desc: dataView.getUint8(j + 2),
|
|
3860
|
+
spare: dataView.getUint8(j + 3),
|
|
3861
|
+
time: dataView.getUint32(j + 4, true)
|
|
3862
|
+
});
|
|
3863
|
+
j += size;
|
|
3864
|
+
}
|
|
3865
|
+
}
|
|
3866
|
+
}
|
|
3867
|
+
|
|
3868
|
+
class GetRadioStatusReplyD2HPacket extends HostBoundPacket {
|
|
3869
|
+
static COMMAND_ID = 86;
|
|
3870
|
+
static COMMAND_EXTENDED_ID = 38;
|
|
3871
|
+
device;
|
|
3872
|
+
quality;
|
|
3873
|
+
strength;
|
|
3874
|
+
channel;
|
|
3875
|
+
timeslot;
|
|
3876
|
+
constructor(data) {
|
|
3877
|
+
super(data);
|
|
3878
|
+
const dataView = PacketView.fromPacket(this);
|
|
3879
|
+
const n = this.ackIndex;
|
|
3880
|
+
this.device = dataView.nextUint8();
|
|
3881
|
+
this.quality = dataView.nextUint16();
|
|
3882
|
+
this.strength = dataView.nextInt16();
|
|
3883
|
+
this.channel = this.data[n + 6];
|
|
3884
|
+
this.timeslot = this.data[n + 7];
|
|
3885
|
+
}
|
|
3886
|
+
}
|
|
3887
|
+
|
|
3888
|
+
class GetUserDataReplyD2HPacket extends HostBoundPacket {
|
|
3889
|
+
static COMMAND_ID = 86;
|
|
3890
|
+
static COMMAND_EXTENDED_ID = 39;
|
|
3891
|
+
}
|
|
3892
|
+
|
|
3893
|
+
class ScreenCaptureReplyD2HPacket extends HostBoundPacket {
|
|
3894
|
+
static COMMAND_ID = 86;
|
|
3895
|
+
static COMMAND_EXTENDED_ID = 40;
|
|
3896
|
+
}
|
|
3897
|
+
|
|
3898
|
+
class SendDashTouchReplyD2HPacket extends HostBoundPacket {
|
|
3899
|
+
static COMMAND_ID = 86;
|
|
3900
|
+
static COMMAND_EXTENDED_ID = 42;
|
|
3901
|
+
}
|
|
3902
|
+
|
|
3903
|
+
class SelectDashReplyD2HPacket extends HostBoundPacket {
|
|
3904
|
+
static COMMAND_ID = 86;
|
|
3905
|
+
static COMMAND_EXTENDED_ID = 43;
|
|
3906
|
+
}
|
|
3907
|
+
|
|
3908
|
+
class EnableDashReplyD2HPacket extends HostBoundPacket {
|
|
3909
|
+
static COMMAND_ID = 86;
|
|
3910
|
+
static COMMAND_EXTENDED_ID = 44;
|
|
3911
|
+
}
|
|
3912
|
+
|
|
3913
|
+
class DisableDashReplyD2HPacket extends HostBoundPacket {
|
|
3914
|
+
static COMMAND_ID = 86;
|
|
3915
|
+
static COMMAND_EXTENDED_ID = 45;
|
|
3916
|
+
}
|
|
3917
|
+
|
|
3918
|
+
class ReadKeyValueReplyD2HPacket extends HostBoundPacket {
|
|
3919
|
+
static COMMAND_ID = 86;
|
|
3920
|
+
static COMMAND_EXTENDED_ID = 46;
|
|
3921
|
+
value;
|
|
3922
|
+
constructor(data) {
|
|
3923
|
+
super(data);
|
|
3924
|
+
const dataView = PacketView.fromPacket(this);
|
|
3925
|
+
this.value = dataView.nextVarNTBS(255);
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3928
|
+
|
|
3929
|
+
class WriteKeyValueReplyD2HPacket extends HostBoundPacket {
|
|
3930
|
+
static COMMAND_ID = 86;
|
|
3931
|
+
static COMMAND_EXTENDED_ID = 47;
|
|
3932
|
+
}
|
|
3933
|
+
|
|
3934
|
+
class GetSlot1to4InfoReplyD2HPacket extends HostBoundPacket {
|
|
3935
|
+
static COMMAND_ID = 86;
|
|
3936
|
+
static COMMAND_EXTENDED_ID = 49;
|
|
3937
|
+
slotFlags;
|
|
3938
|
+
slots;
|
|
3939
|
+
constructor(data, start = 1) {
|
|
3940
|
+
super(data);
|
|
3941
|
+
const dataView = PacketView.fromPacket(this);
|
|
3942
|
+
this.slotFlags = dataView.nextUint8();
|
|
3943
|
+
this.slots = [];
|
|
3944
|
+
for (let i = 0;i < 4; i++) {
|
|
3945
|
+
const hasData = (this.slotFlags & Math.pow(2, start - 1 + i)) !== 0;
|
|
3946
|
+
if (!hasData)
|
|
3947
|
+
continue;
|
|
3948
|
+
const iconNum = dataView.nextUint16();
|
|
3949
|
+
const nameLen = dataView.nextUint8();
|
|
3950
|
+
const name = dataView.nextString(nameLen);
|
|
3951
|
+
this.slots.push({
|
|
3952
|
+
slot: start + i,
|
|
3953
|
+
icon: iconNum,
|
|
3954
|
+
name
|
|
3955
|
+
});
|
|
3956
|
+
}
|
|
3957
|
+
}
|
|
3958
|
+
}
|
|
3959
|
+
|
|
3960
|
+
class GetSlot5to8InfoReplyD2HPacket extends GetSlot1to4InfoReplyD2HPacket {
|
|
3961
|
+
static COMMAND_ID = 86;
|
|
3962
|
+
static COMMAND_EXTENDED_ID = 50;
|
|
3963
|
+
slotStartIndex = 5;
|
|
3964
|
+
constructor(data) {
|
|
3965
|
+
super(data, 5);
|
|
3966
|
+
}
|
|
3967
|
+
}
|
|
3968
|
+
|
|
3969
|
+
class FactoryStatusReplyD2HPacket extends HostBoundPacket {
|
|
3970
|
+
static COMMAND_ID = 86;
|
|
3971
|
+
static COMMAND_EXTENDED_ID = 241;
|
|
3972
|
+
status;
|
|
3973
|
+
percent;
|
|
3974
|
+
constructor(data) {
|
|
3975
|
+
super(data);
|
|
3976
|
+
const dataView = PacketView.fromPacket(this);
|
|
3977
|
+
this.status = dataView.nextUint8();
|
|
3978
|
+
this.percent = dataView.nextUint8();
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
|
|
3982
|
+
class FactoryEnableReplyD2HPacket extends HostBoundPacket {
|
|
3983
|
+
static COMMAND_ID = 86;
|
|
3984
|
+
static COMMAND_EXTENDED_ID = 255;
|
|
3985
|
+
}
|
|
3986
|
+
|
|
3987
|
+
// ../serial/src/VexConnection.ts
|
|
3988
|
+
var thePacketEncoder = PacketEncoder.getInstance();
|
|
3989
|
+
|
|
3990
|
+
class VexSerialConnection extends VexEventTarget {
|
|
3991
|
+
filters = [{ usbVendorId: 10376 }];
|
|
3992
|
+
writer;
|
|
3993
|
+
reader;
|
|
3994
|
+
port;
|
|
3995
|
+
serial;
|
|
3996
|
+
callbacksQueue = [];
|
|
3997
|
+
get isConnected() {
|
|
3998
|
+
return this.port !== undefined && this.reader !== undefined && this.writer !== undefined;
|
|
3999
|
+
}
|
|
4000
|
+
constructor(serial) {
|
|
4001
|
+
super();
|
|
4002
|
+
this.serial = serial;
|
|
4003
|
+
}
|
|
4004
|
+
async close() {
|
|
4005
|
+
if (!this.isConnected)
|
|
4006
|
+
return;
|
|
4007
|
+
try {
|
|
4008
|
+
await this.writer?.close();
|
|
4009
|
+
this.writer = undefined;
|
|
4010
|
+
} catch (e) {}
|
|
4011
|
+
try {
|
|
4012
|
+
await this.reader?.cancel();
|
|
4013
|
+
try {
|
|
4014
|
+
while (this.reader != null) {
|
|
4015
|
+
const { done } = await this.reader.read();
|
|
4016
|
+
if (done)
|
|
4017
|
+
break;
|
|
4018
|
+
}
|
|
4019
|
+
} catch (e) {}
|
|
4020
|
+
this.reader = undefined;
|
|
4021
|
+
} catch (e) {}
|
|
4022
|
+
try {
|
|
4023
|
+
await new Promise((resolve) => setTimeout(resolve, 1));
|
|
4024
|
+
await this.port?.close();
|
|
4025
|
+
this.port = undefined;
|
|
4026
|
+
} catch (e) {
|
|
4027
|
+
console.warn("Close port error.", e);
|
|
4028
|
+
} finally {
|
|
4029
|
+
this.emit("disconnected", undefined);
|
|
4030
|
+
}
|
|
4031
|
+
}
|
|
4032
|
+
async open(use = 0, askUser = true) {
|
|
4033
|
+
if (this.port !== undefined)
|
|
4034
|
+
throw new Error("Already connected.");
|
|
4035
|
+
let port;
|
|
4036
|
+
if (use !== undefined) {
|
|
4037
|
+
const ports = (await this.serial.getPorts()).filter((p) => {
|
|
4038
|
+
const info = p.getInfo();
|
|
4039
|
+
return this.filters.find((f) => (f.usbVendorId === undefined || f.usbVendorId === info.usbVendorId) && (f.usbProductId === undefined || f.usbProductId === info.usbProductId));
|
|
4040
|
+
}).filter((e) => e.readable !== null);
|
|
4041
|
+
port = ports[use];
|
|
4042
|
+
}
|
|
4043
|
+
if (port == null && askUser) {
|
|
4044
|
+
try {
|
|
4045
|
+
port = await this.serial.requestPort({ filters: this.filters });
|
|
4046
|
+
} catch (e) {
|
|
4047
|
+
console.warn("No valid port selected.");
|
|
4048
|
+
}
|
|
4049
|
+
}
|
|
4050
|
+
if (port == null)
|
|
4051
|
+
return;
|
|
4052
|
+
if (port.readable != null)
|
|
4053
|
+
return false;
|
|
4054
|
+
try {
|
|
4055
|
+
await port.open({ baudRate: 115200 });
|
|
4056
|
+
this.port = port;
|
|
4057
|
+
this.port.addEventListener("disconnect", () => {
|
|
4058
|
+
this.close();
|
|
4059
|
+
});
|
|
4060
|
+
this.emit("connected", undefined);
|
|
4061
|
+
this.writer = this.port.writable.getWriter();
|
|
4062
|
+
this.reader = this.port.readable.getReader();
|
|
4063
|
+
this.startReader();
|
|
4064
|
+
return true;
|
|
4065
|
+
} catch (e) {
|
|
4066
|
+
return false;
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4069
|
+
writeData(rawData, resolve, timeout = 1000) {
|
|
4070
|
+
this.writeDataAsync(rawData, timeout).then(resolve);
|
|
4071
|
+
}
|
|
4072
|
+
async writeDataAsync(rawData, timeout = 1000) {
|
|
4073
|
+
return await new Promise((resolve) => {
|
|
4074
|
+
if (this.writer === undefined) {
|
|
4075
|
+
resolve(255 /* CDC2_NACK */);
|
|
4076
|
+
return;
|
|
4077
|
+
}
|
|
4078
|
+
const data = rawData instanceof DeviceBoundPacket ? rawData.data : rawData;
|
|
4079
|
+
const cb = {
|
|
4080
|
+
callback: resolve,
|
|
4081
|
+
timeout: setTimeout(() => {
|
|
4082
|
+
this.callbacksQueue.shift()?.callback(256 /* TIMEOUT */);
|
|
4083
|
+
}, timeout),
|
|
4084
|
+
wantedCommandId: rawData instanceof DeviceBoundPacket ? rawData.constructor.COMMAND_ID : undefined,
|
|
4085
|
+
wantedCommandExId: rawData instanceof DeviceBoundPacket ? rawData.constructor.COMMAND_EXTENDED_ID : undefined
|
|
4086
|
+
};
|
|
4087
|
+
this.callbacksQueue.push(cb);
|
|
4088
|
+
this.writer.write(data).then(() => {
|
|
4089
|
+
logData(data, 100);
|
|
4090
|
+
}).catch(() => {
|
|
4091
|
+
this.callbacksQueue.splice(this.callbacksQueue.indexOf(cb), 1);
|
|
4092
|
+
resolve(257 /* WRITE_ERROR */);
|
|
4093
|
+
});
|
|
4094
|
+
});
|
|
4095
|
+
}
|
|
4096
|
+
async readData(cache, expectedSize) {
|
|
4097
|
+
if (this.reader == null)
|
|
4098
|
+
throw new Error("No reader");
|
|
4099
|
+
while (cache.byteLength < expectedSize) {
|
|
4100
|
+
const { value: readData, done: isDone } = await this.reader.read();
|
|
4101
|
+
if (isDone)
|
|
4102
|
+
throw new Error("No data");
|
|
4103
|
+
cache = binaryArrayJoin(cache, readData);
|
|
4104
|
+
}
|
|
4105
|
+
return cache;
|
|
4106
|
+
}
|
|
4107
|
+
async startReader() {
|
|
4108
|
+
let cache = new Uint8Array([]);
|
|
4109
|
+
let sliceIdx = 0;
|
|
4110
|
+
for (;; )
|
|
4111
|
+
try {
|
|
4112
|
+
cache = await this.readData(cache, 5);
|
|
4113
|
+
sliceIdx = 0;
|
|
4114
|
+
if (!thePacketEncoder.validateHeader(cache))
|
|
4115
|
+
throw new Error("Invalid header");
|
|
4116
|
+
const payloadExpectedSize = thePacketEncoder.getPayloadSize(cache);
|
|
4117
|
+
const n = payloadExpectedSize > 128 ? 5 : 4;
|
|
4118
|
+
const totalSize = n + payloadExpectedSize;
|
|
4119
|
+
cache = await this.readData(cache, totalSize);
|
|
4120
|
+
sliceIdx = totalSize;
|
|
4121
|
+
const cmdId = cache[2];
|
|
4122
|
+
const hasExtId = cmdId === 88 || cmdId === 86;
|
|
4123
|
+
const cmdExId = hasExtId ? cache[n] : undefined;
|
|
4124
|
+
const ack = cache[n + 1];
|
|
4125
|
+
if (hasExtId) {
|
|
4126
|
+
if (!thePacketEncoder.validateMessageCdc(cache))
|
|
4127
|
+
throw new Error("Invalid message CDC");
|
|
4128
|
+
}
|
|
4129
|
+
let callbackInfo;
|
|
4130
|
+
let wantedCmdId;
|
|
4131
|
+
let wantedCmdExId;
|
|
4132
|
+
let tryIdx = 0;
|
|
4133
|
+
while ((callbackInfo = this.callbacksQueue[tryIdx++]) !== null) {
|
|
4134
|
+
wantedCmdId = callbackInfo?.wantedCommandId;
|
|
4135
|
+
wantedCmdExId = callbackInfo?.wantedCommandExId;
|
|
4136
|
+
if (wantedCmdId !== undefined && wantedCmdId !== cmdId || wantedCmdExId !== undefined && wantedCmdExId !== cmdExId) {
|
|
4137
|
+
continue;
|
|
4138
|
+
}
|
|
4139
|
+
break;
|
|
4140
|
+
}
|
|
4141
|
+
if (callbackInfo === undefined) {
|
|
4142
|
+
console.warn("Unexpected command", cmdId, cmdExId, ack);
|
|
4143
|
+
continue;
|
|
4144
|
+
}
|
|
4145
|
+
const data = cache.slice(0, sliceIdx);
|
|
4146
|
+
const PackageType = thePacketEncoder.allPacketsTable[wantedCmdId + " " + wantedCmdExId];
|
|
4147
|
+
if (wantedCmdId === undefined && wantedCmdExId === undefined || PackageType === undefined) {
|
|
4148
|
+
callbackInfo.callback(data);
|
|
4149
|
+
} else {
|
|
4150
|
+
if (!hasExtId || PackageType.isValidPacket(data, n)) {
|
|
4151
|
+
callbackInfo.callback(new PackageType(data));
|
|
4152
|
+
} else {
|
|
4153
|
+
console.warn("ack", ack);
|
|
4154
|
+
callbackInfo.callback(ack);
|
|
4155
|
+
}
|
|
4156
|
+
}
|
|
4157
|
+
clearTimeout(callbackInfo.timeout);
|
|
4158
|
+
this.callbacksQueue.splice(tryIdx - 1, 1);
|
|
4159
|
+
} catch (e) {
|
|
4160
|
+
if (!(e instanceof Error && e.message === "No data")) {
|
|
4161
|
+
console.warn("Read error.", e, cache);
|
|
4162
|
+
}
|
|
4163
|
+
await this.close();
|
|
4164
|
+
break;
|
|
4165
|
+
} finally {
|
|
4166
|
+
cache = cache.slice(sliceIdx);
|
|
4167
|
+
}
|
|
4168
|
+
}
|
|
4169
|
+
async query1() {
|
|
4170
|
+
const result = await this.writeDataAsync(new Query1H2DPacket, 100);
|
|
4171
|
+
return result instanceof Query1ReplyD2HPacket ? result : null;
|
|
4172
|
+
}
|
|
4173
|
+
async getSystemVersion() {
|
|
4174
|
+
const result = await this.writeDataAsync(new SystemVersionH2DPacket);
|
|
4175
|
+
return result instanceof SystemVersionReplyD2HPacket ? result.version : null;
|
|
4176
|
+
}
|
|
4177
|
+
}
|
|
4178
|
+
|
|
4179
|
+
class V5SerialConnection extends VexSerialConnection {
|
|
4180
|
+
filters = [
|
|
4181
|
+
{ usbVendorId: 10376, usbProductId: 1281 /* V5_BRAIN */ },
|
|
4182
|
+
{ usbVendorId: 10376, usbProductId: 1282 /* V5_BRAIN_DFU */ },
|
|
4183
|
+
{ usbVendorId: 10376, usbProductId: 1283 /* V5_CONTROLLER */ }
|
|
4184
|
+
];
|
|
4185
|
+
async getDeviceStatus() {
|
|
4186
|
+
const result = await this.writeDataAsync(new GetDeviceStatusH2DPacket);
|
|
4187
|
+
return result instanceof GetDeviceStatusReplyD2HPacket ? result : null;
|
|
4188
|
+
}
|
|
4189
|
+
async getRadioStatus() {
|
|
4190
|
+
const result = await this.writeDataAsync(new GetRadioStatusH2DPacket);
|
|
4191
|
+
return result instanceof GetRadioStatusReplyD2HPacket ? result : null;
|
|
4192
|
+
}
|
|
4193
|
+
async getSystemFlags() {
|
|
4194
|
+
const result = await this.writeDataAsync(new GetSystemFlagsH2DPacket);
|
|
4195
|
+
return result instanceof GetSystemFlagsReplyD2HPacket ? result : null;
|
|
4196
|
+
}
|
|
4197
|
+
async getSystemStatus(timeout = 1000) {
|
|
4198
|
+
const result = await this.writeDataAsync(new GetSystemStatusH2DPacket, timeout);
|
|
4199
|
+
return result instanceof GetSystemStatusReplyD2HPacket ? result : null;
|
|
4200
|
+
}
|
|
4201
|
+
async getMatchStatus() {
|
|
4202
|
+
const result = await this.writeDataAsync(new GetMatchStatusH2DPacket);
|
|
4203
|
+
return result instanceof MatchStatusReplyD2HPacket ? result : null;
|
|
4204
|
+
}
|
|
4205
|
+
async uploadProgramToDevice(iniConfig, binFileBuf, coldFileBuf, progressCallback) {
|
|
4206
|
+
const iniFileBuffer = new TextEncoder().encode(iniConfig.createIni());
|
|
4207
|
+
const basename = iniConfig.baseName;
|
|
4208
|
+
const iniRequest = {
|
|
4209
|
+
filename: basename + ".ini",
|
|
4210
|
+
buf: iniFileBuffer,
|
|
4211
|
+
downloadTarget: 1 /* FILE_TARGET_QSPI */,
|
|
4212
|
+
vendor: 1 /* USER */,
|
|
4213
|
+
autoRun: false
|
|
4214
|
+
};
|
|
4215
|
+
const r1 = await this.uploadFileToDevice(iniRequest, (current, total) => {
|
|
4216
|
+
progressCallback("INI", current, total);
|
|
4217
|
+
});
|
|
4218
|
+
if (!r1)
|
|
4219
|
+
return false;
|
|
4220
|
+
const coldRequest = coldFileBuf !== undefined ? {
|
|
4221
|
+
filename: basename + "_lib.bin",
|
|
4222
|
+
buf: coldFileBuf,
|
|
4223
|
+
downloadTarget: 1 /* FILE_TARGET_QSPI */,
|
|
4224
|
+
vendor: 24 /* DEV2 */,
|
|
4225
|
+
autoRun: false
|
|
4226
|
+
} : undefined;
|
|
4227
|
+
if (coldRequest != null) {
|
|
4228
|
+
const r2 = await this.uploadFileToDevice(coldRequest, (current, total) => {
|
|
4229
|
+
progressCallback("COLD", current, total);
|
|
4230
|
+
});
|
|
4231
|
+
if (!r2)
|
|
4232
|
+
return;
|
|
4233
|
+
}
|
|
4234
|
+
const binRequest = {
|
|
4235
|
+
filename: basename + ".bin",
|
|
4236
|
+
buf: binFileBuf,
|
|
4237
|
+
downloadTarget: 1 /* FILE_TARGET_QSPI */,
|
|
4238
|
+
vendor: 1 /* USER */,
|
|
4239
|
+
loadAddress: coldFileBuf != null ? 125829120 : undefined,
|
|
4240
|
+
autoRun: iniConfig.autorun,
|
|
4241
|
+
linkedFile: coldRequest
|
|
4242
|
+
};
|
|
4243
|
+
const r3 = await this.uploadFileToDevice(binRequest, (current, total) => {
|
|
4244
|
+
progressCallback("BIN", current, total);
|
|
4245
|
+
});
|
|
4246
|
+
return r3;
|
|
4247
|
+
}
|
|
4248
|
+
async downloadFileToHost(request, downloadTarget = 1 /* FILE_TARGET_QSPI */, progressCallback) {
|
|
4249
|
+
const { filename, vendor, loadAddress, size } = request;
|
|
4250
|
+
let nextAddress = loadAddress ?? USER_FLASH_USR_CODE_START;
|
|
4251
|
+
const p1 = await this.writeDataAsync(new InitFileTransferH2DPacket(2 /* READ */, downloadTarget, vendor, 0 /* NONE */, new Uint8Array, nextAddress, filename, ""));
|
|
4252
|
+
if (!(p1 instanceof InitFileTransferReplyD2HPacket))
|
|
4253
|
+
throw new Error("InitFileTransferH2DPacket failed");
|
|
4254
|
+
const fileSize = size ?? p1.fileSize;
|
|
4255
|
+
const bufferChunkSize = p1.windowSize > 0 && p1.windowSize <= USER_PROG_CHUNK_SIZE ? p1.windowSize : USER_PROG_CHUNK_SIZE;
|
|
4256
|
+
let bufferOffset = 0;
|
|
4257
|
+
let fileBuf = new Uint8Array(fileSize + bufferChunkSize);
|
|
4258
|
+
let lastBlock = false;
|
|
4259
|
+
while (!lastBlock) {
|
|
4260
|
+
if (fileSize <= bufferOffset + bufferChunkSize) {
|
|
4261
|
+
lastBlock = true;
|
|
4262
|
+
}
|
|
4263
|
+
const p2 = await this.writeDataAsync(new ReadFileH2DPacket(nextAddress, bufferChunkSize), 3000);
|
|
4264
|
+
if (!(p2 instanceof ReadFileReplyD2HPacket))
|
|
4265
|
+
throw new Error("ReadFileReplyD2HPacket failed");
|
|
4266
|
+
fileBuf.set(new Uint8Array(p2.buf), bufferOffset);
|
|
4267
|
+
if (progressCallback != null)
|
|
4268
|
+
progressCallback(bufferOffset, fileSize);
|
|
4269
|
+
bufferOffset += bufferChunkSize;
|
|
4270
|
+
nextAddress += bufferChunkSize;
|
|
4271
|
+
}
|
|
4272
|
+
await this.writeDataAsync(new ExitFileTransferH2DPacket(3 /* EXIT_HALT */), 30000);
|
|
4273
|
+
fileBuf = fileBuf.slice(0, fileSize);
|
|
4274
|
+
return fileBuf;
|
|
4275
|
+
}
|
|
4276
|
+
async uploadFileToDevice(request, progressCallback) {
|
|
4277
|
+
let {
|
|
4278
|
+
filename,
|
|
4279
|
+
buf,
|
|
4280
|
+
downloadTarget,
|
|
4281
|
+
vendor,
|
|
4282
|
+
loadAddress,
|
|
4283
|
+
exttype,
|
|
4284
|
+
autoRun,
|
|
4285
|
+
linkedFile
|
|
4286
|
+
} = request;
|
|
4287
|
+
if (buf === undefined) {
|
|
4288
|
+
return false;
|
|
4289
|
+
}
|
|
4290
|
+
downloadTarget = downloadTarget ?? 1 /* FILE_TARGET_QSPI */;
|
|
4291
|
+
vendor = vendor ?? 1 /* USER */;
|
|
4292
|
+
let nextAddress = loadAddress ?? USER_FLASH_USR_CODE_START;
|
|
4293
|
+
console.log("init file transfer", filename);
|
|
4294
|
+
const p1 = await this.writeDataAsync(new InitFileTransferH2DPacket(1 /* WRITE */, downloadTarget, vendor, 1 /* OVERWRITE */, buf, nextAddress, filename, exttype));
|
|
4295
|
+
if (!(p1 instanceof InitFileTransferReplyD2HPacket))
|
|
4296
|
+
throw new Error("InitFileTransferH2DPacket failed");
|
|
4297
|
+
console.log(p1);
|
|
4298
|
+
if (linkedFile !== undefined) {
|
|
4299
|
+
const p3 = await this.writeDataAsync(new LinkFileH2DPacket(linkedFile.vendor ?? 1 /* USER */, linkedFile.filename, 0), 1e4);
|
|
4300
|
+
if (!(p3 instanceof LinkFileReplyD2HPacket))
|
|
4301
|
+
throw new Error("LinkFileH2DPacket failed");
|
|
4302
|
+
}
|
|
4303
|
+
const bufferChunkSize = p1.windowSize > 0 && p1.windowSize <= USER_PROG_CHUNK_SIZE ? p1.windowSize : USER_PROG_CHUNK_SIZE;
|
|
4304
|
+
let bufferOffset = 0;
|
|
4305
|
+
let lastBlock = false;
|
|
4306
|
+
let transferFailed = true;
|
|
4307
|
+
let exitReply;
|
|
4308
|
+
try {
|
|
4309
|
+
while (!lastBlock) {
|
|
4310
|
+
let tmpbuf;
|
|
4311
|
+
if (buf.byteLength - bufferOffset > bufferChunkSize) {
|
|
4312
|
+
tmpbuf = buf.subarray(bufferOffset, bufferOffset + bufferChunkSize);
|
|
4313
|
+
} else {
|
|
4314
|
+
const length = (buf.byteLength - bufferOffset + 3) / 4 >>> 0;
|
|
4315
|
+
tmpbuf = new Uint8Array(length * 4);
|
|
4316
|
+
tmpbuf.set(buf.subarray(bufferOffset, buf.byteLength));
|
|
4317
|
+
lastBlock = true;
|
|
4318
|
+
}
|
|
4319
|
+
const p2 = await this.writeDataAsync(new WriteFileH2DPacket(nextAddress, tmpbuf), 3000);
|
|
4320
|
+
if (!(p2 instanceof WriteFileReplyD2HPacket))
|
|
4321
|
+
throw new Error("WriteFileReplyD2HPacket failed");
|
|
4322
|
+
if (progressCallback != null)
|
|
4323
|
+
progressCallback(bufferOffset, buf.byteLength);
|
|
4324
|
+
bufferOffset += bufferChunkSize;
|
|
4325
|
+
nextAddress += bufferChunkSize;
|
|
4326
|
+
}
|
|
4327
|
+
transferFailed = false;
|
|
4328
|
+
} finally {
|
|
4329
|
+
exitReply = await this.writeDataAsync(new ExitFileTransferH2DPacket(transferFailed ? 3 /* EXIT_HALT */ : autoRun ? 1 /* EXIT_RUN */ : 3 /* EXIT_HALT */), 30000);
|
|
4330
|
+
}
|
|
4331
|
+
return exitReply instanceof ExitFileTransferReplyD2HPacket;
|
|
4332
|
+
}
|
|
4333
|
+
async setMatchMode(mode) {
|
|
4334
|
+
const result = await this.writeDataAsync(new UpdateMatchModeH2DPacket(mode, 0));
|
|
4335
|
+
return result instanceof MatchModeReplyD2HPacket ? result : null;
|
|
4336
|
+
}
|
|
4337
|
+
async loadProgram(value) {
|
|
4338
|
+
const result = await this.writeDataAsync(new LoadFileActionH2DPacket(1 /* USER */, 0 /* RUN */, value));
|
|
4339
|
+
return result instanceof LoadFileActionReplyD2HPacket ? result : null;
|
|
4340
|
+
}
|
|
4341
|
+
async stopProgram() {
|
|
4342
|
+
const result = await this.writeDataAsync(new LoadFileActionH2DPacket(1 /* USER */, 128 /* STOP */, ""));
|
|
4343
|
+
return result instanceof LoadFileActionReplyD2HPacket ? result : null;
|
|
4344
|
+
}
|
|
4345
|
+
async mockTouch(x, y, press) {
|
|
4346
|
+
const result = await this.writeDataAsync(new SendDashTouchH2DPacket(x, y, press));
|
|
4347
|
+
return result instanceof SendDashTouchReplyD2HPacket ? result : null;
|
|
4348
|
+
}
|
|
4349
|
+
async openScreen(screen, port) {
|
|
4350
|
+
const result = await this.writeDataAsync(new SelectDashH2DPacket(screen, port));
|
|
4351
|
+
return result instanceof SendDashTouchReplyD2HPacket ? result : null;
|
|
4352
|
+
}
|
|
4353
|
+
}
|
|
4354
|
+
function logData(data, limitedSize) {
|
|
4355
|
+
if (data === undefined)
|
|
4356
|
+
return;
|
|
4357
|
+
limitedSize ||= data.length;
|
|
4358
|
+
let a = "";
|
|
4359
|
+
for (let n = 0;n < data.length && n < limitedSize; n++)
|
|
4360
|
+
a += ("00" + data[n].toString(16)).substr(-2, 2) + " ";
|
|
4361
|
+
limitedSize < data.length && (a += " ... ");
|
|
4362
|
+
}
|
|
4363
|
+
function binaryArrayJoin(left, right) {
|
|
4364
|
+
const leftSize = left != null ? left.byteLength : 0;
|
|
4365
|
+
const rightSize = right != null ? right.byteLength : 0;
|
|
4366
|
+
const all = new Uint8Array(leftSize + rightSize);
|
|
4367
|
+
return all.length === 0 ? new Uint8Array : (left != null && all.set(new Uint8Array(left), 0), right != null && all.set(new Uint8Array(right), leftSize), all);
|
|
4368
|
+
}
|
|
4369
|
+
// ../serial/src/VexDevice.ts
|
|
4370
|
+
async function downloadFileFromInternet(link) {
|
|
4371
|
+
return await new Promise((resolve, reject) => {
|
|
4372
|
+
const oReq = new XMLHttpRequest;
|
|
4373
|
+
oReq.open("GET", link, true);
|
|
4374
|
+
oReq.responseType = "arraybuffer";
|
|
4375
|
+
oReq.onload = function(_oEvent) {
|
|
4376
|
+
const arrayBuffer = oReq.response;
|
|
4377
|
+
resolve(arrayBuffer);
|
|
4378
|
+
};
|
|
4379
|
+
oReq.onerror = function(oEvent) {
|
|
4380
|
+
reject(oEvent);
|
|
4381
|
+
};
|
|
4382
|
+
oReq.send(null);
|
|
4383
|
+
});
|
|
4384
|
+
}
|
|
4385
|
+
async function sleepUntilAsync(f, timeout, interval = 20) {
|
|
4386
|
+
return await new Promise((resolve) => {
|
|
4387
|
+
let lastTime = new Date().getTime();
|
|
4388
|
+
let stopped = false;
|
|
4389
|
+
const stopper = setTimeout(() => {
|
|
4390
|
+
stopped = true;
|
|
4391
|
+
resolve(false);
|
|
4392
|
+
}, timeout);
|
|
4393
|
+
const checker = (val) => {
|
|
4394
|
+
if (stopped)
|
|
4395
|
+
return;
|
|
4396
|
+
if (val) {
|
|
4397
|
+
clearTimeout(stopper);
|
|
4398
|
+
resolve(true);
|
|
4399
|
+
} else if (new Date().getTime() - lastTime > interval) {
|
|
4400
|
+
lastTime = new Date().getTime();
|
|
4401
|
+
f().then(checker);
|
|
4402
|
+
} else
|
|
4403
|
+
setTimeout(() => {
|
|
4404
|
+
lastTime = new Date().getTime();
|
|
4405
|
+
f().then(checker);
|
|
4406
|
+
}, new Date().getTime() - lastTime);
|
|
4407
|
+
};
|
|
4408
|
+
f().then(checker);
|
|
4409
|
+
});
|
|
4410
|
+
}
|
|
4411
|
+
async function sleepUntil(f, timeout, interval = 20) {
|
|
4412
|
+
return await new Promise((resolve) => {
|
|
4413
|
+
const timeWas = new Date().getTime();
|
|
4414
|
+
const wait = setInterval(function() {
|
|
4415
|
+
if (f()) {
|
|
4416
|
+
clearInterval(wait);
|
|
4417
|
+
resolve(true);
|
|
4418
|
+
} else if (new Date().getTime() - timeWas > timeout) {
|
|
4419
|
+
clearInterval(wait);
|
|
4420
|
+
resolve(false);
|
|
4421
|
+
}
|
|
4422
|
+
}, interval);
|
|
4423
|
+
});
|
|
4424
|
+
}
|
|
4425
|
+
async function sleep(ms) {
|
|
4426
|
+
return await new Promise((resolve) => setTimeout(resolve, ms));
|
|
4427
|
+
}
|
|
4428
|
+
|
|
4429
|
+
class VexSerialDevice extends VexEventTarget {
|
|
4430
|
+
connection;
|
|
4431
|
+
defaultSerial;
|
|
4432
|
+
get isConnected() {
|
|
4433
|
+
return this.connection != null ? this.connection.isConnected : false;
|
|
4434
|
+
}
|
|
4435
|
+
get deviceType() {
|
|
4436
|
+
return this.isConnected ? this.connection?.port?.getInfo().usbProductId : undefined;
|
|
4437
|
+
}
|
|
4438
|
+
constructor(defaultSerial) {
|
|
4439
|
+
super();
|
|
4440
|
+
this.defaultSerial = defaultSerial;
|
|
4441
|
+
}
|
|
4442
|
+
}
|
|
4443
|
+
|
|
4444
|
+
class V5SerialDeviceState {
|
|
4445
|
+
_instance;
|
|
4446
|
+
_isFileTransferring = false;
|
|
4447
|
+
brain = {
|
|
4448
|
+
activeProgram: 0,
|
|
4449
|
+
battery: {
|
|
4450
|
+
batteryPercent: 0,
|
|
4451
|
+
isCharging: false
|
|
4452
|
+
},
|
|
4453
|
+
button: {
|
|
4454
|
+
isPressed: false,
|
|
4455
|
+
isDoublePressed: false
|
|
4456
|
+
},
|
|
4457
|
+
cpu0Version: VexFirmwareVersion.allZero(),
|
|
4458
|
+
cpu1Version: VexFirmwareVersion.allZero(),
|
|
4459
|
+
isAvailable: false,
|
|
4460
|
+
settings: {
|
|
4461
|
+
isScreenReversed: false,
|
|
4462
|
+
isWhiteTheme: false,
|
|
4463
|
+
usingLanguage: 0
|
|
4464
|
+
},
|
|
4465
|
+
systemVersion: VexFirmwareVersion.allZero(),
|
|
4466
|
+
uniqueId: 0
|
|
4467
|
+
};
|
|
4468
|
+
controllers = [
|
|
4469
|
+
{
|
|
4470
|
+
battery: 0,
|
|
4471
|
+
isAvailable: false,
|
|
4472
|
+
isCharging: false
|
|
4473
|
+
},
|
|
4474
|
+
{
|
|
4475
|
+
battery: 0,
|
|
4476
|
+
isAvailable: false
|
|
4477
|
+
}
|
|
4478
|
+
];
|
|
4479
|
+
devices = [];
|
|
4480
|
+
isFieldControllerConnected = false;
|
|
4481
|
+
matchMode = "disabled";
|
|
4482
|
+
radio = {
|
|
4483
|
+
channel: 0,
|
|
4484
|
+
isAvailable: false,
|
|
4485
|
+
isConnected: false,
|
|
4486
|
+
isVexNet: false,
|
|
4487
|
+
isRadioData: false,
|
|
4488
|
+
latency: 0,
|
|
4489
|
+
signalQuality: 0,
|
|
4490
|
+
signalStrength: 0
|
|
4491
|
+
};
|
|
4492
|
+
constructor(instance) {
|
|
4493
|
+
this._instance = instance;
|
|
4494
|
+
}
|
|
4495
|
+
}
|
|
4496
|
+
|
|
4497
|
+
class V5Brain {
|
|
4498
|
+
state;
|
|
4499
|
+
constructor(state) {
|
|
4500
|
+
this.state = state;
|
|
4501
|
+
}
|
|
4502
|
+
get isRunningProgram() {
|
|
4503
|
+
return this.activeProgram !== 0;
|
|
4504
|
+
}
|
|
4505
|
+
get activeProgram() {
|
|
4506
|
+
return this.state.brain.activeProgram;
|
|
4507
|
+
}
|
|
4508
|
+
set activeProgram(value) {
|
|
4509
|
+
(async () => {
|
|
4510
|
+
if (this.state.brain.activeProgram === value)
|
|
4511
|
+
return;
|
|
4512
|
+
const conn = this.state._instance.connection;
|
|
4513
|
+
if (conn == null)
|
|
4514
|
+
return;
|
|
4515
|
+
const fn = value === 0 ? await conn.stopProgram() : await conn.loadProgram(value);
|
|
4516
|
+
if (fn != null)
|
|
4517
|
+
this.state.brain.activeProgram = value;
|
|
4518
|
+
})();
|
|
4519
|
+
}
|
|
4520
|
+
get battery() {
|
|
4521
|
+
return new V5Battery(this.state);
|
|
4522
|
+
}
|
|
4523
|
+
get button() {
|
|
4524
|
+
return new V5BrainButton(this.state);
|
|
4525
|
+
}
|
|
4526
|
+
get cpu0Version() {
|
|
4527
|
+
return this.state.brain.cpu0Version;
|
|
4528
|
+
}
|
|
4529
|
+
get cpu1Version() {
|
|
4530
|
+
return this.state.brain.cpu1Version;
|
|
4531
|
+
}
|
|
4532
|
+
get isAvailable() {
|
|
4533
|
+
return this.state.brain.isAvailable;
|
|
4534
|
+
}
|
|
4535
|
+
get settings() {
|
|
4536
|
+
return new V5BrainSettings(this.state);
|
|
4537
|
+
}
|
|
4538
|
+
get systemVersion() {
|
|
4539
|
+
return this.state.brain.systemVersion;
|
|
4540
|
+
}
|
|
4541
|
+
get uniqueId() {
|
|
4542
|
+
return this.state.brain.uniqueId;
|
|
4543
|
+
}
|
|
4544
|
+
async getValue(key) {
|
|
4545
|
+
const result = await this.state._instance.connection?.writeDataAsync(new ReadKeyValueH2DPacket(key));
|
|
4546
|
+
return result instanceof ReadKeyValueReplyD2HPacket ? result.value : undefined;
|
|
4547
|
+
}
|
|
4548
|
+
async setValue(key, value) {
|
|
4549
|
+
const result = await this.state._instance.connection?.writeDataAsync(new WriteKeyValueH2DPacket(key, value));
|
|
4550
|
+
return result instanceof WriteKeyValueReplyD2HPacket;
|
|
4551
|
+
}
|
|
4552
|
+
async listFiles(vendor = 1 /* USER */) {
|
|
4553
|
+
const conn = this.state._instance.connection;
|
|
4554
|
+
if (conn == null || !conn.isConnected)
|
|
4555
|
+
return;
|
|
4556
|
+
const result = await conn.writeDataAsync(new GetDirectoryFileCountH2DPacket(vendor));
|
|
4557
|
+
if (!(result instanceof GetDirectoryFileCountReplyD2HPacket))
|
|
4558
|
+
return;
|
|
4559
|
+
const files = [];
|
|
4560
|
+
for (let i = 0;i < result.count; i++) {
|
|
4561
|
+
const result2 = await conn.writeDataAsync(new GetDirectoryEntryH2DPacket(i));
|
|
4562
|
+
if (!(result2 instanceof GetDirectoryEntryReplyD2HPacket))
|
|
4563
|
+
return;
|
|
4564
|
+
if (result2.file != null) {
|
|
4565
|
+
files.push({
|
|
4566
|
+
filename: result2.file.filename,
|
|
4567
|
+
vendor,
|
|
4568
|
+
loadAddress: result2.file.loadAddress,
|
|
4569
|
+
size: result2.file.size,
|
|
4570
|
+
crc32: result2.file.crc32,
|
|
4571
|
+
type: result2.file.type,
|
|
4572
|
+
timestamp: result2.file.timestamp,
|
|
4573
|
+
version: result2.file.version
|
|
4574
|
+
});
|
|
4575
|
+
}
|
|
4576
|
+
}
|
|
4577
|
+
return files;
|
|
4578
|
+
}
|
|
4579
|
+
async listProgram() {
|
|
4580
|
+
const conn = this.state._instance.connection;
|
|
4581
|
+
if (conn == null || !conn.isConnected)
|
|
4582
|
+
return;
|
|
4583
|
+
const files = await this.listFiles(1 /* USER */);
|
|
4584
|
+
if (files === undefined)
|
|
4585
|
+
return;
|
|
4586
|
+
const programList = [];
|
|
4587
|
+
const iniFiles = files.filter((file) => file?.filename.search(/.ini$/) > 0);
|
|
4588
|
+
for (let i = 0;i < iniFiles.length; i++) {
|
|
4589
|
+
const ini = iniFiles[i];
|
|
4590
|
+
if (ini.size === 0)
|
|
4591
|
+
continue;
|
|
4592
|
+
const programName = /(.+?)(\.[^.]*$|$)/.exec(ini.filename)?.[1] ?? "";
|
|
4593
|
+
const bin = files.filter((e) => e != null && e.filename === programName + ".bin")[0];
|
|
4594
|
+
if (bin == null || bin.timestamp === 0 || bin.size === 0)
|
|
4595
|
+
continue;
|
|
4596
|
+
const n = new Date;
|
|
4597
|
+
n.setTime(1000 * bin.timestamp);
|
|
4598
|
+
const program2 = {
|
|
4599
|
+
name: programName,
|
|
4600
|
+
binfile: bin.filename,
|
|
4601
|
+
size: ini.size + bin.size,
|
|
4602
|
+
slot: -1,
|
|
4603
|
+
time: n,
|
|
4604
|
+
requestedSlot: -1
|
|
4605
|
+
};
|
|
4606
|
+
const result2 = await conn?.writeDataAsync(new GetProgramSlotInfoH2DPacket(1 /* USER */, program2.binfile));
|
|
4607
|
+
if (result2 instanceof GetProgramSlotInfoReplyD2HPacket) {
|
|
4608
|
+
program2.slot = result2.slot;
|
|
4609
|
+
program2.requestedSlot = result2.requestedSlot;
|
|
4610
|
+
}
|
|
4611
|
+
programList.push(program2);
|
|
4612
|
+
}
|
|
4613
|
+
return programList;
|
|
4614
|
+
}
|
|
4615
|
+
async readFile(request, downloadTarget = 1 /* FILE_TARGET_QSPI */, progressCallback) {
|
|
4616
|
+
const conn = this.state._instance.connection;
|
|
4617
|
+
if (conn == null || !conn.isConnected)
|
|
4618
|
+
return;
|
|
4619
|
+
this.state._isFileTransferring = true;
|
|
4620
|
+
let handle;
|
|
4621
|
+
if (typeof request === "string") {
|
|
4622
|
+
handle = { filename: request, vendor: 1 /* USER */ };
|
|
4623
|
+
} else {
|
|
4624
|
+
handle = request;
|
|
4625
|
+
}
|
|
4626
|
+
try {
|
|
4627
|
+
return await conn.downloadFileToHost(handle, downloadTarget, progressCallback);
|
|
4628
|
+
} catch (e) {
|
|
4629
|
+
this.state._isFileTransferring = false;
|
|
4630
|
+
throw e;
|
|
4631
|
+
}
|
|
4632
|
+
}
|
|
4633
|
+
async removeFile(request) {
|
|
4634
|
+
const conn = this.state._instance.connection;
|
|
4635
|
+
if (conn == null || !conn.isConnected)
|
|
4636
|
+
return;
|
|
4637
|
+
let vendor, filename;
|
|
4638
|
+
if (typeof request === "string") {
|
|
4639
|
+
vendor = 1 /* USER */;
|
|
4640
|
+
filename = request;
|
|
4641
|
+
} else {
|
|
4642
|
+
vendor = request.vendor;
|
|
4643
|
+
filename = request.filename;
|
|
4644
|
+
}
|
|
4645
|
+
const result = await conn.writeDataAsync(new EraseFileH2DPacket(vendor, filename));
|
|
4646
|
+
const result2 = await conn.writeDataAsync(new ExitFileTransferH2DPacket(3 /* EXIT_HALT */));
|
|
4647
|
+
if (!(result instanceof EraseFileReplyD2HPacket))
|
|
4648
|
+
return false;
|
|
4649
|
+
if (!(result2 instanceof ExitFileTransferReplyD2HPacket))
|
|
4650
|
+
return false;
|
|
4651
|
+
return true;
|
|
4652
|
+
}
|
|
4653
|
+
async removeAllFiles() {
|
|
4654
|
+
const conn = this.state._instance.connection;
|
|
4655
|
+
if (conn == null || !conn.isConnected)
|
|
4656
|
+
return;
|
|
4657
|
+
const result = await conn.writeDataAsync(new FileClearUpH2DPacket(1 /* USER */), 30000);
|
|
4658
|
+
return result instanceof FileClearUpReplyD2HPacket;
|
|
4659
|
+
}
|
|
4660
|
+
async uploadFirmware(publicUrl = "https://content.vexrobotics.com/vexos/public/V5/", usingVersion, progressCallback) {
|
|
4661
|
+
const device = this.state._instance;
|
|
4662
|
+
const conn = device.connection;
|
|
4663
|
+
if (conn == null || !conn.isConnected)
|
|
4664
|
+
return;
|
|
4665
|
+
const pcb = progressCallback ?? (() => {});
|
|
4666
|
+
let vexos, bootBin, assertBin;
|
|
4667
|
+
try {
|
|
4668
|
+
if (usingVersion === undefined) {
|
|
4669
|
+
pcb("FETCH CATALOG", 0, 1);
|
|
4670
|
+
const catalog = await downloadFileFromInternet(publicUrl + "catalog.txt");
|
|
4671
|
+
const latestVersion = new TextDecoder().decode(catalog);
|
|
4672
|
+
usingVersion = latestVersion;
|
|
4673
|
+
pcb("FETCH CATALOG", 1, 1);
|
|
4674
|
+
console.log("fetched catalog.txt", latestVersion);
|
|
4675
|
+
}
|
|
4676
|
+
pcb("FETCH VEXOS", 0, 1);
|
|
4677
|
+
vexos = await downloadFileFromInternet(publicUrl + usingVersion + ".vexos");
|
|
4678
|
+
pcb("FETCH VEXOS", 1, 1);
|
|
4679
|
+
pcb("UNZIP VEXOS", 0, 1);
|
|
4680
|
+
const { unzip } = await import("unzipit");
|
|
4681
|
+
const { entries } = await unzip(vexos);
|
|
4682
|
+
bootBin = await entries[usingVersion + "/BOOT.bin"].arrayBuffer();
|
|
4683
|
+
assertBin = await entries[usingVersion + "/assets.bin"].arrayBuffer();
|
|
4684
|
+
pcb("UNZIP VEXOS", 1, 1);
|
|
4685
|
+
} catch (e) {
|
|
4686
|
+
return;
|
|
4687
|
+
}
|
|
4688
|
+
try {
|
|
4689
|
+
this.state._isFileTransferring = true;
|
|
4690
|
+
pcb("FACTORY ENB BOOT", 0, 0);
|
|
4691
|
+
const result = await conn.writeDataAsync(new FactoryEnableH2DPacket);
|
|
4692
|
+
if (!(result instanceof FactoryEnableReplyD2HPacket))
|
|
4693
|
+
return false;
|
|
4694
|
+
const bootWriteRequest = {
|
|
4695
|
+
filename: "null.bin",
|
|
4696
|
+
vendor: 1 /* USER */,
|
|
4697
|
+
loadAddress: USER_FLASH_USR_CODE_START,
|
|
4698
|
+
buf: new Uint8Array(bootBin),
|
|
4699
|
+
downloadTarget: 14 /* FILE_TARGET_B1 */,
|
|
4700
|
+
exttype: "bin",
|
|
4701
|
+
autoRun: true,
|
|
4702
|
+
linkedFile: undefined
|
|
4703
|
+
};
|
|
4704
|
+
const result2 = await conn.uploadFileToDevice(bootWriteRequest, (c, t) => {
|
|
4705
|
+
pcb("UPLOAD BOOT", c, t);
|
|
4706
|
+
});
|
|
4707
|
+
if (!result2)
|
|
4708
|
+
return false;
|
|
4709
|
+
while (true) {
|
|
4710
|
+
const result3 = await conn.writeDataAsync(new FactoryStatusH2DPacket, 1e4);
|
|
4711
|
+
if (result3 instanceof FactoryStatusReplyD2HPacket) {
|
|
4712
|
+
switch (result3.status) {
|
|
4713
|
+
case 2:
|
|
4714
|
+
pcb("ERASE BOOT", result3.percent, 100);
|
|
4715
|
+
break;
|
|
4716
|
+
case 3:
|
|
4717
|
+
pcb("WRITE BOOT", result3.percent, 100);
|
|
4718
|
+
break;
|
|
4719
|
+
case 4:
|
|
4720
|
+
pcb("VERIFY BOOT", result3.percent, 100);
|
|
4721
|
+
break;
|
|
4722
|
+
case 8:
|
|
4723
|
+
pcb("FINISHING BOOT", result3.percent, 100);
|
|
4724
|
+
break;
|
|
4725
|
+
}
|
|
4726
|
+
if (result3.status === 0 && result3.percent === 100)
|
|
4727
|
+
break;
|
|
4728
|
+
} else {
|
|
4729
|
+
return false;
|
|
4730
|
+
}
|
|
4731
|
+
await sleep(500);
|
|
4732
|
+
}
|
|
4733
|
+
pcb("FACTORY ENB ASSERT", 0, 0);
|
|
4734
|
+
const result5 = await conn.writeDataAsync(new FactoryEnableH2DPacket);
|
|
4735
|
+
if (!(result5 instanceof FactoryEnableReplyD2HPacket))
|
|
4736
|
+
return false;
|
|
4737
|
+
const assertWriteRequest = {
|
|
4738
|
+
filename: "null.bin",
|
|
4739
|
+
vendor: 1 /* USER */,
|
|
4740
|
+
loadAddress: USER_FLASH_USR_CODE_START,
|
|
4741
|
+
buf: new Uint8Array(assertBin),
|
|
4742
|
+
downloadTarget: 13 /* FILE_TARGET_A1 */,
|
|
4743
|
+
exttype: "bin",
|
|
4744
|
+
autoRun: true,
|
|
4745
|
+
linkedFile: undefined
|
|
4746
|
+
};
|
|
4747
|
+
const result6 = await conn.uploadFileToDevice(assertWriteRequest, (c, t) => {
|
|
4748
|
+
pcb("UPLOAD ASSERT", c, t);
|
|
4749
|
+
});
|
|
4750
|
+
if (!result6)
|
|
4751
|
+
return false;
|
|
4752
|
+
while (true) {
|
|
4753
|
+
const result7 = await conn.writeDataAsync(new FactoryStatusH2DPacket, 1e4);
|
|
4754
|
+
if (result7 instanceof FactoryStatusReplyD2HPacket) {
|
|
4755
|
+
switch (result7.status) {
|
|
4756
|
+
case 2:
|
|
4757
|
+
pcb("ERASE ASSERT", result7.percent, 100);
|
|
4758
|
+
break;
|
|
4759
|
+
case 3:
|
|
4760
|
+
pcb("WRITE ASSERT", result7.percent, 100);
|
|
4761
|
+
break;
|
|
4762
|
+
case 4:
|
|
4763
|
+
pcb("VERIFY ASSERT", result7.percent, 100);
|
|
4764
|
+
break;
|
|
4765
|
+
case 8:
|
|
4766
|
+
pcb("FINISHING ASSERT", result7.percent, 100);
|
|
4767
|
+
break;
|
|
4768
|
+
}
|
|
4769
|
+
if (result7.status === 0 && result7.percent === 100)
|
|
4770
|
+
break;
|
|
4771
|
+
} else {
|
|
4772
|
+
return false;
|
|
4773
|
+
}
|
|
4774
|
+
await sleep(500);
|
|
4775
|
+
}
|
|
4776
|
+
} catch (e) {
|
|
4777
|
+
this.state._isFileTransferring = false;
|
|
4778
|
+
throw e;
|
|
4779
|
+
}
|
|
4780
|
+
return true;
|
|
4781
|
+
}
|
|
4782
|
+
async uploadProgram(iniConfig, binFileBuf, coldFileBuf, progressCallback) {
|
|
4783
|
+
const device = this.state._instance;
|
|
4784
|
+
const conn = device.connection;
|
|
4785
|
+
if (conn == null || !conn.isConnected)
|
|
4786
|
+
return;
|
|
4787
|
+
this.state._isFileTransferring = true;
|
|
4788
|
+
try {
|
|
4789
|
+
if (device.isV5Controller) {
|
|
4790
|
+
await sleep(250);
|
|
4791
|
+
if (!await device.refresh())
|
|
4792
|
+
return;
|
|
4793
|
+
console.log("Transferring to download channel");
|
|
4794
|
+
const p1 = await device.radio.changeChannel(1 /* DOWNLOAD */);
|
|
4795
|
+
if (!p1)
|
|
4796
|
+
return false;
|
|
4797
|
+
await sleep(250);
|
|
4798
|
+
await sleepUntilAsync(async () => await conn?.getSystemStatus(150) != null, 1e4, 200);
|
|
4799
|
+
console.log("Transferred to download channel");
|
|
4800
|
+
}
|
|
4801
|
+
const p2 = await conn.uploadProgramToDevice(iniConfig, binFileBuf, coldFileBuf, progressCallback);
|
|
4802
|
+
if (!(p2 ?? false))
|
|
4803
|
+
return false;
|
|
4804
|
+
if (device.isV5Controller) {
|
|
4805
|
+
if (!device.brain.isAvailable)
|
|
4806
|
+
return false;
|
|
4807
|
+
console.log("Transferring back to pit channel");
|
|
4808
|
+
const p3 = await device.radio.changeChannel(0 /* PIT */);
|
|
4809
|
+
if (!p3)
|
|
4810
|
+
return false;
|
|
4811
|
+
await sleep(250);
|
|
4812
|
+
await sleepUntilAsync(async () => await conn?.getSystemStatus(150) != null, 1e4, 200);
|
|
4813
|
+
console.log("All done");
|
|
4814
|
+
}
|
|
4815
|
+
return true;
|
|
4816
|
+
} catch (e) {
|
|
4817
|
+
this.state._isFileTransferring = false;
|
|
4818
|
+
throw e;
|
|
4819
|
+
}
|
|
4820
|
+
}
|
|
4821
|
+
async writeFile(request, progressCallback) {
|
|
4822
|
+
this.state._isFileTransferring = true;
|
|
4823
|
+
const conn = this.state._instance.connection;
|
|
4824
|
+
if (conn == null || !conn.isConnected)
|
|
4825
|
+
return;
|
|
4826
|
+
try {
|
|
4827
|
+
return await conn.uploadFileToDevice(request, progressCallback);
|
|
4828
|
+
} catch (e) {
|
|
4829
|
+
this.state._isFileTransferring = false;
|
|
4830
|
+
throw e;
|
|
4831
|
+
}
|
|
4832
|
+
}
|
|
4833
|
+
async captureScreen(progressCallback) {
|
|
4834
|
+
const conn = this.state._instance.connection;
|
|
4835
|
+
if (conn == null || !conn.isConnected)
|
|
4836
|
+
return;
|
|
4837
|
+
await new Promise((resolve) => {
|
|
4838
|
+
conn.writeData(new ScreenCaptureH2DPacket(0), resolve);
|
|
4839
|
+
});
|
|
4840
|
+
const height = 272;
|
|
4841
|
+
const width = 480;
|
|
4842
|
+
const channels = 3;
|
|
4843
|
+
const messageWidth = 512;
|
|
4844
|
+
const messageChannels = 4;
|
|
4845
|
+
let buf = await conn?.downloadFileToHost({
|
|
4846
|
+
filename: "screen",
|
|
4847
|
+
vendor: 15 /* SYS */,
|
|
4848
|
+
loadAddress: 0,
|
|
4849
|
+
size: messageWidth * height * messageChannels
|
|
4850
|
+
}, 2 /* FILE_TARGET_CBUF */, progressCallback);
|
|
4851
|
+
if (buf == null)
|
|
4852
|
+
return;
|
|
4853
|
+
buf = buf.filter((_byte, i) => i % (messageWidth * messageChannels) < width * messageChannels).filter((_byte, i) => (i + 1) % messageChannels !== 0);
|
|
4854
|
+
for (let i = 0;i < buf.length; i += channels) {
|
|
4855
|
+
const px = buf.slice(i, i + channels).reverse();
|
|
4856
|
+
for (let j = 0;j < px.length; j++) {
|
|
4857
|
+
buf[i + j] = px[j];
|
|
4858
|
+
}
|
|
4859
|
+
}
|
|
4860
|
+
return buf;
|
|
4861
|
+
}
|
|
4862
|
+
}
|
|
4863
|
+
|
|
4864
|
+
class V5Battery {
|
|
4865
|
+
state;
|
|
4866
|
+
constructor(state) {
|
|
4867
|
+
this.state = state;
|
|
4868
|
+
}
|
|
4869
|
+
get batteryPercent() {
|
|
4870
|
+
return this.state.brain.battery.batteryPercent;
|
|
4871
|
+
}
|
|
4872
|
+
get isCharging() {
|
|
4873
|
+
return this.state.brain.battery.isCharging;
|
|
4874
|
+
}
|
|
4875
|
+
}
|
|
4876
|
+
|
|
4877
|
+
class V5BrainButton {
|
|
4878
|
+
state;
|
|
4879
|
+
constructor(state) {
|
|
4880
|
+
this.state = state;
|
|
4881
|
+
}
|
|
4882
|
+
get isPressed() {
|
|
4883
|
+
return this.state.brain.button.isPressed;
|
|
4884
|
+
}
|
|
4885
|
+
get isDoublePressed() {
|
|
4886
|
+
return this.state.brain.button.isDoublePressed;
|
|
4887
|
+
}
|
|
4888
|
+
}
|
|
4889
|
+
|
|
4890
|
+
class V5BrainSettings {
|
|
4891
|
+
state;
|
|
4892
|
+
constructor(state) {
|
|
4893
|
+
this.state = state;
|
|
4894
|
+
}
|
|
4895
|
+
get isScreenReversed() {
|
|
4896
|
+
return this.state.brain.settings.isScreenReversed;
|
|
4897
|
+
}
|
|
4898
|
+
get isWhiteTheme() {
|
|
4899
|
+
return this.state.brain.settings.isWhiteTheme;
|
|
4900
|
+
}
|
|
4901
|
+
get usingLanguage() {
|
|
4902
|
+
return this.state.brain.settings.usingLanguage;
|
|
4903
|
+
}
|
|
4904
|
+
}
|
|
4905
|
+
|
|
4906
|
+
class V5Controller {
|
|
4907
|
+
state;
|
|
4908
|
+
controllerIndex;
|
|
4909
|
+
constructor(state, controllerIndex) {
|
|
4910
|
+
this.state = state;
|
|
4911
|
+
this.controllerIndex = controllerIndex;
|
|
4912
|
+
}
|
|
4913
|
+
get batteryPercent() {
|
|
4914
|
+
return this.state.controllers[this.controllerIndex].battery;
|
|
4915
|
+
}
|
|
4916
|
+
get isMasterController() {
|
|
4917
|
+
return this.controllerIndex === 0;
|
|
4918
|
+
}
|
|
4919
|
+
get isAvailable() {
|
|
4920
|
+
return this.state.controllers[this.controllerIndex].isAvailable;
|
|
4921
|
+
}
|
|
4922
|
+
get isCharging() {
|
|
4923
|
+
return this.state.controllers[this.controllerIndex].isCharging;
|
|
4924
|
+
}
|
|
4925
|
+
}
|
|
4926
|
+
|
|
4927
|
+
class V5SmartDevice {
|
|
4928
|
+
state;
|
|
4929
|
+
deviceIndex;
|
|
4930
|
+
constructor(state, index) {
|
|
4931
|
+
this.state = state;
|
|
4932
|
+
this.deviceIndex = index;
|
|
4933
|
+
}
|
|
4934
|
+
getDeviceInfo() {
|
|
4935
|
+
return this.state.devices[this.deviceIndex];
|
|
4936
|
+
}
|
|
4937
|
+
get isAvailable() {
|
|
4938
|
+
return this.getDeviceInfo() !== undefined;
|
|
4939
|
+
}
|
|
4940
|
+
get port() {
|
|
4941
|
+
return this.deviceIndex;
|
|
4942
|
+
}
|
|
4943
|
+
get type() {
|
|
4944
|
+
return this.getDeviceInfo()?.type ?? 0 /* EMPTY */;
|
|
4945
|
+
}
|
|
4946
|
+
get version() {
|
|
4947
|
+
return this.getDeviceInfo()?.version ?? 0;
|
|
4948
|
+
}
|
|
4949
|
+
}
|
|
4950
|
+
|
|
4951
|
+
class V5Radio {
|
|
4952
|
+
state;
|
|
4953
|
+
constructor(state) {
|
|
4954
|
+
this.state = state;
|
|
4955
|
+
}
|
|
4956
|
+
get channel() {
|
|
4957
|
+
return this.state.radio.channel;
|
|
4958
|
+
}
|
|
4959
|
+
get isAvailable() {
|
|
4960
|
+
return this.state.radio.isAvailable;
|
|
4961
|
+
}
|
|
4962
|
+
get isConnected() {
|
|
4963
|
+
return this.state.radio.isConnected;
|
|
4964
|
+
}
|
|
4965
|
+
get isVexNet() {
|
|
4966
|
+
return this.state.radio.isVexNet;
|
|
4967
|
+
}
|
|
4968
|
+
get isRadioData() {
|
|
4969
|
+
return this.state.radio.isRadioData;
|
|
4970
|
+
}
|
|
4971
|
+
get latency() {
|
|
4972
|
+
return this.state.radio.latency;
|
|
4973
|
+
}
|
|
4974
|
+
async changeChannel(channel) {
|
|
4975
|
+
const result = await this.state._instance.connection?.writeDataAsync(new FileControlH2DPacket(1, channel));
|
|
4976
|
+
return result instanceof FileControlReplyD2HPacket;
|
|
4977
|
+
}
|
|
4978
|
+
}
|
|
4979
|
+
|
|
4980
|
+
class V5SerialDevice extends VexSerialDevice {
|
|
4981
|
+
autoReconnect = true;
|
|
4982
|
+
autoRefresh = true;
|
|
4983
|
+
pauseRefreshOnFileTransfer = true;
|
|
4984
|
+
_isReconnecting = false;
|
|
4985
|
+
_refreshInterval;
|
|
4986
|
+
state = new V5SerialDeviceState(this);
|
|
4987
|
+
constructor(defaultSerial) {
|
|
4988
|
+
super(defaultSerial);
|
|
4989
|
+
let isLastRefreshComplete = true;
|
|
4990
|
+
this._refreshInterval = setInterval(() => {
|
|
4991
|
+
if (this.autoRefresh && isLastRefreshComplete) {
|
|
4992
|
+
if (!this.isConnected) {
|
|
4993
|
+
this.state.brain.isAvailable = false;
|
|
4994
|
+
return;
|
|
4995
|
+
}
|
|
4996
|
+
if (!this.pauseRefreshOnFileTransfer || !this.state._isFileTransferring) {
|
|
4997
|
+
isLastRefreshComplete = false;
|
|
4998
|
+
this.refresh().finally(() => isLastRefreshComplete = true);
|
|
4999
|
+
}
|
|
5000
|
+
}
|
|
5001
|
+
}, 200);
|
|
5002
|
+
}
|
|
5003
|
+
get isV5Controller() {
|
|
5004
|
+
return this.deviceType === 1283 /* V5_CONTROLLER */;
|
|
5005
|
+
}
|
|
5006
|
+
get brain() {
|
|
5007
|
+
return new V5Brain(this.state);
|
|
5008
|
+
}
|
|
5009
|
+
get controllers() {
|
|
5010
|
+
return [new V5Controller(this.state, 0), new V5Controller(this.state, 1)];
|
|
5011
|
+
}
|
|
5012
|
+
get devices() {
|
|
5013
|
+
const rtn = [];
|
|
5014
|
+
for (let i = 1;i <= this.state.devices.length; i++) {
|
|
5015
|
+
if (this.state.devices[i] != null)
|
|
5016
|
+
rtn.push(new V5SmartDevice(this.state, i));
|
|
5017
|
+
}
|
|
5018
|
+
return rtn;
|
|
5019
|
+
}
|
|
5020
|
+
get isFieldControllerConnected() {
|
|
5021
|
+
return this.state.isFieldControllerConnected;
|
|
5022
|
+
}
|
|
5023
|
+
get matchMode() {
|
|
5024
|
+
return this.state.matchMode;
|
|
5025
|
+
}
|
|
5026
|
+
set matchMode(value) {
|
|
5027
|
+
(async () => {
|
|
5028
|
+
if (await this.connection?.setMatchMode(value) != null)
|
|
5029
|
+
this.state.matchMode = value;
|
|
5030
|
+
})();
|
|
5031
|
+
}
|
|
5032
|
+
get radio() {
|
|
5033
|
+
return new V5Radio(this.state);
|
|
5034
|
+
}
|
|
5035
|
+
async mockTouch(x, y, press) {
|
|
5036
|
+
return !(await this.connection?.mockTouch(x, y, press) == null);
|
|
5037
|
+
}
|
|
5038
|
+
async connect(conn) {
|
|
5039
|
+
if (this.isConnected)
|
|
5040
|
+
return true;
|
|
5041
|
+
if (conn != null && !conn.isConnected) {
|
|
5042
|
+
if (await conn.query1() === null)
|
|
5043
|
+
return false;
|
|
5044
|
+
this.connection = conn;
|
|
5045
|
+
} else {
|
|
5046
|
+
let tryIdx = 0;
|
|
5047
|
+
while (true) {
|
|
5048
|
+
const c = new V5SerialConnection(this.defaultSerial);
|
|
5049
|
+
const result = await c.open(tryIdx++, true);
|
|
5050
|
+
if (result === undefined)
|
|
5051
|
+
return false;
|
|
5052
|
+
if (!result) {
|
|
5053
|
+
await c.close();
|
|
5054
|
+
continue;
|
|
5055
|
+
}
|
|
5056
|
+
if (await c.query1() === null) {
|
|
5057
|
+
await c.close();
|
|
5058
|
+
continue;
|
|
5059
|
+
}
|
|
5060
|
+
this.connection = c;
|
|
5061
|
+
break;
|
|
5062
|
+
}
|
|
5063
|
+
}
|
|
5064
|
+
if (!this.isConnected)
|
|
5065
|
+
return false;
|
|
5066
|
+
await this.doAfterConnect();
|
|
5067
|
+
return true;
|
|
5068
|
+
}
|
|
5069
|
+
async disconnect() {
|
|
5070
|
+
await this.connection?.close();
|
|
5071
|
+
this.connection = undefined;
|
|
5072
|
+
}
|
|
5073
|
+
async dispose() {
|
|
5074
|
+
this.autoReconnect = false;
|
|
5075
|
+
this.autoRefresh = false;
|
|
5076
|
+
clearInterval(this._refreshInterval);
|
|
5077
|
+
await this.disconnect();
|
|
5078
|
+
}
|
|
5079
|
+
async reconnect(timeout = 0) {
|
|
5080
|
+
if (this.isConnected)
|
|
5081
|
+
return true;
|
|
5082
|
+
if (timeout < 0)
|
|
5083
|
+
return false;
|
|
5084
|
+
const endTime = new Date().getTime() + timeout;
|
|
5085
|
+
if (this._isReconnecting) {
|
|
5086
|
+
let successBeforeTimeout;
|
|
5087
|
+
do {
|
|
5088
|
+
successBeforeTimeout = await sleepUntil(() => !this._isReconnecting, timeout === 0 ? 1000 : timeout);
|
|
5089
|
+
} while (timeout === 0 && !successBeforeTimeout);
|
|
5090
|
+
if (this.isConnected)
|
|
5091
|
+
return true;
|
|
5092
|
+
if (!successBeforeTimeout)
|
|
5093
|
+
return false;
|
|
5094
|
+
}
|
|
5095
|
+
this._isReconnecting = true;
|
|
5096
|
+
while (timeout === 0 || new Date().getTime() < endTime) {
|
|
5097
|
+
let tryIdx = 0;
|
|
5098
|
+
while (true) {
|
|
5099
|
+
const c = new V5SerialConnection(this.defaultSerial);
|
|
5100
|
+
const result = await c.open(tryIdx++, false);
|
|
5101
|
+
if (result === undefined)
|
|
5102
|
+
break;
|
|
5103
|
+
if (!result) {
|
|
5104
|
+
await c.close();
|
|
5105
|
+
continue;
|
|
5106
|
+
}
|
|
5107
|
+
const result2 = await c.getSystemStatus(200);
|
|
5108
|
+
if (result2 === null) {
|
|
5109
|
+
await c.close();
|
|
5110
|
+
continue;
|
|
5111
|
+
}
|
|
5112
|
+
if (this.brain.uniqueId !== 0 && result2.uniqueId !== this.brain.uniqueId) {
|
|
5113
|
+
await c.close();
|
|
5114
|
+
continue;
|
|
5115
|
+
}
|
|
5116
|
+
this.connection = c;
|
|
5117
|
+
break;
|
|
5118
|
+
}
|
|
5119
|
+
if (this.isConnected)
|
|
5120
|
+
break;
|
|
5121
|
+
const getPortCount = async () => (await this.defaultSerial.getPorts()).length;
|
|
5122
|
+
const portsCount = await getPortCount();
|
|
5123
|
+
await sleepUntilAsync(async () => await getPortCount() !== portsCount, 1000);
|
|
5124
|
+
}
|
|
5125
|
+
this._isReconnecting = false;
|
|
5126
|
+
if (!this.isConnected)
|
|
5127
|
+
return false;
|
|
5128
|
+
this.doAfterConnect();
|
|
5129
|
+
return true;
|
|
5130
|
+
}
|
|
5131
|
+
async doAfterConnect() {
|
|
5132
|
+
if (this.connection == null)
|
|
5133
|
+
return;
|
|
5134
|
+
this.connection.on("disconnected", (_data) => {
|
|
5135
|
+
if (this.autoReconnect)
|
|
5136
|
+
this.reconnect();
|
|
5137
|
+
});
|
|
5138
|
+
await this.refresh();
|
|
5139
|
+
}
|
|
5140
|
+
async refresh() {
|
|
5141
|
+
const ssPacket = await this.connection?.getSystemStatus();
|
|
5142
|
+
if (ssPacket == null) {
|
|
5143
|
+
this.state.brain.isAvailable = false;
|
|
5144
|
+
return false;
|
|
5145
|
+
}
|
|
5146
|
+
this.state.brain.cpu0Version = ssPacket.cpu0Version;
|
|
5147
|
+
this.state.brain.cpu1Version = ssPacket.cpu1Version;
|
|
5148
|
+
this.state.brain.systemVersion = ssPacket.systemVersion;
|
|
5149
|
+
const flags2 = ssPacket.sysflags[2];
|
|
5150
|
+
this.state.controllers[0].isCharging = (flags2 & 128) !== 0;
|
|
5151
|
+
this.state.matchMode = (flags2 & 32) !== 0 ? "disabled" : (flags2 & 64) !== 0 ? "autonomous" : "driver";
|
|
5152
|
+
this.state.isFieldControllerConnected = (flags2 & 16) !== 0;
|
|
5153
|
+
const flags4 = ssPacket.sysflags[4];
|
|
5154
|
+
this.state.brain.settings.usingLanguage = (flags4 & 240) >> 4;
|
|
5155
|
+
this.state.brain.settings.isWhiteTheme = (flags4 & 4) !== 0;
|
|
5156
|
+
this.state.brain.settings.isScreenReversed = (flags4 & 1) === 0;
|
|
5157
|
+
this.state.brain.uniqueId = ssPacket.uniqueId;
|
|
5158
|
+
const sfPacket = await this.connection?.getSystemFlags();
|
|
5159
|
+
if (sfPacket == null)
|
|
5160
|
+
return false;
|
|
5161
|
+
const flags5 = sfPacket.flags;
|
|
5162
|
+
this.state.radio.isRadioData = (flags5 & Math.pow(2, 20)) !== 0;
|
|
5163
|
+
this.state.brain.button.isDoublePressed = (flags5 & Math.pow(2, 18)) !== 0;
|
|
5164
|
+
this.state.brain.battery.isCharging = (flags5 & Math.pow(2, 17)) !== 0;
|
|
5165
|
+
this.state.brain.button.isPressed = (flags5 & Math.pow(2, 15)) !== 0;
|
|
5166
|
+
this.state.radio.isVexNet = (flags5 & Math.pow(2, 14)) !== 0;
|
|
5167
|
+
this.state.controllers[1].isAvailable = (flags5 & Math.pow(2, 13)) !== 0;
|
|
5168
|
+
this.state.radio.isConnected = (flags5 & Math.pow(2, 10)) !== 0;
|
|
5169
|
+
this.state.radio.isAvailable = (flags5 & Math.pow(2, 9)) !== 0;
|
|
5170
|
+
this.state.brain.battery.batteryPercent = sfPacket.battery ?? 0;
|
|
5171
|
+
this.state.controllers[0].isAvailable = this.state.radio.isConnected || this.state.controllers[0].isCharging;
|
|
5172
|
+
this.state.controllers[0].battery = sfPacket.controllerBatteryPercent ?? 0;
|
|
5173
|
+
this.state.controllers[1].battery = sfPacket.partnerControllerBatteryPercent ?? 0;
|
|
5174
|
+
this.state.brain.activeProgram = sfPacket.currentProgram;
|
|
5175
|
+
this.state.brain.isAvailable = !this.isV5Controller || this.state.radio.isConnected;
|
|
5176
|
+
const rdPacket = await this.connection?.getRadioStatus();
|
|
5177
|
+
if (rdPacket == null)
|
|
5178
|
+
return false;
|
|
5179
|
+
this.state.radio.channel = rdPacket.channel;
|
|
5180
|
+
this.state.radio.latency = rdPacket.timeslot;
|
|
5181
|
+
this.state.radio.signalQuality = rdPacket.quality;
|
|
5182
|
+
this.state.radio.signalStrength = rdPacket.strength;
|
|
5183
|
+
const dsPacket = await this.connection?.getDeviceStatus();
|
|
5184
|
+
if (dsPacket == null)
|
|
5185
|
+
return false;
|
|
5186
|
+
let missingPorts = this.state.devices.map((d) => d?.port).filter((p) => p !== undefined);
|
|
5187
|
+
for (let i = 0;i < dsPacket.devices.length; i++) {
|
|
5188
|
+
const device = dsPacket.devices[i];
|
|
5189
|
+
this.state.devices[device.port] = device;
|
|
5190
|
+
missingPorts = missingPorts.filter((p) => p !== device.port);
|
|
5191
|
+
}
|
|
5192
|
+
missingPorts.forEach((port) => {
|
|
5193
|
+
this.state.devices[port] = undefined;
|
|
5194
|
+
});
|
|
5195
|
+
return true;
|
|
5196
|
+
}
|
|
5197
|
+
}
|
|
5198
|
+
// ../serial/src/VexIniConfig.ts
|
|
5199
|
+
class BaseIniBuilder {
|
|
5200
|
+
str = "";
|
|
5201
|
+
addLine(line) {
|
|
5202
|
+
this.str += line + `
|
|
5203
|
+
`;
|
|
5204
|
+
}
|
|
5205
|
+
addComment(comment) {
|
|
5206
|
+
this.addLine("; " + comment);
|
|
5207
|
+
return this;
|
|
5208
|
+
}
|
|
5209
|
+
getContent() {
|
|
5210
|
+
return this.str;
|
|
5211
|
+
}
|
|
5212
|
+
}
|
|
5213
|
+
|
|
5214
|
+
class IniSectionBuilder extends BaseIniBuilder {
|
|
5215
|
+
name;
|
|
5216
|
+
object;
|
|
5217
|
+
keyTransform;
|
|
5218
|
+
constructor(name, object, keyTransform = (k) => k.toString()) {
|
|
5219
|
+
super();
|
|
5220
|
+
this.name = name;
|
|
5221
|
+
this.object = object;
|
|
5222
|
+
this.keyTransform = keyTransform;
|
|
5223
|
+
}
|
|
5224
|
+
addSingleObjProperty(key, maxValueLength) {
|
|
5225
|
+
if (this.object[key] == null || this.object[key].toString().length === 0)
|
|
5226
|
+
return;
|
|
5227
|
+
const formattedKey = this.keyTransform(key).padEnd(12).slice(0, 12);
|
|
5228
|
+
const trimmedVal = this.object[key].toString().slice(0, maxValueLength);
|
|
5229
|
+
this.addLine(`${formattedKey} = "${trimmedVal}"`);
|
|
5230
|
+
}
|
|
5231
|
+
addObjProperty(key, maxValueLength) {
|
|
5232
|
+
const keys = Array.isArray(key) ? key : [key];
|
|
5233
|
+
for (const k of keys) {
|
|
5234
|
+
this.addSingleObjProperty(k, maxValueLength);
|
|
5235
|
+
}
|
|
5236
|
+
return this;
|
|
5237
|
+
}
|
|
5238
|
+
addAllObjProps(maxValueLength) {
|
|
5239
|
+
const keys = Object.keys(this.object);
|
|
5240
|
+
for (const k of keys) {
|
|
5241
|
+
this.addSingleObjProperty(k, maxValueLength);
|
|
5242
|
+
}
|
|
5243
|
+
return this;
|
|
5244
|
+
}
|
|
5245
|
+
}
|
|
5246
|
+
|
|
5247
|
+
class IniFileBuilder extends BaseIniBuilder {
|
|
5248
|
+
addSection(section) {
|
|
5249
|
+
this.addLine(`[${section.name}]`);
|
|
5250
|
+
this.str += section.getContent();
|
|
5251
|
+
return this;
|
|
5252
|
+
}
|
|
5253
|
+
}
|
|
5254
|
+
|
|
5255
|
+
class ProgramIniConfig {
|
|
5256
|
+
baseName = "slot_1";
|
|
5257
|
+
autorun = false;
|
|
5258
|
+
project = { version: "1", ide: "Unknown", file: "none" };
|
|
5259
|
+
program = {
|
|
5260
|
+
version: "1",
|
|
5261
|
+
name: "program",
|
|
5262
|
+
slot: 0,
|
|
5263
|
+
icon: "default.bmp",
|
|
5264
|
+
iconalt: "",
|
|
5265
|
+
description: "",
|
|
5266
|
+
date: "",
|
|
5267
|
+
timezone: "0"
|
|
5268
|
+
};
|
|
5269
|
+
config = {};
|
|
5270
|
+
controller1 = {};
|
|
5271
|
+
controller2 = {};
|
|
5272
|
+
constructor() {
|
|
5273
|
+
this.config = {
|
|
5274
|
+
22: "adi"
|
|
5275
|
+
};
|
|
5276
|
+
}
|
|
5277
|
+
setProgramDate(date) {
|
|
5278
|
+
const d = date;
|
|
5279
|
+
this.program.date = d.toISOString();
|
|
5280
|
+
const tzo = Math.abs(d.getTimezoneOffset());
|
|
5281
|
+
const tzh = tzo / 60 >>> 0;
|
|
5282
|
+
const tzm = tzo - tzh * 60;
|
|
5283
|
+
this.program.timezone = (d.getTimezoneOffset() > 0 ? "-" : "+") + this.dec2(tzh) + ":" + this.dec2(tzm);
|
|
5284
|
+
}
|
|
5285
|
+
createIni() {
|
|
5286
|
+
if (this.program.date.length === 0) {
|
|
5287
|
+
this.setProgramDate(new Date);
|
|
5288
|
+
}
|
|
5289
|
+
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("description", 256).addObjProperty("icon", 16).addObjProperty("iconalt", 16).addObjProperty("slot", 16)).addComment("").addSection(new IniSectionBuilder("config", this.config, (k) => "port_" + this.dec2(k)).addAllObjProps()).addComment("").addSection(new IniSectionBuilder("controller_1", this.controller1).addAllObjProps()).addComment("").addSection(new IniSectionBuilder("controller_2", this.controller2).addAllObjProps()).getContent();
|
|
5290
|
+
}
|
|
5291
|
+
dec2(value) {
|
|
5292
|
+
const str = ("00" + value.toString(10)).substr(-2, 2);
|
|
5293
|
+
return str.toUpperCase();
|
|
5294
|
+
}
|
|
5295
|
+
}
|
|
5296
|
+
// ../../node_modules/.bun/bun-serialport@0.1.1/node_modules/bun-serialport/src/serialport.js
|
|
5297
|
+
import { EventEmitter } from "events";
|
|
5298
|
+
|
|
5299
|
+
// ../../node_modules/.bun/bun-serialport@0.1.1/node_modules/bun-serialport/src/bindings/posix.js
|
|
5300
|
+
import { dlopen, FFIType, ptr, toArrayBuffer, CString } from "bun:ffi";
|
|
5301
|
+
|
|
5302
|
+
// ../../node_modules/.bun/bun-serialport@0.1.1/node_modules/bun-serialport/src/bindings/constants.js
|
|
5303
|
+
import { platform } from "os";
|
|
5304
|
+
var IS_LINUX = platform() === "linux";
|
|
5305
|
+
var IS_DARWIN = platform() === "darwin";
|
|
5306
|
+
if (!IS_LINUX && !IS_DARWIN) {
|
|
5307
|
+
throw new Error(`bun-serialport: unsupported platform "${platform()}"`);
|
|
5308
|
+
}
|
|
5309
|
+
var O_RDWR = 2;
|
|
5310
|
+
var O_NOCTTY = IS_LINUX ? 256 : 131072;
|
|
5311
|
+
var O_NONBLOCK = IS_LINUX ? 2048 : 4;
|
|
5312
|
+
var TCSADRAIN = 1;
|
|
5313
|
+
var TCSAFLUSH = 2;
|
|
5314
|
+
var TCIOFLUSH = IS_LINUX ? 2 : 3;
|
|
5315
|
+
var CSIZE = IS_LINUX ? 48 : 768;
|
|
5316
|
+
var CS5 = IS_LINUX ? 0 : 0;
|
|
5317
|
+
var CS6 = IS_LINUX ? 16 : 256;
|
|
5318
|
+
var CS7 = IS_LINUX ? 32 : 512;
|
|
5319
|
+
var CS8 = IS_LINUX ? 48 : 768;
|
|
5320
|
+
var CSTOPB = IS_LINUX ? 64 : 1024;
|
|
5321
|
+
var CREAD = IS_LINUX ? 128 : 2048;
|
|
5322
|
+
var PARENB = IS_LINUX ? 256 : 4096;
|
|
5323
|
+
var PARODD = IS_LINUX ? 512 : 8192;
|
|
5324
|
+
var CLOCAL = IS_LINUX ? 2048 : 32768;
|
|
5325
|
+
var CRTSCTS = IS_LINUX ? 2147483648 : 196608;
|
|
5326
|
+
var INPCK = IS_LINUX ? 16 : 16;
|
|
5327
|
+
var IXON = IS_LINUX ? 1024 : 512;
|
|
5328
|
+
var IXOFF = IS_LINUX ? 4096 : 1024;
|
|
5329
|
+
var VMIN = IS_LINUX ? 6 : 16;
|
|
5330
|
+
var VTIME = IS_LINUX ? 5 : 17;
|
|
5331
|
+
var NCCS = IS_LINUX ? 32 : 20;
|
|
5332
|
+
var TIOCMGET = IS_LINUX ? 21525 : 1074033770;
|
|
5333
|
+
var TIOCMBIS = IS_LINUX ? 21526 : 2147775596;
|
|
5334
|
+
var TIOCMBIC = IS_LINUX ? 21527 : 2147775595;
|
|
5335
|
+
var TIOCM_DTR = 2;
|
|
5336
|
+
var TIOCM_RTS = 4;
|
|
5337
|
+
var TIOCM_CTS = 32;
|
|
5338
|
+
var TIOCM_DSR = 256;
|
|
5339
|
+
var TIOCM_CD = 64;
|
|
5340
|
+
var TIOCM_RI = 128;
|
|
5341
|
+
var TERMIOS_SIZE = IS_LINUX ? 60 : 72;
|
|
5342
|
+
var TCFLAG_SIZE = IS_LINUX ? 4 : 8;
|
|
5343
|
+
var TERMIOS_OFFSETS = IS_LINUX ? { c_iflag: 0, c_oflag: 4, c_cflag: 8, c_lflag: 12, c_line: 16, c_cc: 17, c_ispeed: 52, c_ospeed: 56 } : { c_iflag: 0, c_oflag: 8, c_cflag: 16, c_lflag: 24, c_cc: 32, c_ispeed: 56, c_ospeed: 64 };
|
|
5344
|
+
var LINUX_BAUD_MAP = {
|
|
5345
|
+
0: 0,
|
|
5346
|
+
110: 3,
|
|
5347
|
+
300: 7,
|
|
5348
|
+
600: 8,
|
|
5349
|
+
1200: 9,
|
|
5350
|
+
2400: 11,
|
|
5351
|
+
4800: 12,
|
|
5352
|
+
9600: 13,
|
|
5353
|
+
19200: 14,
|
|
5354
|
+
38400: 15,
|
|
5355
|
+
57600: 4097,
|
|
5356
|
+
115200: 4098,
|
|
5357
|
+
230400: 4099,
|
|
5358
|
+
460800: 4100,
|
|
5359
|
+
500000: 4101,
|
|
5360
|
+
576000: 4102,
|
|
5361
|
+
921600: 4103,
|
|
5362
|
+
1e6: 4104,
|
|
5363
|
+
1152000: 4105,
|
|
5364
|
+
1500000: 4106,
|
|
5365
|
+
2000000: 4107,
|
|
5366
|
+
2500000: 4108,
|
|
5367
|
+
3000000: 4109,
|
|
5368
|
+
3500000: 4110,
|
|
5369
|
+
4000000: 4111
|
|
5370
|
+
};
|
|
5371
|
+
function encodeBaudRate(rate) {
|
|
5372
|
+
if (IS_DARWIN)
|
|
5373
|
+
return rate;
|
|
5374
|
+
const encoded = LINUX_BAUD_MAP[rate];
|
|
5375
|
+
if (encoded === undefined)
|
|
5376
|
+
throw new Error(`Unsupported baud rate: ${rate}`);
|
|
5377
|
+
return encoded;
|
|
5378
|
+
}
|
|
5379
|
+
function dataBitsFlag(bits) {
|
|
5380
|
+
switch (bits) {
|
|
5381
|
+
case 5:
|
|
5382
|
+
return CS5;
|
|
5383
|
+
case 6:
|
|
5384
|
+
return CS6;
|
|
5385
|
+
case 7:
|
|
5386
|
+
return CS7;
|
|
5387
|
+
case 8:
|
|
5388
|
+
return CS8;
|
|
5389
|
+
default:
|
|
5390
|
+
throw new Error(`Invalid data bits: ${bits}`);
|
|
5391
|
+
}
|
|
5392
|
+
}
|
|
5393
|
+
|
|
5394
|
+
// ../../node_modules/.bun/bun-serialport@0.1.1/node_modules/bun-serialport/src/bindings/posix.js
|
|
5395
|
+
import { platform as platform2 } from "os";
|
|
5396
|
+
var IS_LINUX2 = platform2() === "linux";
|
|
5397
|
+
var IS_DARWIN2 = platform2() === "darwin";
|
|
5398
|
+
var LIBC_PATH = IS_LINUX2 ? "libc.so.6" : "libSystem.B.dylib";
|
|
5399
|
+
var libc = dlopen(LIBC_PATH, {
|
|
5400
|
+
open: { args: [FFIType.cstring, FFIType.i32], returns: FFIType.i32 },
|
|
5401
|
+
close: { args: [FFIType.i32], returns: FFIType.i32 },
|
|
5402
|
+
read: { args: [FFIType.i32, FFIType.ptr, FFIType.u64], returns: FFIType.i64 },
|
|
5403
|
+
write: { args: [FFIType.i32, FFIType.ptr, FFIType.u64], returns: FFIType.i64 },
|
|
5404
|
+
tcgetattr: { args: [FFIType.i32, FFIType.ptr], returns: FFIType.i32 },
|
|
5405
|
+
tcsetattr: { args: [FFIType.i32, FFIType.i32, FFIType.ptr], returns: FFIType.i32 },
|
|
5406
|
+
tcflush: { args: [FFIType.i32, FFIType.i32], returns: FFIType.i32 },
|
|
5407
|
+
tcdrain: { args: [FFIType.i32], returns: FFIType.i32 },
|
|
5408
|
+
cfsetispeed: { args: [FFIType.ptr, FFIType.u64], returns: FFIType.i32 },
|
|
5409
|
+
cfsetospeed: { args: [FFIType.ptr, FFIType.u64], returns: FFIType.i32 },
|
|
5410
|
+
fcntl: { args: [FFIType.i32, FFIType.i32, FFIType.i32], returns: FFIType.i32 },
|
|
5411
|
+
ioctl: { args: [FFIType.i32, FFIType.u64, FFIType.ptr], returns: FFIType.i32 },
|
|
5412
|
+
strerror: { args: [FFIType.i32], returns: FFIType.ptr }
|
|
5413
|
+
});
|
|
5414
|
+
var errnoLib = dlopen(LIBC_PATH, IS_LINUX2 ? { __errno_location: { args: [], returns: FFIType.ptr } } : { __error: { args: [], returns: FFIType.ptr } });
|
|
5415
|
+
function getErrno() {
|
|
5416
|
+
const errPtr = IS_LINUX2 ? errnoLib.symbols.__errno_location() : errnoLib.symbols.__error();
|
|
5417
|
+
const view = new DataView(toArrayBuffer(errPtr, 0, 4));
|
|
5418
|
+
return view.getInt32(0, true);
|
|
5419
|
+
}
|
|
5420
|
+
function errnoError(syscall) {
|
|
5421
|
+
const code = getErrno();
|
|
5422
|
+
const msgPtr = libc.symbols.strerror(code);
|
|
5423
|
+
const msg = msgPtr ? new CString(msgPtr) : `errno ${code}`;
|
|
5424
|
+
const err = new Error(`${syscall}: ${msg}`);
|
|
5425
|
+
err.code = code;
|
|
5426
|
+
err.syscall = syscall;
|
|
5427
|
+
return err;
|
|
5428
|
+
}
|
|
5429
|
+
function readFlag(buf, offset) {
|
|
5430
|
+
if (TCFLAG_SIZE === 4) {
|
|
5431
|
+
return buf.getUint32(offset, true);
|
|
5432
|
+
}
|
|
5433
|
+
return Number(buf.getBigUint64(offset, true));
|
|
5434
|
+
}
|
|
5435
|
+
function writeFlag(buf, offset, value) {
|
|
5436
|
+
if (TCFLAG_SIZE === 4) {
|
|
5437
|
+
buf.setUint32(offset, value >>> 0, true);
|
|
5438
|
+
} else {
|
|
5439
|
+
buf.setBigUint64(offset, BigInt(value >>> 0), true);
|
|
5440
|
+
}
|
|
5441
|
+
}
|
|
5442
|
+
function writeSpeed(buf, offset, value) {
|
|
5443
|
+
if (TCFLAG_SIZE === 4) {
|
|
5444
|
+
buf.setUint32(offset, value >>> 0, true);
|
|
5445
|
+
} else {
|
|
5446
|
+
buf.setBigUint64(offset, BigInt(value), true);
|
|
5447
|
+
}
|
|
5448
|
+
}
|
|
5449
|
+
function openPort(path, options) {
|
|
5450
|
+
const {
|
|
5451
|
+
baudRate = 9600,
|
|
5452
|
+
dataBits = 8,
|
|
5453
|
+
stopBits = 1,
|
|
5454
|
+
parity = "none",
|
|
5455
|
+
rtscts = false,
|
|
5456
|
+
xon = false,
|
|
5457
|
+
xoff = false
|
|
5458
|
+
} = options;
|
|
5459
|
+
const pathBuf = Buffer.from(path + "\x00", "utf-8");
|
|
5460
|
+
const fd = libc.symbols.open(ptr(pathBuf), O_RDWR | O_NOCTTY | O_NONBLOCK);
|
|
5461
|
+
if (fd < 0)
|
|
5462
|
+
throw errnoError("open");
|
|
5463
|
+
const termiosBuf = new ArrayBuffer(TERMIOS_SIZE);
|
|
5464
|
+
const termiosBytes = new Uint8Array(termiosBuf);
|
|
5465
|
+
const termiosView = new DataView(termiosBuf);
|
|
5466
|
+
const termiosPtr = ptr(termiosBytes);
|
|
5467
|
+
if (libc.symbols.tcgetattr(fd, termiosPtr) < 0) {
|
|
5468
|
+
libc.symbols.close(fd);
|
|
5469
|
+
throw errnoError("tcgetattr");
|
|
5470
|
+
}
|
|
5471
|
+
const off = TERMIOS_OFFSETS;
|
|
5472
|
+
let cflag = readFlag(termiosView, off.c_cflag);
|
|
5473
|
+
cflag &= ~CSIZE;
|
|
5474
|
+
cflag |= dataBitsFlag(dataBits);
|
|
5475
|
+
cflag |= CREAD | CLOCAL;
|
|
5476
|
+
if (stopBits === 2)
|
|
5477
|
+
cflag |= CSTOPB;
|
|
5478
|
+
else
|
|
5479
|
+
cflag &= ~CSTOPB;
|
|
5480
|
+
if (parity === "none") {
|
|
5481
|
+
cflag &= ~(PARENB | PARODD);
|
|
5482
|
+
} else if (parity === "even") {
|
|
5483
|
+
cflag |= PARENB;
|
|
5484
|
+
cflag &= ~PARODD;
|
|
5485
|
+
} else if (parity === "odd") {
|
|
5486
|
+
cflag |= PARENB | PARODD;
|
|
5487
|
+
}
|
|
5488
|
+
if (rtscts)
|
|
5489
|
+
cflag |= CRTSCTS;
|
|
5490
|
+
else
|
|
5491
|
+
cflag &= ~CRTSCTS;
|
|
5492
|
+
writeFlag(termiosView, off.c_cflag, cflag);
|
|
5493
|
+
let iflag = 0;
|
|
5494
|
+
if (parity !== "none")
|
|
5495
|
+
iflag |= INPCK;
|
|
5496
|
+
if (xon)
|
|
5497
|
+
iflag |= IXON;
|
|
5498
|
+
if (xoff)
|
|
5499
|
+
iflag |= IXOFF;
|
|
5500
|
+
writeFlag(termiosView, off.c_iflag, iflag);
|
|
5501
|
+
writeFlag(termiosView, off.c_oflag, 0);
|
|
5502
|
+
writeFlag(termiosView, off.c_lflag, 0);
|
|
5503
|
+
const ccOffset = off.c_cc;
|
|
5504
|
+
for (let i = 0;i < NCCS; i++)
|
|
5505
|
+
termiosBytes[ccOffset + i] = 0;
|
|
5506
|
+
termiosBytes[ccOffset + VMIN] = 1;
|
|
5507
|
+
termiosBytes[ccOffset + VTIME] = 0;
|
|
5508
|
+
const baudCode = encodeBaudRate(baudRate);
|
|
5509
|
+
if (IS_LINUX2) {
|
|
5510
|
+
writeSpeed(termiosView, off.c_ispeed, baudCode);
|
|
5511
|
+
writeSpeed(termiosView, off.c_ospeed, baudCode);
|
|
5512
|
+
}
|
|
5513
|
+
if (libc.symbols.cfsetispeed(termiosPtr, baudCode) < 0) {
|
|
5514
|
+
libc.symbols.close(fd);
|
|
5515
|
+
throw errnoError("cfsetispeed");
|
|
5516
|
+
}
|
|
5517
|
+
if (libc.symbols.cfsetospeed(termiosPtr, baudCode) < 0) {
|
|
5518
|
+
libc.symbols.close(fd);
|
|
5519
|
+
throw errnoError("cfsetospeed");
|
|
5520
|
+
}
|
|
5521
|
+
if (libc.symbols.tcsetattr(fd, TCSAFLUSH, termiosPtr) < 0) {
|
|
5522
|
+
libc.symbols.close(fd);
|
|
5523
|
+
throw errnoError("tcsetattr");
|
|
5524
|
+
}
|
|
5525
|
+
libc.symbols.tcflush(fd, TCIOFLUSH);
|
|
5526
|
+
return fd;
|
|
5527
|
+
}
|
|
5528
|
+
function closePort(fd) {
|
|
5529
|
+
if (libc.symbols.close(fd) < 0)
|
|
5530
|
+
throw errnoError("close");
|
|
5531
|
+
}
|
|
5532
|
+
var MAX_EAGAIN_RETRIES = 1000;
|
|
5533
|
+
function writePort(fd, data) {
|
|
5534
|
+
const buf = data instanceof Uint8Array ? data : Buffer.from(data, "utf-8");
|
|
5535
|
+
let offset = 0;
|
|
5536
|
+
let eagainCount = 0;
|
|
5537
|
+
while (offset < buf.length) {
|
|
5538
|
+
const slice = buf.subarray(offset);
|
|
5539
|
+
const written = Number(libc.symbols.write(fd, ptr(slice), BigInt(slice.length)));
|
|
5540
|
+
if (written < 0) {
|
|
5541
|
+
const code = getErrno();
|
|
5542
|
+
if (code === 11 || code === 35) {
|
|
5543
|
+
if (++eagainCount > MAX_EAGAIN_RETRIES) {
|
|
5544
|
+
throw new Error("write: device not accepting data (EAGAIN limit exceeded)");
|
|
5545
|
+
}
|
|
5546
|
+
continue;
|
|
5547
|
+
}
|
|
5548
|
+
throw errnoError("write");
|
|
5549
|
+
}
|
|
5550
|
+
eagainCount = 0;
|
|
5551
|
+
offset += written;
|
|
5552
|
+
}
|
|
5553
|
+
return offset;
|
|
5554
|
+
}
|
|
5555
|
+
function readPort(fd, buffer) {
|
|
5556
|
+
const n = Number(libc.symbols.read(fd, ptr(buffer), BigInt(buffer.length)));
|
|
5557
|
+
if (n < 0) {
|
|
5558
|
+
const code = getErrno();
|
|
5559
|
+
if (code === 11 || code === 35)
|
|
5560
|
+
return 0;
|
|
5561
|
+
throw errnoError("read");
|
|
5562
|
+
}
|
|
5563
|
+
return n;
|
|
5564
|
+
}
|
|
5565
|
+
function updateBaudRate(fd, baudRate) {
|
|
5566
|
+
const termiosBuf = new ArrayBuffer(TERMIOS_SIZE);
|
|
5567
|
+
const termiosPtr = ptr(new Uint8Array(termiosBuf));
|
|
5568
|
+
if (libc.symbols.tcgetattr(fd, termiosPtr) < 0)
|
|
5569
|
+
throw errnoError("tcgetattr");
|
|
5570
|
+
const baudCode = encodeBaudRate(baudRate);
|
|
5571
|
+
if (libc.symbols.cfsetispeed(termiosPtr, baudCode) < 0)
|
|
5572
|
+
throw errnoError("cfsetispeed");
|
|
5573
|
+
if (libc.symbols.cfsetospeed(termiosPtr, baudCode) < 0)
|
|
5574
|
+
throw errnoError("cfsetospeed");
|
|
5575
|
+
if (IS_LINUX2) {
|
|
5576
|
+
const view = new DataView(termiosBuf);
|
|
5577
|
+
writeSpeed(view, TERMIOS_OFFSETS.c_ispeed, baudCode);
|
|
5578
|
+
writeSpeed(view, TERMIOS_OFFSETS.c_ospeed, baudCode);
|
|
5579
|
+
}
|
|
5580
|
+
if (libc.symbols.tcsetattr(fd, TCSADRAIN, termiosPtr) < 0)
|
|
5581
|
+
throw errnoError("tcsetattr");
|
|
5582
|
+
}
|
|
5583
|
+
function setModemLines(fd, flags) {
|
|
5584
|
+
const { dtr, rts, brk } = flags;
|
|
5585
|
+
const intBuf = new ArrayBuffer(4);
|
|
5586
|
+
const intView = new DataView(intBuf);
|
|
5587
|
+
const intPtr = ptr(new Uint8Array(intBuf));
|
|
5588
|
+
let bitsToSet = 0;
|
|
5589
|
+
let bitsToClear = 0;
|
|
5590
|
+
if (dtr === true)
|
|
5591
|
+
bitsToSet |= TIOCM_DTR;
|
|
5592
|
+
if (dtr === false)
|
|
5593
|
+
bitsToClear |= TIOCM_DTR;
|
|
5594
|
+
if (rts === true)
|
|
5595
|
+
bitsToSet |= TIOCM_RTS;
|
|
5596
|
+
if (rts === false)
|
|
5597
|
+
bitsToClear |= TIOCM_RTS;
|
|
5598
|
+
if (bitsToSet) {
|
|
5599
|
+
intView.setInt32(0, bitsToSet, true);
|
|
5600
|
+
if (libc.symbols.ioctl(fd, TIOCMBIS, intPtr) < 0)
|
|
5601
|
+
throw errnoError("ioctl TIOCMBIS");
|
|
5602
|
+
}
|
|
5603
|
+
if (bitsToClear) {
|
|
5604
|
+
intView.setInt32(0, bitsToClear, true);
|
|
5605
|
+
if (libc.symbols.ioctl(fd, TIOCMBIC, intPtr) < 0)
|
|
5606
|
+
throw errnoError("ioctl TIOCMBIC");
|
|
5607
|
+
}
|
|
5608
|
+
}
|
|
5609
|
+
function getModemLines(fd) {
|
|
5610
|
+
const intBuf = new ArrayBuffer(4);
|
|
5611
|
+
const intView = new DataView(intBuf);
|
|
5612
|
+
const intPtr = ptr(new Uint8Array(intBuf));
|
|
5613
|
+
if (libc.symbols.ioctl(fd, TIOCMGET, intPtr) < 0)
|
|
5614
|
+
throw errnoError("ioctl TIOCMGET");
|
|
5615
|
+
const bits = intView.getInt32(0, true);
|
|
5616
|
+
return {
|
|
5617
|
+
cts: !!(bits & TIOCM_CTS),
|
|
5618
|
+
dsr: !!(bits & TIOCM_DSR),
|
|
5619
|
+
dcd: !!(bits & TIOCM_CD),
|
|
5620
|
+
ri: !!(bits & TIOCM_RI)
|
|
5621
|
+
};
|
|
5622
|
+
}
|
|
5623
|
+
function flushPort(fd) {
|
|
5624
|
+
if (libc.symbols.tcflush(fd, TCIOFLUSH) < 0)
|
|
5625
|
+
throw errnoError("tcflush");
|
|
5626
|
+
}
|
|
5627
|
+
function drainPort(fd) {
|
|
5628
|
+
if (libc.symbols.tcdrain(fd) < 0)
|
|
5629
|
+
throw errnoError("tcdrain");
|
|
5630
|
+
}
|
|
5631
|
+
|
|
5632
|
+
// ../../node_modules/.bun/bun-serialport@0.1.1/node_modules/bun-serialport/src/serialport.js
|
|
5633
|
+
var DEFAULT_READ_BUFFER_SIZE = 65536;
|
|
5634
|
+
var DEFAULT_READ_INTERVAL_MS = 1;
|
|
5635
|
+
|
|
5636
|
+
class SerialPort extends EventEmitter {
|
|
5637
|
+
#fd = -1;
|
|
5638
|
+
#path;
|
|
5639
|
+
#baudRate;
|
|
5640
|
+
#options;
|
|
5641
|
+
#isOpen = false;
|
|
5642
|
+
#isClosing = false;
|
|
5643
|
+
#readBuf;
|
|
5644
|
+
#readInterval;
|
|
5645
|
+
#readTimer = null;
|
|
5646
|
+
constructor(options) {
|
|
5647
|
+
super();
|
|
5648
|
+
if (!options || !options.path)
|
|
5649
|
+
throw new Error("options.path is required");
|
|
5650
|
+
if (!options.baudRate)
|
|
5651
|
+
throw new Error("options.baudRate is required");
|
|
5652
|
+
this.#path = options.path;
|
|
5653
|
+
this.#baudRate = options.baudRate;
|
|
5654
|
+
this.#options = { ...options };
|
|
5655
|
+
this.#readBuf = new Uint8Array(options.readBufferSize || DEFAULT_READ_BUFFER_SIZE);
|
|
5656
|
+
this.#readInterval = options.readInterval || DEFAULT_READ_INTERVAL_MS;
|
|
5657
|
+
if (options.autoOpen !== false) {
|
|
5658
|
+
queueMicrotask(() => this.open().catch((err) => this.emit("error", err)));
|
|
5659
|
+
}
|
|
5660
|
+
}
|
|
5661
|
+
get path() {
|
|
5662
|
+
return this.#path;
|
|
5663
|
+
}
|
|
5664
|
+
get baudRate() {
|
|
5665
|
+
return this.#baudRate;
|
|
5666
|
+
}
|
|
5667
|
+
get isOpen() {
|
|
5668
|
+
return this.#isOpen && !this.#isClosing;
|
|
5669
|
+
}
|
|
5670
|
+
async open() {
|
|
5671
|
+
if (this.#isOpen)
|
|
5672
|
+
throw new Error("Port is already open");
|
|
5673
|
+
try {
|
|
5674
|
+
this.#fd = openPort(this.#path, this.#options);
|
|
5675
|
+
this.#isOpen = true;
|
|
5676
|
+
this.#isClosing = false;
|
|
5677
|
+
this.#startReading();
|
|
5678
|
+
this.emit("open");
|
|
5679
|
+
} catch (err) {
|
|
5680
|
+
this.#isOpen = false;
|
|
5681
|
+
throw err;
|
|
5682
|
+
}
|
|
5683
|
+
}
|
|
5684
|
+
async close() {
|
|
5685
|
+
if (!this.#isOpen)
|
|
5686
|
+
throw new Error("Port is not open");
|
|
5687
|
+
if (this.#isClosing)
|
|
5688
|
+
return;
|
|
5689
|
+
this.#isClosing = true;
|
|
5690
|
+
this.#stopReading();
|
|
5691
|
+
try {
|
|
5692
|
+
closePort(this.#fd);
|
|
5693
|
+
} catch (err) {
|
|
5694
|
+
this.#isClosing = false;
|
|
5695
|
+
throw err;
|
|
5696
|
+
}
|
|
5697
|
+
this.#fd = -1;
|
|
5698
|
+
this.#isOpen = false;
|
|
5699
|
+
this.#isClosing = false;
|
|
5700
|
+
this.emit("close");
|
|
5701
|
+
}
|
|
5702
|
+
async write(data) {
|
|
5703
|
+
if (!this.#isOpen || this.#isClosing) {
|
|
5704
|
+
throw new Error("Port is not open");
|
|
5705
|
+
}
|
|
5706
|
+
const buf = typeof data === "string" ? Buffer.from(data, "utf-8") : data;
|
|
5707
|
+
return writePort(this.#fd, buf);
|
|
5708
|
+
}
|
|
5709
|
+
async update(options) {
|
|
5710
|
+
if (!this.#isOpen)
|
|
5711
|
+
throw new Error("Port is not open");
|
|
5712
|
+
if (options.baudRate !== undefined) {
|
|
5713
|
+
updateBaudRate(this.#fd, options.baudRate);
|
|
5714
|
+
this.#baudRate = options.baudRate;
|
|
5715
|
+
}
|
|
5716
|
+
}
|
|
5717
|
+
async set(flags) {
|
|
5718
|
+
if (!this.#isOpen)
|
|
5719
|
+
throw new Error("Port is not open");
|
|
5720
|
+
setModemLines(this.#fd, flags);
|
|
5721
|
+
}
|
|
5722
|
+
async get() {
|
|
5723
|
+
if (!this.#isOpen)
|
|
5724
|
+
throw new Error("Port is not open");
|
|
5725
|
+
return getModemLines(this.#fd);
|
|
5726
|
+
}
|
|
5727
|
+
async flush() {
|
|
5728
|
+
if (!this.#isOpen)
|
|
5729
|
+
throw new Error("Port is not open");
|
|
5730
|
+
flushPort(this.#fd);
|
|
5731
|
+
}
|
|
5732
|
+
async drain() {
|
|
5733
|
+
if (!this.#isOpen)
|
|
5734
|
+
throw new Error("Port is not open");
|
|
5735
|
+
drainPort(this.#fd);
|
|
5736
|
+
}
|
|
5737
|
+
pipe(parser) {
|
|
5738
|
+
const handler = (chunk) => parser.push(chunk);
|
|
5739
|
+
this.on("data", handler);
|
|
5740
|
+
parser._unpipe = () => this.off("data", handler);
|
|
5741
|
+
return parser;
|
|
5742
|
+
}
|
|
5743
|
+
unpipe(parser) {
|
|
5744
|
+
if (parser && typeof parser._unpipe === "function") {
|
|
5745
|
+
parser._unpipe();
|
|
5746
|
+
parser._unpipe = undefined;
|
|
5747
|
+
}
|
|
5748
|
+
}
|
|
5749
|
+
#startReading() {
|
|
5750
|
+
this.#readTimer = setInterval(() => {
|
|
5751
|
+
if (!this.#isOpen || this.#isClosing)
|
|
5752
|
+
return;
|
|
5753
|
+
try {
|
|
5754
|
+
const n = readPort(this.#fd, this.#readBuf);
|
|
5755
|
+
if (n > 0) {
|
|
5756
|
+
const data = this.#readBuf.slice(0, n);
|
|
5757
|
+
this.emit("data", data);
|
|
5758
|
+
}
|
|
5759
|
+
} catch (err) {
|
|
5760
|
+
err.disconnected = true;
|
|
5761
|
+
this.emit("error", err);
|
|
5762
|
+
this.close().catch(() => {});
|
|
5763
|
+
}
|
|
5764
|
+
}, this.#readInterval);
|
|
5765
|
+
}
|
|
5766
|
+
#stopReading() {
|
|
5767
|
+
if (this.#readTimer !== null) {
|
|
5768
|
+
clearInterval(this.#readTimer);
|
|
5769
|
+
this.#readTimer = null;
|
|
5770
|
+
}
|
|
5771
|
+
}
|
|
5772
|
+
}
|
|
5773
|
+
// ../../node_modules/.bun/bun-serialport@0.1.1/node_modules/bun-serialport/src/list.js
|
|
5774
|
+
import { platform as platform3 } from "os";
|
|
5775
|
+
import { readdir, readlink, access } from "fs/promises";
|
|
5776
|
+
import { join as join2 } from "path";
|
|
5777
|
+
var IS_LINUX3 = platform3() === "linux";
|
|
5778
|
+
async function exists2(path) {
|
|
5779
|
+
try {
|
|
5780
|
+
await access(path);
|
|
5781
|
+
return true;
|
|
5782
|
+
} catch {
|
|
5783
|
+
return false;
|
|
5784
|
+
}
|
|
5785
|
+
}
|
|
5786
|
+
async function readFileQuiet(path) {
|
|
5787
|
+
try {
|
|
5788
|
+
return (await Bun.file(path).text()).trim();
|
|
5789
|
+
} catch {
|
|
5790
|
+
return "";
|
|
5791
|
+
}
|
|
5792
|
+
}
|
|
5793
|
+
async function listLinux() {
|
|
5794
|
+
const ttys = await readdir("/sys/class/tty").catch(() => []);
|
|
5795
|
+
const checks = ttys.map(async (name) => {
|
|
5796
|
+
const sysPath = `/sys/class/tty/${name}`;
|
|
5797
|
+
const devicePath = join2(sysPath, "device");
|
|
5798
|
+
if (!await exists2(devicePath))
|
|
5799
|
+
return null;
|
|
5800
|
+
const devPath = `/dev/${name}`;
|
|
5801
|
+
if (!await exists2(devPath))
|
|
5802
|
+
return null;
|
|
5803
|
+
return { name, devPath, devicePath };
|
|
5804
|
+
});
|
|
5805
|
+
const valid = (await Promise.all(checks)).filter(Boolean);
|
|
5806
|
+
const ports = await Promise.all(valid.map(async ({ devPath, devicePath }) => {
|
|
5807
|
+
const info = { path: devPath };
|
|
5808
|
+
const subsystem = await readlink(join2(devicePath, "subsystem")).catch(() => "");
|
|
5809
|
+
if (subsystem.includes("usb-serial") || subsystem.includes("usb")) {
|
|
5810
|
+
const usbDevice = await findUsbParent(devicePath);
|
|
5811
|
+
if (usbDevice) {
|
|
5812
|
+
const [manufacturer, serialNumber, vendorId, productId, product] = await Promise.all([
|
|
5813
|
+
readFileQuiet(join2(usbDevice, "manufacturer")),
|
|
5814
|
+
readFileQuiet(join2(usbDevice, "serial")),
|
|
5815
|
+
readFileQuiet(join2(usbDevice, "idVendor")),
|
|
5816
|
+
readFileQuiet(join2(usbDevice, "idProduct")),
|
|
5817
|
+
readFileQuiet(join2(usbDevice, "product"))
|
|
5818
|
+
]);
|
|
5819
|
+
info.manufacturer = manufacturer;
|
|
5820
|
+
info.serialNumber = serialNumber;
|
|
5821
|
+
info.vendorId = vendorId;
|
|
5822
|
+
info.productId = productId;
|
|
5823
|
+
info.product = product;
|
|
5824
|
+
}
|
|
5825
|
+
}
|
|
5826
|
+
return info;
|
|
5827
|
+
}));
|
|
5828
|
+
return ports;
|
|
5829
|
+
}
|
|
5830
|
+
async function findUsbParent(devicePath) {
|
|
5831
|
+
let current = devicePath;
|
|
5832
|
+
for (let i = 0;i < 10; i++) {
|
|
5833
|
+
current = join2(current, "..");
|
|
5834
|
+
if (await exists2(join2(current, "idVendor")))
|
|
5835
|
+
return current;
|
|
5836
|
+
}
|
|
5837
|
+
return null;
|
|
5838
|
+
}
|
|
5839
|
+
async function listDarwin() {
|
|
5840
|
+
const devFiles = await readdir("/dev").catch(() => []);
|
|
5841
|
+
const seen = new Map;
|
|
5842
|
+
for (const name of devFiles) {
|
|
5843
|
+
if (!name.startsWith("cu.") && !name.startsWith("tty."))
|
|
5844
|
+
continue;
|
|
5845
|
+
if (name === "tty")
|
|
5846
|
+
continue;
|
|
5847
|
+
const isCu = name.startsWith("cu.");
|
|
5848
|
+
const suffix = name.slice(isCu ? 3 : 4);
|
|
5849
|
+
if (seen.has(suffix) && !isCu)
|
|
5850
|
+
continue;
|
|
5851
|
+
seen.set(suffix, { path: `/dev/${name}` });
|
|
5852
|
+
}
|
|
5853
|
+
return [...seen.values()];
|
|
5854
|
+
}
|
|
5855
|
+
async function list() {
|
|
5856
|
+
return IS_LINUX3 ? listLinux() : listDarwin();
|
|
5857
|
+
}
|
|
5858
|
+
// src/adapter.ts
|
|
5859
|
+
import { readdir as readdir2, realpath, readlink as readlink2 } from "fs/promises";
|
|
5860
|
+
import { join as join3 } from "path";
|
|
5861
|
+
import { platform as platform4 } from "os";
|
|
5862
|
+
|
|
5863
|
+
class WebSerialPortAdapter extends EventTarget {
|
|
5864
|
+
onconnect = () => {};
|
|
5865
|
+
ondisconnect = () => {};
|
|
5866
|
+
_port = null;
|
|
5867
|
+
_path;
|
|
5868
|
+
_info;
|
|
5869
|
+
_readable = null;
|
|
5870
|
+
_writable = null;
|
|
5871
|
+
_readerController = null;
|
|
5872
|
+
constructor(path, info) {
|
|
5873
|
+
super();
|
|
5874
|
+
this._path = path;
|
|
5875
|
+
this._info = info;
|
|
5876
|
+
}
|
|
5877
|
+
get readable() {
|
|
5878
|
+
return this._readable;
|
|
5879
|
+
}
|
|
5880
|
+
get writable() {
|
|
5881
|
+
return this._writable;
|
|
5882
|
+
}
|
|
5883
|
+
getInfo() {
|
|
5884
|
+
return this._info;
|
|
5885
|
+
}
|
|
5886
|
+
async open(options) {
|
|
5887
|
+
if (this._port)
|
|
5888
|
+
throw new Error("Port already open");
|
|
5889
|
+
this._port = new SerialPort({
|
|
5890
|
+
path: this._path,
|
|
5891
|
+
baudRate: options.baudRate,
|
|
5892
|
+
autoOpen: false
|
|
5893
|
+
});
|
|
5894
|
+
await this._port.open();
|
|
5895
|
+
this._readable = new ReadableStream({
|
|
5896
|
+
start: (controller) => {
|
|
5897
|
+
this._readerController = controller;
|
|
5898
|
+
this._port?.on("data", (data) => {
|
|
5899
|
+
controller.enqueue(data);
|
|
5900
|
+
});
|
|
5901
|
+
this._port?.on("error", (err) => {
|
|
5902
|
+
controller.error(err);
|
|
5903
|
+
this.close().catch(() => {});
|
|
5904
|
+
});
|
|
5905
|
+
},
|
|
5906
|
+
cancel: () => {
|
|
5907
|
+
this.close();
|
|
5908
|
+
}
|
|
5909
|
+
});
|
|
5910
|
+
this._writable = new WritableStream({
|
|
5911
|
+
write: async (chunk) => {
|
|
5912
|
+
if (!this._port)
|
|
5913
|
+
throw new Error("Port closed");
|
|
5914
|
+
await this._port.write(chunk);
|
|
5915
|
+
},
|
|
5916
|
+
close: async () => {
|
|
5917
|
+
await this.close();
|
|
5918
|
+
}
|
|
5919
|
+
});
|
|
5920
|
+
}
|
|
5921
|
+
async close() {
|
|
5922
|
+
if (!this._port)
|
|
5923
|
+
return;
|
|
5924
|
+
const port = this._port;
|
|
5925
|
+
this._port = null;
|
|
5926
|
+
if (this._readerController) {
|
|
5927
|
+
try {
|
|
5928
|
+
this._readerController.close();
|
|
5929
|
+
} catch (e) {}
|
|
5930
|
+
this._readerController = null;
|
|
5931
|
+
}
|
|
5932
|
+
await port.close();
|
|
5933
|
+
try {
|
|
5934
|
+
port.removeAllListeners?.();
|
|
5935
|
+
} catch (e) {}
|
|
5936
|
+
this._readable = null;
|
|
5937
|
+
this._writable = null;
|
|
5938
|
+
this.dispatchEvent(new Event("disconnect"));
|
|
5939
|
+
}
|
|
5940
|
+
async forget() {
|
|
5941
|
+
await this.close();
|
|
5942
|
+
}
|
|
5943
|
+
}
|
|
5944
|
+
|
|
5945
|
+
class WebSerialAdapter extends EventTarget {
|
|
5946
|
+
onconnect = () => {};
|
|
5947
|
+
ondisconnect = () => {};
|
|
5948
|
+
async _listPortsLinux() {
|
|
5949
|
+
const ttys = await readdir2("/sys/class/tty").catch(() => []);
|
|
5950
|
+
const ports = [];
|
|
5951
|
+
for (const name of ttys) {
|
|
5952
|
+
const sysPath = `/sys/class/tty/${name}`;
|
|
5953
|
+
const devicePath = join3(sysPath, "device");
|
|
5954
|
+
try {
|
|
5955
|
+
const realDevicePath = await realpath(devicePath);
|
|
5956
|
+
const subsystem = await readlink2(join3(realDevicePath, "subsystem")).catch(() => "");
|
|
5957
|
+
const info = { path: `/dev/${name}` };
|
|
5958
|
+
if (subsystem.includes("usb")) {
|
|
5959
|
+
let current = realDevicePath;
|
|
5960
|
+
for (let i = 0;i < 5; i++) {
|
|
5961
|
+
try {
|
|
5962
|
+
const vendorId = await Bun.file(join3(current, "idVendor")).text().then((t) => t.trim());
|
|
5963
|
+
const productId = await Bun.file(join3(current, "idProduct")).text().then((t) => t.trim());
|
|
5964
|
+
info.vendorId = vendorId;
|
|
5965
|
+
info.productId = productId;
|
|
5966
|
+
break;
|
|
5967
|
+
} catch (e) {
|
|
5968
|
+
current = join3(current, "..");
|
|
5969
|
+
}
|
|
5970
|
+
}
|
|
5971
|
+
}
|
|
5972
|
+
ports.push(info);
|
|
5973
|
+
} catch (e) {}
|
|
5974
|
+
}
|
|
5975
|
+
return ports;
|
|
5976
|
+
}
|
|
5977
|
+
async getPorts() {
|
|
5978
|
+
const ports = platform4() === "linux" ? await this._listPortsLinux() : await list();
|
|
5979
|
+
return ports.map((p) => new WebSerialPortAdapter(p.path, {
|
|
5980
|
+
usbVendorId: p.vendorId ? parseInt(p.vendorId, 16) : undefined,
|
|
5981
|
+
usbProductId: p.productId ? parseInt(p.productId, 16) : undefined
|
|
5982
|
+
}));
|
|
5983
|
+
}
|
|
5984
|
+
async requestPort(options) {
|
|
5985
|
+
const ports = await this.getPorts();
|
|
5986
|
+
if (options?.filters && options.filters.length > 0) {
|
|
5987
|
+
const filtered = ports.filter((p) => {
|
|
5988
|
+
const info = p.getInfo();
|
|
5989
|
+
return options.filters?.some((f) => (f.usbVendorId === undefined || f.usbVendorId === info.usbVendorId) && (f.usbProductId === undefined || f.usbProductId === info.usbProductId));
|
|
5990
|
+
});
|
|
5991
|
+
if (filtered.length > 0)
|
|
5992
|
+
return filtered[0];
|
|
5993
|
+
throw new Error("No port found matching filters");
|
|
5994
|
+
}
|
|
5995
|
+
if (ports.length > 0)
|
|
5996
|
+
return ports[0];
|
|
5997
|
+
throw new Error("No port found");
|
|
5998
|
+
}
|
|
5999
|
+
}
|
|
6000
|
+
var serial = new WebSerialAdapter;
|
|
6001
|
+
|
|
6002
|
+
// src/commands/upload.ts
|
|
6003
|
+
async function uploadProsProgram(path, options) {
|
|
6004
|
+
const hotFile = Bun.file(join4(path, "bin", "hot.package.bin"));
|
|
6005
|
+
const coldFile = Bun.file(join4(path, "bin", "cold.package.bin"));
|
|
6006
|
+
if (!await hotFile.exists() || !await coldFile.exists()) {
|
|
6007
|
+
console.error("no bin files found, run build first");
|
|
6008
|
+
process.exit(1);
|
|
6009
|
+
}
|
|
6010
|
+
const device = new V5SerialDevice(serial);
|
|
6011
|
+
device.autoRefresh = false;
|
|
6012
|
+
const connected = await device.connect();
|
|
6013
|
+
if (!connected) {
|
|
6014
|
+
console.error("no v5 devices found");
|
|
6015
|
+
await device.dispose();
|
|
6016
|
+
process.exit(1);
|
|
6017
|
+
}
|
|
6018
|
+
const ini = new ProgramIniConfig;
|
|
6019
|
+
const uploaded = await device.brain.uploadProgram(ini, Bun.gzipSync(await hotFile.bytes()), Bun.gzipSync(await coldFile.bytes()), (state, current, total) => console.log(state, (current / total * 100).toFixed(1) + "%"));
|
|
6020
|
+
await device.dispose();
|
|
6021
|
+
if (!uploaded) {
|
|
6022
|
+
console.error("upload failed");
|
|
6023
|
+
process.exit(1);
|
|
6024
|
+
}
|
|
6025
|
+
}
|
|
6026
|
+
var upload = new Command("upload").alias("u").description("build a program for the vex v5 brain").argument("[path]", "path to the program", process.cwd()).option("-t, --type <type>", "type of the program").action(async (path, options) => {
|
|
6027
|
+
if (!await exists3(path)) {
|
|
6028
|
+
console.error(`path does not exist: ${path}`);
|
|
6029
|
+
return;
|
|
6030
|
+
}
|
|
6031
|
+
const type = options.type ?? await detectProgramType(path);
|
|
6032
|
+
switch (type) {
|
|
6033
|
+
case "pros":
|
|
6034
|
+
return uploadProsProgram(path, options);
|
|
6035
|
+
case "unknown":
|
|
6036
|
+
console.error("could not detect program type");
|
|
6037
|
+
break;
|
|
6038
|
+
default:
|
|
6039
|
+
console.error(`unknown program type: ${type}`);
|
|
6040
|
+
break;
|
|
6041
|
+
}
|
|
6042
|
+
});
|
|
6043
|
+
|
|
2247
6044
|
// src/index.ts
|
|
2248
|
-
program.name("v5x").description("modern v5 development").version(package_default.version).addCommand(build);
|
|
6045
|
+
program.name("v5x").description("modern v5 development").version(package_default.version).addCommand(build).addCommand(upload);
|
|
2249
6046
|
program.parse();
|