@v5x/cli 0.0.23 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -2
- package/dist/index.js +1426 -1018
- package/dist/index.js.map +22 -19
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1656,7 +1656,7 @@ var lib_default2 = (e, t2) => new o(e, t2);
|
|
|
1656
1656
|
var package_default = {
|
|
1657
1657
|
name: "@v5x/cli",
|
|
1658
1658
|
description: "modern v5 tools",
|
|
1659
|
-
version: "0.0.
|
|
1659
|
+
version: "0.0.24",
|
|
1660
1660
|
module: "dist/index.js",
|
|
1661
1661
|
type: "module",
|
|
1662
1662
|
sideEffects: true,
|
|
@@ -1681,6 +1681,7 @@ var package_default = {
|
|
|
1681
1681
|
typecheck: "tsc --noEmit",
|
|
1682
1682
|
lint: "oxlint src --type-aware",
|
|
1683
1683
|
test: "bun test",
|
|
1684
|
+
"benchmark:screenshot": "bun ./benchmarks/screenshot.ts",
|
|
1684
1685
|
prepack: "bun run --cwd ../serial build && bun run build"
|
|
1685
1686
|
},
|
|
1686
1687
|
devDependencies: {
|
|
@@ -2209,325 +2210,13 @@ var source_default = chalk;
|
|
|
2209
2210
|
import { basename, dirname, join as join2, resolve } from "path";
|
|
2210
2211
|
import { stat } from "fs/promises";
|
|
2211
2212
|
|
|
2212
|
-
//
|
|
2213
|
-
var __defProp2 = Object.defineProperty;
|
|
2214
|
-
var __returnValue2 = (v) => v;
|
|
2215
|
-
function __exportSetter2(name, newValue) {
|
|
2216
|
-
this[name] = __returnValue2.bind(null, newValue);
|
|
2217
|
-
}
|
|
2218
|
-
var __export2 = (target, all) => {
|
|
2219
|
-
for (var name in all)
|
|
2220
|
-
__defProp2(target, name, {
|
|
2221
|
-
get: all[name],
|
|
2222
|
-
enumerable: true,
|
|
2223
|
-
configurable: true,
|
|
2224
|
-
set: __exportSetter2.bind(all, name)
|
|
2225
|
-
});
|
|
2226
|
-
};
|
|
2227
|
-
var USER_PROG_CHUNK_SIZE = 4096;
|
|
2228
|
-
var USER_FLASH_USR_CODE_START = 58720256;
|
|
2229
|
-
var USER_FLASH_MAX_FILE_SIZE = 2097152;
|
|
2230
|
-
var FileVendor;
|
|
2231
|
-
((FileVendor2) => {
|
|
2232
|
-
FileVendor2[FileVendor2["USER"] = 1] = "USER";
|
|
2233
|
-
FileVendor2[FileVendor2["SYS"] = 15] = "SYS";
|
|
2234
|
-
FileVendor2[FileVendor2["DEV1"] = 16] = "DEV1";
|
|
2235
|
-
FileVendor2[FileVendor2["DEV2"] = 24] = "DEV2";
|
|
2236
|
-
FileVendor2[FileVendor2["DEV3"] = 32] = "DEV3";
|
|
2237
|
-
FileVendor2[FileVendor2["DEV4"] = 40] = "DEV4";
|
|
2238
|
-
FileVendor2[FileVendor2["DEV5"] = 48] = "DEV5";
|
|
2239
|
-
FileVendor2[FileVendor2["DEV6"] = 56] = "DEV6";
|
|
2240
|
-
FileVendor2[FileVendor2["VEXVM"] = 64] = "VEXVM";
|
|
2241
|
-
FileVendor2[FileVendor2["VEX"] = 240] = "VEX";
|
|
2242
|
-
FileVendor2[FileVendor2["UNDEFINED"] = 241] = "UNDEFINED";
|
|
2243
|
-
})(FileVendor ||= {});
|
|
2244
|
-
var FileDownloadTarget;
|
|
2245
|
-
((FileDownloadTarget2) => {
|
|
2246
|
-
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_DDR"] = 0] = "FILE_TARGET_DDR";
|
|
2247
|
-
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_QSPI"] = 1] = "FILE_TARGET_QSPI";
|
|
2248
|
-
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_CBUF"] = 2] = "FILE_TARGET_CBUF";
|
|
2249
|
-
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_VBUF"] = 3] = "FILE_TARGET_VBUF";
|
|
2250
|
-
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_DDRC"] = 4] = "FILE_TARGET_DDRC";
|
|
2251
|
-
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_DDRE"] = 5] = "FILE_TARGET_DDRE";
|
|
2252
|
-
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_FLASH"] = 6] = "FILE_TARGET_FLASH";
|
|
2253
|
-
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_RADIO"] = 7] = "FILE_TARGET_RADIO";
|
|
2254
|
-
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_A1"] = 13] = "FILE_TARGET_A1";
|
|
2255
|
-
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_B1"] = 14] = "FILE_TARGET_B1";
|
|
2256
|
-
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_B2"] = 15] = "FILE_TARGET_B2";
|
|
2257
|
-
})(FileDownloadTarget ||= {});
|
|
2258
|
-
var FileInitAction;
|
|
2259
|
-
((FileInitAction2) => {
|
|
2260
|
-
FileInitAction2[FileInitAction2["WRITE"] = 1] = "WRITE";
|
|
2261
|
-
FileInitAction2[FileInitAction2["READ"] = 2] = "READ";
|
|
2262
|
-
})(FileInitAction ||= {});
|
|
2263
|
-
var FileInitOption;
|
|
2264
|
-
((FileInitOption2) => {
|
|
2265
|
-
FileInitOption2[FileInitOption2["NONE"] = 0] = "NONE";
|
|
2266
|
-
FileInitOption2[FileInitOption2["OVERWRITE"] = 1] = "OVERWRITE";
|
|
2267
|
-
})(FileInitOption ||= {});
|
|
2268
|
-
var FileLoadAction;
|
|
2269
|
-
((FileLoadAction2) => {
|
|
2270
|
-
FileLoadAction2[FileLoadAction2["RUN"] = 0] = "RUN";
|
|
2271
|
-
FileLoadAction2[FileLoadAction2["STOP"] = 128] = "STOP";
|
|
2272
|
-
})(FileLoadAction ||= {});
|
|
2273
|
-
var FileExitAction;
|
|
2274
|
-
((FileExitAction2) => {
|
|
2275
|
-
FileExitAction2[FileExitAction2["EXIT_NONE"] = 0] = "EXIT_NONE";
|
|
2276
|
-
FileExitAction2[FileExitAction2["EXIT_RUN"] = 1] = "EXIT_RUN";
|
|
2277
|
-
FileExitAction2[FileExitAction2["EXIT_HALT"] = 3] = "EXIT_HALT";
|
|
2278
|
-
})(FileExitAction ||= {});
|
|
2279
|
-
var RadioChannelType;
|
|
2280
|
-
((RadioChannelType2) => {
|
|
2281
|
-
RadioChannelType2[RadioChannelType2["PIT"] = 0] = "PIT";
|
|
2282
|
-
RadioChannelType2[RadioChannelType2["DOWNLOAD"] = 1] = "DOWNLOAD";
|
|
2283
|
-
})(RadioChannelType ||= {});
|
|
2284
|
-
var AckType;
|
|
2285
|
-
((AckType2) => {
|
|
2286
|
-
AckType2[AckType2["CDC2_ACK"] = 118] = "CDC2_ACK";
|
|
2287
|
-
AckType2[AckType2["CDC2_NACK"] = 255] = "CDC2_NACK";
|
|
2288
|
-
AckType2[AckType2["CDC2_NACK_PACKET_CRC"] = 206] = "CDC2_NACK_PACKET_CRC";
|
|
2289
|
-
AckType2[AckType2["CDC2_NACK_CMD_LENGTH"] = 208] = "CDC2_NACK_CMD_LENGTH";
|
|
2290
|
-
AckType2[AckType2["CDC2_NACK_SIZE"] = 209] = "CDC2_NACK_SIZE";
|
|
2291
|
-
AckType2[AckType2["CDC2_NACK_CRC"] = 210] = "CDC2_NACK_CRC";
|
|
2292
|
-
AckType2[AckType2["CDC2_NACK_FILE"] = 211] = "CDC2_NACK_FILE";
|
|
2293
|
-
AckType2[AckType2["CDC2_NACK_INIT"] = 212] = "CDC2_NACK_INIT";
|
|
2294
|
-
AckType2[AckType2["CDC2_NACK_FUNC"] = 213] = "CDC2_NACK_FUNC";
|
|
2295
|
-
AckType2[AckType2["CDC2_NACK_ALIGN"] = 214] = "CDC2_NACK_ALIGN";
|
|
2296
|
-
AckType2[AckType2["CDC2_NACK_ADDR"] = 215] = "CDC2_NACK_ADDR";
|
|
2297
|
-
AckType2[AckType2["CDC2_NACK_INCOMPLETE"] = 216] = "CDC2_NACK_INCOMPLETE";
|
|
2298
|
-
AckType2[AckType2["CDC2_NACK_DIR_INDEX"] = 217] = "CDC2_NACK_DIR_INDEX";
|
|
2299
|
-
AckType2[AckType2["CDC2_NACK_MAX_USER_FILES"] = 218] = "CDC2_NACK_MAX_USER_FILES";
|
|
2300
|
-
AckType2[AckType2["CDC2_NACK_FILE_EXISTS"] = 219] = "CDC2_NACK_FILE_EXISTS";
|
|
2301
|
-
AckType2[AckType2["CDC2_NACK_FILE_SYS_FULL"] = 220] = "CDC2_NACK_FILE_SYS_FULL";
|
|
2302
|
-
AckType2[AckType2["TIMEOUT"] = 256] = "TIMEOUT";
|
|
2303
|
-
AckType2[AckType2["WRITE_ERROR"] = 257] = "WRITE_ERROR";
|
|
2304
|
-
})(AckType ||= {});
|
|
2305
|
-
var SmartDeviceType;
|
|
2306
|
-
((SmartDeviceType2) => {
|
|
2307
|
-
SmartDeviceType2[SmartDeviceType2["EMPTY"] = 0] = "EMPTY";
|
|
2308
|
-
SmartDeviceType2[SmartDeviceType2["V5_POWER"] = 1] = "V5_POWER";
|
|
2309
|
-
SmartDeviceType2[SmartDeviceType2["MOTOR"] = 2] = "MOTOR";
|
|
2310
|
-
SmartDeviceType2[SmartDeviceType2["LED"] = 3] = "LED";
|
|
2311
|
-
SmartDeviceType2[SmartDeviceType2["ABS_ENCODER_SENSOR"] = 4] = "ABS_ENCODER_SENSOR";
|
|
2312
|
-
SmartDeviceType2[SmartDeviceType2["CR_MOTOR"] = 5] = "CR_MOTOR";
|
|
2313
|
-
SmartDeviceType2[SmartDeviceType2["IMU_SENSOR"] = 6] = "IMU_SENSOR";
|
|
2314
|
-
SmartDeviceType2[SmartDeviceType2["DISTANCE_SENSOR"] = 7] = "DISTANCE_SENSOR";
|
|
2315
|
-
SmartDeviceType2[SmartDeviceType2["RADIO_SENSOR"] = 8] = "RADIO_SENSOR";
|
|
2316
|
-
SmartDeviceType2[SmartDeviceType2["CONTROLLER"] = 9] = "CONTROLLER";
|
|
2317
|
-
SmartDeviceType2[SmartDeviceType2["BRAIN"] = 10] = "BRAIN";
|
|
2318
|
-
SmartDeviceType2[SmartDeviceType2["VISION_SENSOR"] = 11] = "VISION_SENSOR";
|
|
2319
|
-
SmartDeviceType2[SmartDeviceType2["ADI"] = 12] = "ADI";
|
|
2320
|
-
SmartDeviceType2[SmartDeviceType2["PARTNER_CONTROLLER"] = 13] = "PARTNER_CONTROLLER";
|
|
2321
|
-
SmartDeviceType2[SmartDeviceType2["BATTERY"] = 14] = "BATTERY";
|
|
2322
|
-
SmartDeviceType2[SmartDeviceType2["SOL"] = 15] = "SOL";
|
|
2323
|
-
SmartDeviceType2[SmartDeviceType2["OPTICAL_SENSOR"] = 16] = "OPTICAL_SENSOR";
|
|
2324
|
-
SmartDeviceType2[SmartDeviceType2["MAGNET"] = 17] = "MAGNET";
|
|
2325
|
-
SmartDeviceType2[SmartDeviceType2["GPS_SENSOR"] = 20] = "GPS_SENSOR";
|
|
2326
|
-
SmartDeviceType2[SmartDeviceType2["UNDEFINED_SENSOR"] = 255] = "UNDEFINED_SENSOR";
|
|
2327
|
-
})(SmartDeviceType ||= {});
|
|
2328
|
-
var SerialDeviceType;
|
|
2329
|
-
((SerialDeviceType2) => {
|
|
2330
|
-
SerialDeviceType2[SerialDeviceType2["V5_BRAIN"] = 1281] = "V5_BRAIN";
|
|
2331
|
-
SerialDeviceType2[SerialDeviceType2["V5_BRAIN_DFU"] = 1282] = "V5_BRAIN_DFU";
|
|
2332
|
-
SerialDeviceType2[SerialDeviceType2["V5_CONTROLLER"] = 1283] = "V5_CONTROLLER";
|
|
2333
|
-
SerialDeviceType2[SerialDeviceType2["XILINX"] = 256] = "XILINX";
|
|
2334
|
-
SerialDeviceType2[SerialDeviceType2["IQ_BRAIN"] = 2] = "IQ_BRAIN";
|
|
2335
|
-
SerialDeviceType2[SerialDeviceType2["IQ_BRAIN2"] = 3] = "IQ_BRAIN2";
|
|
2336
|
-
SerialDeviceType2[SerialDeviceType2["IQ_BRAIN_DFU"] = 255] = "IQ_BRAIN_DFU";
|
|
2337
|
-
SerialDeviceType2[SerialDeviceType2["IQ2_BRAIN"] = 512] = "IQ2_BRAIN";
|
|
2338
|
-
SerialDeviceType2[SerialDeviceType2["IQ2_BRAIN_DFU"] = 527] = "IQ2_BRAIN_DFU";
|
|
2339
|
-
SerialDeviceType2[SerialDeviceType2["IQ2_CONTROLLER"] = 528] = "IQ2_CONTROLLER";
|
|
2340
|
-
SerialDeviceType2[SerialDeviceType2["IQ2_CONTROLLER_DFU"] = 543] = "IQ2_CONTROLLER_DFU";
|
|
2341
|
-
SerialDeviceType2[SerialDeviceType2["EXP_BRAIN"] = 1536] = "EXP_BRAIN";
|
|
2342
|
-
SerialDeviceType2[SerialDeviceType2["EXP_BRAIN_DFU"] = 1551] = "EXP_BRAIN_DFU";
|
|
2343
|
-
SerialDeviceType2[SerialDeviceType2["EXP_CONTROLLER"] = 1552] = "EXP_CONTROLLER";
|
|
2344
|
-
SerialDeviceType2[SerialDeviceType2["EXP_CONTROLLER_DFU"] = 1567] = "EXP_CONTROLLER_DFU";
|
|
2345
|
-
SerialDeviceType2[SerialDeviceType2["PIXY"] = 61440] = "PIXY";
|
|
2346
|
-
SerialDeviceType2[SerialDeviceType2["PIXY_DFU"] = 12] = "PIXY_DFU";
|
|
2347
|
-
SerialDeviceType2[SerialDeviceType2["VEXCAM"] = 1287] = "VEXCAM";
|
|
2348
|
-
SerialDeviceType2[SerialDeviceType2["VEXCAM_DFU"] = 1288] = "VEXCAM_DFU";
|
|
2349
|
-
SerialDeviceType2[SerialDeviceType2["SENSOR_TEST"] = 1535] = "SENSOR_TEST";
|
|
2350
|
-
SerialDeviceType2[SerialDeviceType2["CORTEX_PROGCBL"] = 10] = "CORTEX_PROGCBL";
|
|
2351
|
-
SerialDeviceType2[SerialDeviceType2["CORTEX_BRAIN"] = 11] = "CORTEX_BRAIN";
|
|
2352
|
-
SerialDeviceType2[SerialDeviceType2["CORTEX_JOYSTK"] = 12] = "CORTEX_JOYSTK";
|
|
2353
|
-
SerialDeviceType2[SerialDeviceType2["VEXNET_KEY_20"] = 7] = "VEXNET_KEY_20";
|
|
2354
|
-
SerialDeviceType2[SerialDeviceType2["VEXNET_KEY_10"] = 9587] = "VEXNET_KEY_10";
|
|
2355
|
-
SerialDeviceType2[SerialDeviceType2["PROLIFIC"] = 8963] = "PROLIFIC";
|
|
2356
|
-
})(SerialDeviceType ||= {});
|
|
2357
|
-
var SelectDashScreen;
|
|
2358
|
-
((SelectDashScreen2) => {
|
|
2359
|
-
SelectDashScreen2[SelectDashScreen2["HOME"] = 0] = "HOME";
|
|
2360
|
-
SelectDashScreen2[SelectDashScreen2["BATTERY"] = 1] = "BATTERY";
|
|
2361
|
-
SelectDashScreen2[SelectDashScreen2["LED"] = 3] = "LED";
|
|
2362
|
-
SelectDashScreen2[SelectDashScreen2["MATCH_CONFIG"] = 4] = "MATCH_CONFIG";
|
|
2363
|
-
SelectDashScreen2[SelectDashScreen2["MATCH_CONFIG_MORE"] = 5] = "MATCH_CONFIG_MORE";
|
|
2364
|
-
SelectDashScreen2[SelectDashScreen2["WIRING"] = 6] = "WIRING";
|
|
2365
|
-
SelectDashScreen2[SelectDashScreen2["RADIO"] = 8] = "RADIO";
|
|
2366
|
-
SelectDashScreen2[SelectDashScreen2["BRAIN"] = 10] = "BRAIN";
|
|
2367
|
-
SelectDashScreen2[SelectDashScreen2["RUN_PROGRAM"] = 13] = "RUN_PROGRAM";
|
|
2368
|
-
SelectDashScreen2[SelectDashScreen2["DRIVE_PROGRAM_CONTROL_LEFT_MAPPING"] = 14] = "DRIVE_PROGRAM_CONTROL_LEFT_MAPPING";
|
|
2369
|
-
SelectDashScreen2[SelectDashScreen2["DRIVE_PROGRAM_MENU"] = 15] = "DRIVE_PROGRAM_MENU";
|
|
2370
|
-
SelectDashScreen2[SelectDashScreen2["DEVICES"] = 16] = "DEVICES";
|
|
2371
|
-
SelectDashScreen2[SelectDashScreen2["USER_PROGRAM_FOLDER"] = 17] = "USER_PROGRAM_FOLDER";
|
|
2372
|
-
SelectDashScreen2[SelectDashScreen2["VEX_PROGRAM_FOLDER"] = 18] = "VEX_PROGRAM_FOLDER";
|
|
2373
|
-
SelectDashScreen2[SelectDashScreen2["SETTINGS"] = 19] = "SETTINGS";
|
|
2374
|
-
SelectDashScreen2[SelectDashScreen2["SCARY_CONFIGURATION"] = 20] = "SCARY_CONFIGURATION";
|
|
2375
|
-
SelectDashScreen2[SelectDashScreen2["LANGUAGE"] = 21] = "LANGUAGE";
|
|
2376
|
-
SelectDashScreen2[SelectDashScreen2["DRIVE_MOTOR_CONFIG"] = 22] = "DRIVE_MOTOR_CONFIG";
|
|
2377
|
-
SelectDashScreen2[SelectDashScreen2["PROGRAM_MENU"] = 24] = "PROGRAM_MENU";
|
|
2378
|
-
SelectDashScreen2[SelectDashScreen2["SHUTDOWN"] = 25] = "SHUTDOWN";
|
|
2379
|
-
SelectDashScreen2[SelectDashScreen2["CONTROLLER_2_MAPPING"] = 26] = "CONTROLLER_2_MAPPING";
|
|
2380
|
-
SelectDashScreen2[SelectDashScreen2["SCARY_CONFIGURATION_MORE"] = 27] = "SCARY_CONFIGURATION_MORE";
|
|
2381
|
-
SelectDashScreen2[SelectDashScreen2["CONFIRM_XX"] = 28] = "CONFIRM_XX";
|
|
2382
|
-
SelectDashScreen2[SelectDashScreen2["CONTROLLER_1_MAPPING"] = 29] = "CONTROLLER_1_MAPPING";
|
|
2383
|
-
SelectDashScreen2[SelectDashScreen2["DRIVE_PROGRAM_CONTROL_DUAL_MAPPING"] = 30] = "DRIVE_PROGRAM_CONTROL_DUAL_MAPPING";
|
|
2384
|
-
SelectDashScreen2[SelectDashScreen2["DRIVE_PROGRAM_CONTROL_SPLIT_MAPPING"] = 31] = "DRIVE_PROGRAM_CONTROL_SPLIT_MAPPING";
|
|
2385
|
-
SelectDashScreen2[SelectDashScreen2["DRIVE_PROGRAM_CONTROL_RIGHT_MAPPING"] = 32] = "DRIVE_PROGRAM_CONTROL_RIGHT_MAPPING";
|
|
2386
|
-
SelectDashScreen2[SelectDashScreen2["MATCH_2_4_PLAYERS"] = 33] = "MATCH_2_4_PLAYERS";
|
|
2387
|
-
SelectDashScreen2[SelectDashScreen2["EVENT_LOG"] = 34] = "EVENT_LOG";
|
|
2388
|
-
SelectDashScreen2[SelectDashScreen2["USER_PROGRAM_WIRING"] = 40] = "USER_PROGRAM_WIRING";
|
|
2389
|
-
SelectDashScreen2[SelectDashScreen2["CLAWBOT_PROGRAM_MENU"] = 41] = "CLAWBOT_PROGRAM_MENU";
|
|
2390
|
-
SelectDashScreen2[SelectDashScreen2["ABOUT"] = 42] = "ABOUT";
|
|
2391
|
-
SelectDashScreen2[SelectDashScreen2["LANGUAGE_MORE"] = 43] = "LANGUAGE_MORE";
|
|
2392
|
-
SelectDashScreen2[SelectDashScreen2["OBJECT_COLOR"] = 45] = "OBJECT_COLOR";
|
|
2393
|
-
SelectDashScreen2[SelectDashScreen2["SIGNATURE_ID"] = 46] = "SIGNATURE_ID";
|
|
2394
|
-
SelectDashScreen2[SelectDashScreen2["LOG_DATA"] = 47] = "LOG_DATA";
|
|
2395
|
-
})(SelectDashScreen ||= {});
|
|
2396
|
-
|
|
2397
|
-
class VexSerialError extends Error {
|
|
2398
|
-
kind;
|
|
2399
|
-
ackType = undefined;
|
|
2400
|
-
constructor(kind, message) {
|
|
2401
|
-
super(message);
|
|
2402
|
-
this.name = "VexSerialError";
|
|
2403
|
-
this.kind = kind;
|
|
2404
|
-
}
|
|
2405
|
-
}
|
|
2406
|
-
|
|
2407
|
-
class VexNotConnectedError extends VexSerialError {
|
|
2408
|
-
constructor(message = "no connection to a V5 device") {
|
|
2409
|
-
super("not-connected", message);
|
|
2410
|
-
this.name = "VexNotConnectedError";
|
|
2411
|
-
}
|
|
2412
|
-
}
|
|
2413
|
-
|
|
2414
|
-
class VexInvalidArgumentError extends VexSerialError {
|
|
2415
|
-
constructor(message) {
|
|
2416
|
-
super("invalid-argument", message);
|
|
2417
|
-
this.name = "VexInvalidArgumentError";
|
|
2418
|
-
}
|
|
2419
|
-
}
|
|
2420
|
-
|
|
2421
|
-
class VexProtocolError extends VexSerialError {
|
|
2422
|
-
ackType;
|
|
2423
|
-
constructor(message, ackType) {
|
|
2424
|
-
super("protocol", message);
|
|
2425
|
-
this.name = "VexProtocolError";
|
|
2426
|
-
this.ackType = ackType;
|
|
2427
|
-
}
|
|
2428
|
-
}
|
|
2429
|
-
|
|
2430
|
-
class VexTransferError extends VexSerialError {
|
|
2431
|
-
constructor(message) {
|
|
2432
|
-
super("transfer", message);
|
|
2433
|
-
this.name = "VexTransferError";
|
|
2434
|
-
}
|
|
2435
|
-
}
|
|
2436
|
-
|
|
2437
|
-
class VexDownloadError extends VexSerialError {
|
|
2438
|
-
constructor(message) {
|
|
2439
|
-
super("download", message);
|
|
2440
|
-
this.name = "VexDownloadError";
|
|
2441
|
-
}
|
|
2442
|
-
}
|
|
2443
|
-
|
|
2444
|
-
class VexFirmwareError extends VexSerialError {
|
|
2445
|
-
constructor(message) {
|
|
2446
|
-
super("firmware", message);
|
|
2447
|
-
this.name = "VexFirmwareError";
|
|
2448
|
-
}
|
|
2449
|
-
}
|
|
2450
|
-
|
|
2451
|
-
class VexIoError extends VexSerialError {
|
|
2452
|
-
constructor(message) {
|
|
2453
|
-
super("io", message);
|
|
2454
|
-
this.name = "VexIoError";
|
|
2455
|
-
}
|
|
2456
|
-
}
|
|
2457
|
-
function toVexSerialError(error, fallback = "io") {
|
|
2458
|
-
if (error instanceof VexSerialError)
|
|
2459
|
-
return error;
|
|
2460
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
2461
|
-
return new VexSerialError(fallback, message);
|
|
2462
|
-
}
|
|
2463
|
-
|
|
2464
|
-
class VexEventEmitter {
|
|
2465
|
-
handlerMap;
|
|
2466
|
-
constructor() {
|
|
2467
|
-
this.handlerMap = new Map;
|
|
2468
|
-
}
|
|
2469
|
-
on(eventName, listener) {
|
|
2470
|
-
let listeners = this.handlerMap.get(eventName);
|
|
2471
|
-
listeners ??= [];
|
|
2472
|
-
listeners.push(listener);
|
|
2473
|
-
this.handlerMap.set(eventName, listeners);
|
|
2474
|
-
}
|
|
2475
|
-
remove(eventName, listener) {
|
|
2476
|
-
let listeners = this.handlerMap.get(eventName);
|
|
2477
|
-
listeners ??= [];
|
|
2478
|
-
const index = listeners.indexOf(listener);
|
|
2479
|
-
if (index > -1) {
|
|
2480
|
-
listeners.splice(index, 1);
|
|
2481
|
-
}
|
|
2482
|
-
this.handlerMap.set(eventName, listeners);
|
|
2483
|
-
}
|
|
2484
|
-
emit(eventName, data) {
|
|
2485
|
-
const errors = [];
|
|
2486
|
-
for (const callback of [...this.handlerMap.get(eventName) ?? []]) {
|
|
2487
|
-
try {
|
|
2488
|
-
callback(data);
|
|
2489
|
-
} catch (error) {
|
|
2490
|
-
errors.push(error);
|
|
2491
|
-
}
|
|
2492
|
-
}
|
|
2493
|
-
if (errors.length === 1)
|
|
2494
|
-
throw errors[0];
|
|
2495
|
-
if (errors.length > 1) {
|
|
2496
|
-
throw new AggregateError(errors, `listeners for ${String(eventName)} failed`);
|
|
2497
|
-
}
|
|
2498
|
-
}
|
|
2499
|
-
clearListeners() {
|
|
2500
|
-
this.handlerMap.clear();
|
|
2501
|
-
}
|
|
2502
|
-
}
|
|
2503
|
-
|
|
2504
|
-
class VexEventTarget {
|
|
2505
|
-
emitter;
|
|
2506
|
-
constructor() {
|
|
2507
|
-
this.emitter = new VexEventEmitter;
|
|
2508
|
-
}
|
|
2509
|
-
emit(eventName, data) {
|
|
2510
|
-
this.emitter.emit(this.normalizeEventName(eventName), data);
|
|
2511
|
-
}
|
|
2512
|
-
on(eventName, listener) {
|
|
2513
|
-
this.emitter.on(this.normalizeEventName(eventName), listener);
|
|
2514
|
-
}
|
|
2515
|
-
remove(eventName, listener) {
|
|
2516
|
-
this.emitter.remove(this.normalizeEventName(eventName), listener);
|
|
2517
|
-
}
|
|
2518
|
-
clearListeners() {
|
|
2519
|
-
this.emitter.clearListeners();
|
|
2520
|
-
}
|
|
2521
|
-
normalizeEventName(eventName) {
|
|
2522
|
-
return String(eventName);
|
|
2523
|
-
}
|
|
2524
|
-
}
|
|
2213
|
+
// ../../node_modules/.bun/neverthrow@8.2.0/node_modules/neverthrow/dist/index.es.js
|
|
2525
2214
|
var defaultErrorConfig = {
|
|
2526
2215
|
withStackTrace: false
|
|
2527
2216
|
};
|
|
2528
|
-
var createNeverThrowError = (message, result,
|
|
2217
|
+
var createNeverThrowError = (message, result, config = defaultErrorConfig) => {
|
|
2529
2218
|
const data = result.isOk() ? { type: "Ok", value: result.value } : { type: "Err", value: result.error };
|
|
2530
|
-
const maybeStack =
|
|
2219
|
+
const maybeStack = config.withStackTrace ? new Error().stack : undefined;
|
|
2531
2220
|
return {
|
|
2532
2221
|
data,
|
|
2533
2222
|
message,
|
|
@@ -2655,7 +2344,6 @@ function __asyncValues(o2) {
|
|
|
2655
2344
|
}, reject);
|
|
2656
2345
|
}
|
|
2657
2346
|
}
|
|
2658
|
-
|
|
2659
2347
|
class ResultAsync {
|
|
2660
2348
|
constructor(res) {
|
|
2661
2349
|
this._promise = res;
|
|
@@ -2767,7 +2455,7 @@ class ResultAsync {
|
|
|
2767
2455
|
return this._promise.then(successCallback, failureCallback);
|
|
2768
2456
|
}
|
|
2769
2457
|
[Symbol.asyncIterator]() {
|
|
2770
|
-
return __asyncGenerator(this, arguments, function*
|
|
2458
|
+
return __asyncGenerator(this, arguments, function* _a() {
|
|
2771
2459
|
const result = yield __await(this._promise);
|
|
2772
2460
|
if (result.isErr()) {
|
|
2773
2461
|
yield yield __await(errAsync(result.error));
|
|
@@ -2837,7 +2525,6 @@ function ok(value) {
|
|
|
2837
2525
|
function err(err2) {
|
|
2838
2526
|
return new Err(err2);
|
|
2839
2527
|
}
|
|
2840
|
-
|
|
2841
2528
|
class Ok {
|
|
2842
2529
|
constructor(value) {
|
|
2843
2530
|
this.value = value;
|
|
@@ -2896,83 +2583,388 @@ class Ok {
|
|
|
2896
2583
|
_unsafeUnwrap(_) {
|
|
2897
2584
|
return this.value;
|
|
2898
2585
|
}
|
|
2899
|
-
_unsafeUnwrapErr(
|
|
2900
|
-
throw createNeverThrowError("Called `_unsafeUnwrapErr` on an Ok", this,
|
|
2586
|
+
_unsafeUnwrapErr(config) {
|
|
2587
|
+
throw createNeverThrowError("Called `_unsafeUnwrapErr` on an Ok", this, config);
|
|
2901
2588
|
}
|
|
2902
2589
|
*[Symbol.iterator]() {
|
|
2903
2590
|
return this.value;
|
|
2904
2591
|
}
|
|
2905
2592
|
}
|
|
2906
2593
|
|
|
2907
|
-
class Err {
|
|
2908
|
-
constructor(error) {
|
|
2909
|
-
this.error = error;
|
|
2910
|
-
}
|
|
2911
|
-
isOk() {
|
|
2912
|
-
return false;
|
|
2913
|
-
}
|
|
2914
|
-
isErr() {
|
|
2915
|
-
return !this.isOk();
|
|
2594
|
+
class Err {
|
|
2595
|
+
constructor(error) {
|
|
2596
|
+
this.error = error;
|
|
2597
|
+
}
|
|
2598
|
+
isOk() {
|
|
2599
|
+
return false;
|
|
2600
|
+
}
|
|
2601
|
+
isErr() {
|
|
2602
|
+
return !this.isOk();
|
|
2603
|
+
}
|
|
2604
|
+
map(_f) {
|
|
2605
|
+
return err(this.error);
|
|
2606
|
+
}
|
|
2607
|
+
mapErr(f) {
|
|
2608
|
+
return err(f(this.error));
|
|
2609
|
+
}
|
|
2610
|
+
andThrough(_f) {
|
|
2611
|
+
return err(this.error);
|
|
2612
|
+
}
|
|
2613
|
+
andTee(_f) {
|
|
2614
|
+
return err(this.error);
|
|
2615
|
+
}
|
|
2616
|
+
orTee(f) {
|
|
2617
|
+
try {
|
|
2618
|
+
f(this.error);
|
|
2619
|
+
} catch (e) {}
|
|
2620
|
+
return err(this.error);
|
|
2621
|
+
}
|
|
2622
|
+
andThen(_f) {
|
|
2623
|
+
return err(this.error);
|
|
2624
|
+
}
|
|
2625
|
+
orElse(f) {
|
|
2626
|
+
return f(this.error);
|
|
2627
|
+
}
|
|
2628
|
+
asyncAndThen(_f) {
|
|
2629
|
+
return errAsync(this.error);
|
|
2630
|
+
}
|
|
2631
|
+
asyncAndThrough(_f) {
|
|
2632
|
+
return errAsync(this.error);
|
|
2633
|
+
}
|
|
2634
|
+
asyncMap(_f) {
|
|
2635
|
+
return errAsync(this.error);
|
|
2636
|
+
}
|
|
2637
|
+
unwrapOr(v) {
|
|
2638
|
+
return v;
|
|
2639
|
+
}
|
|
2640
|
+
match(_ok, err2) {
|
|
2641
|
+
return err2(this.error);
|
|
2642
|
+
}
|
|
2643
|
+
safeUnwrap() {
|
|
2644
|
+
const error = this.error;
|
|
2645
|
+
return function* () {
|
|
2646
|
+
yield err(error);
|
|
2647
|
+
throw new Error("Do not use this generator out of `safeTry`");
|
|
2648
|
+
}();
|
|
2649
|
+
}
|
|
2650
|
+
_unsafeUnwrap(config) {
|
|
2651
|
+
throw createNeverThrowError("Called `_unsafeUnwrap` on an Err", this, config);
|
|
2652
|
+
}
|
|
2653
|
+
_unsafeUnwrapErr(_) {
|
|
2654
|
+
return this.error;
|
|
2655
|
+
}
|
|
2656
|
+
*[Symbol.iterator]() {
|
|
2657
|
+
const self = this;
|
|
2658
|
+
yield self;
|
|
2659
|
+
return self;
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
var fromThrowable = Result.fromThrowable;
|
|
2663
|
+
|
|
2664
|
+
// ../serial/dist/index.js
|
|
2665
|
+
var USER_PROG_CHUNK_SIZE = 4096;
|
|
2666
|
+
var USER_FLASH_USR_CODE_START = 58720256;
|
|
2667
|
+
var USER_FLASH_MAX_FILE_SIZE = 2097152;
|
|
2668
|
+
var FileVendor;
|
|
2669
|
+
((FileVendor2) => {
|
|
2670
|
+
FileVendor2[FileVendor2["USER"] = 1] = "USER";
|
|
2671
|
+
FileVendor2[FileVendor2["SYS"] = 15] = "SYS";
|
|
2672
|
+
FileVendor2[FileVendor2["DEV1"] = 16] = "DEV1";
|
|
2673
|
+
FileVendor2[FileVendor2["DEV2"] = 24] = "DEV2";
|
|
2674
|
+
FileVendor2[FileVendor2["DEV3"] = 32] = "DEV3";
|
|
2675
|
+
FileVendor2[FileVendor2["DEV4"] = 40] = "DEV4";
|
|
2676
|
+
FileVendor2[FileVendor2["DEV5"] = 48] = "DEV5";
|
|
2677
|
+
FileVendor2[FileVendor2["DEV6"] = 56] = "DEV6";
|
|
2678
|
+
FileVendor2[FileVendor2["VEXVM"] = 64] = "VEXVM";
|
|
2679
|
+
FileVendor2[FileVendor2["VEX"] = 240] = "VEX";
|
|
2680
|
+
FileVendor2[FileVendor2["UNDEFINED"] = 241] = "UNDEFINED";
|
|
2681
|
+
})(FileVendor ||= {});
|
|
2682
|
+
var FileDownloadTarget;
|
|
2683
|
+
((FileDownloadTarget2) => {
|
|
2684
|
+
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_DDR"] = 0] = "FILE_TARGET_DDR";
|
|
2685
|
+
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_QSPI"] = 1] = "FILE_TARGET_QSPI";
|
|
2686
|
+
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_CBUF"] = 2] = "FILE_TARGET_CBUF";
|
|
2687
|
+
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_VBUF"] = 3] = "FILE_TARGET_VBUF";
|
|
2688
|
+
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_DDRC"] = 4] = "FILE_TARGET_DDRC";
|
|
2689
|
+
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_DDRE"] = 5] = "FILE_TARGET_DDRE";
|
|
2690
|
+
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_FLASH"] = 6] = "FILE_TARGET_FLASH";
|
|
2691
|
+
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_RADIO"] = 7] = "FILE_TARGET_RADIO";
|
|
2692
|
+
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_A1"] = 13] = "FILE_TARGET_A1";
|
|
2693
|
+
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_B1"] = 14] = "FILE_TARGET_B1";
|
|
2694
|
+
FileDownloadTarget2[FileDownloadTarget2["FILE_TARGET_B2"] = 15] = "FILE_TARGET_B2";
|
|
2695
|
+
})(FileDownloadTarget ||= {});
|
|
2696
|
+
var FileInitAction;
|
|
2697
|
+
((FileInitAction2) => {
|
|
2698
|
+
FileInitAction2[FileInitAction2["WRITE"] = 1] = "WRITE";
|
|
2699
|
+
FileInitAction2[FileInitAction2["READ"] = 2] = "READ";
|
|
2700
|
+
})(FileInitAction ||= {});
|
|
2701
|
+
var FileInitOption;
|
|
2702
|
+
((FileInitOption2) => {
|
|
2703
|
+
FileInitOption2[FileInitOption2["NONE"] = 0] = "NONE";
|
|
2704
|
+
FileInitOption2[FileInitOption2["OVERWRITE"] = 1] = "OVERWRITE";
|
|
2705
|
+
})(FileInitOption ||= {});
|
|
2706
|
+
var FileLoadAction;
|
|
2707
|
+
((FileLoadAction2) => {
|
|
2708
|
+
FileLoadAction2[FileLoadAction2["RUN"] = 0] = "RUN";
|
|
2709
|
+
FileLoadAction2[FileLoadAction2["STOP"] = 128] = "STOP";
|
|
2710
|
+
})(FileLoadAction ||= {});
|
|
2711
|
+
var FileExitAction;
|
|
2712
|
+
((FileExitAction2) => {
|
|
2713
|
+
FileExitAction2[FileExitAction2["EXIT_NONE"] = 0] = "EXIT_NONE";
|
|
2714
|
+
FileExitAction2[FileExitAction2["EXIT_RUN"] = 1] = "EXIT_RUN";
|
|
2715
|
+
FileExitAction2[FileExitAction2["EXIT_HALT"] = 3] = "EXIT_HALT";
|
|
2716
|
+
})(FileExitAction ||= {});
|
|
2717
|
+
var RadioChannelType;
|
|
2718
|
+
((RadioChannelType2) => {
|
|
2719
|
+
RadioChannelType2[RadioChannelType2["PIT"] = 0] = "PIT";
|
|
2720
|
+
RadioChannelType2[RadioChannelType2["DOWNLOAD"] = 1] = "DOWNLOAD";
|
|
2721
|
+
})(RadioChannelType ||= {});
|
|
2722
|
+
var AckType;
|
|
2723
|
+
((AckType2) => {
|
|
2724
|
+
AckType2[AckType2["CDC2_ACK"] = 118] = "CDC2_ACK";
|
|
2725
|
+
AckType2[AckType2["CDC2_NACK"] = 255] = "CDC2_NACK";
|
|
2726
|
+
AckType2[AckType2["CDC2_NACK_PACKET_CRC"] = 206] = "CDC2_NACK_PACKET_CRC";
|
|
2727
|
+
AckType2[AckType2["CDC2_NACK_CMD_LENGTH"] = 208] = "CDC2_NACK_CMD_LENGTH";
|
|
2728
|
+
AckType2[AckType2["CDC2_NACK_SIZE"] = 209] = "CDC2_NACK_SIZE";
|
|
2729
|
+
AckType2[AckType2["CDC2_NACK_CRC"] = 210] = "CDC2_NACK_CRC";
|
|
2730
|
+
AckType2[AckType2["CDC2_NACK_FILE"] = 211] = "CDC2_NACK_FILE";
|
|
2731
|
+
AckType2[AckType2["CDC2_NACK_INIT"] = 212] = "CDC2_NACK_INIT";
|
|
2732
|
+
AckType2[AckType2["CDC2_NACK_FUNC"] = 213] = "CDC2_NACK_FUNC";
|
|
2733
|
+
AckType2[AckType2["CDC2_NACK_ALIGN"] = 214] = "CDC2_NACK_ALIGN";
|
|
2734
|
+
AckType2[AckType2["CDC2_NACK_ADDR"] = 215] = "CDC2_NACK_ADDR";
|
|
2735
|
+
AckType2[AckType2["CDC2_NACK_INCOMPLETE"] = 216] = "CDC2_NACK_INCOMPLETE";
|
|
2736
|
+
AckType2[AckType2["CDC2_NACK_DIR_INDEX"] = 217] = "CDC2_NACK_DIR_INDEX";
|
|
2737
|
+
AckType2[AckType2["CDC2_NACK_MAX_USER_FILES"] = 218] = "CDC2_NACK_MAX_USER_FILES";
|
|
2738
|
+
AckType2[AckType2["CDC2_NACK_FILE_EXISTS"] = 219] = "CDC2_NACK_FILE_EXISTS";
|
|
2739
|
+
AckType2[AckType2["CDC2_NACK_FILE_SYS_FULL"] = 220] = "CDC2_NACK_FILE_SYS_FULL";
|
|
2740
|
+
AckType2[AckType2["TIMEOUT"] = 256] = "TIMEOUT";
|
|
2741
|
+
AckType2[AckType2["WRITE_ERROR"] = 257] = "WRITE_ERROR";
|
|
2742
|
+
AckType2[AckType2["NOT_CONNECTED"] = 258] = "NOT_CONNECTED";
|
|
2743
|
+
})(AckType ||= {});
|
|
2744
|
+
var SmartDeviceType;
|
|
2745
|
+
((SmartDeviceType2) => {
|
|
2746
|
+
SmartDeviceType2[SmartDeviceType2["EMPTY"] = 0] = "EMPTY";
|
|
2747
|
+
SmartDeviceType2[SmartDeviceType2["V5_POWER"] = 1] = "V5_POWER";
|
|
2748
|
+
SmartDeviceType2[SmartDeviceType2["MOTOR"] = 2] = "MOTOR";
|
|
2749
|
+
SmartDeviceType2[SmartDeviceType2["LED"] = 3] = "LED";
|
|
2750
|
+
SmartDeviceType2[SmartDeviceType2["ABS_ENCODER_SENSOR"] = 4] = "ABS_ENCODER_SENSOR";
|
|
2751
|
+
SmartDeviceType2[SmartDeviceType2["CR_MOTOR"] = 5] = "CR_MOTOR";
|
|
2752
|
+
SmartDeviceType2[SmartDeviceType2["IMU_SENSOR"] = 6] = "IMU_SENSOR";
|
|
2753
|
+
SmartDeviceType2[SmartDeviceType2["DISTANCE_SENSOR"] = 7] = "DISTANCE_SENSOR";
|
|
2754
|
+
SmartDeviceType2[SmartDeviceType2["RADIO_SENSOR"] = 8] = "RADIO_SENSOR";
|
|
2755
|
+
SmartDeviceType2[SmartDeviceType2["CONTROLLER"] = 9] = "CONTROLLER";
|
|
2756
|
+
SmartDeviceType2[SmartDeviceType2["BRAIN"] = 10] = "BRAIN";
|
|
2757
|
+
SmartDeviceType2[SmartDeviceType2["VISION_SENSOR"] = 11] = "VISION_SENSOR";
|
|
2758
|
+
SmartDeviceType2[SmartDeviceType2["ADI"] = 12] = "ADI";
|
|
2759
|
+
SmartDeviceType2[SmartDeviceType2["PARTNER_CONTROLLER"] = 13] = "PARTNER_CONTROLLER";
|
|
2760
|
+
SmartDeviceType2[SmartDeviceType2["BATTERY"] = 14] = "BATTERY";
|
|
2761
|
+
SmartDeviceType2[SmartDeviceType2["SOL"] = 15] = "SOL";
|
|
2762
|
+
SmartDeviceType2[SmartDeviceType2["OPTICAL_SENSOR"] = 16] = "OPTICAL_SENSOR";
|
|
2763
|
+
SmartDeviceType2[SmartDeviceType2["MAGNET"] = 17] = "MAGNET";
|
|
2764
|
+
SmartDeviceType2[SmartDeviceType2["GPS_SENSOR"] = 20] = "GPS_SENSOR";
|
|
2765
|
+
SmartDeviceType2[SmartDeviceType2["UNDEFINED_SENSOR"] = 255] = "UNDEFINED_SENSOR";
|
|
2766
|
+
})(SmartDeviceType ||= {});
|
|
2767
|
+
var SerialDeviceType;
|
|
2768
|
+
((SerialDeviceType2) => {
|
|
2769
|
+
SerialDeviceType2[SerialDeviceType2["V5_BRAIN"] = 1281] = "V5_BRAIN";
|
|
2770
|
+
SerialDeviceType2[SerialDeviceType2["V5_BRAIN_DFU"] = 1282] = "V5_BRAIN_DFU";
|
|
2771
|
+
SerialDeviceType2[SerialDeviceType2["V5_CONTROLLER"] = 1283] = "V5_CONTROLLER";
|
|
2772
|
+
SerialDeviceType2[SerialDeviceType2["XILINX"] = 256] = "XILINX";
|
|
2773
|
+
SerialDeviceType2[SerialDeviceType2["IQ_BRAIN"] = 2] = "IQ_BRAIN";
|
|
2774
|
+
SerialDeviceType2[SerialDeviceType2["IQ_BRAIN2"] = 3] = "IQ_BRAIN2";
|
|
2775
|
+
SerialDeviceType2[SerialDeviceType2["IQ_BRAIN_DFU"] = 255] = "IQ_BRAIN_DFU";
|
|
2776
|
+
SerialDeviceType2[SerialDeviceType2["IQ2_BRAIN"] = 512] = "IQ2_BRAIN";
|
|
2777
|
+
SerialDeviceType2[SerialDeviceType2["IQ2_BRAIN_DFU"] = 527] = "IQ2_BRAIN_DFU";
|
|
2778
|
+
SerialDeviceType2[SerialDeviceType2["IQ2_CONTROLLER"] = 528] = "IQ2_CONTROLLER";
|
|
2779
|
+
SerialDeviceType2[SerialDeviceType2["IQ2_CONTROLLER_DFU"] = 543] = "IQ2_CONTROLLER_DFU";
|
|
2780
|
+
SerialDeviceType2[SerialDeviceType2["EXP_BRAIN"] = 1536] = "EXP_BRAIN";
|
|
2781
|
+
SerialDeviceType2[SerialDeviceType2["EXP_BRAIN_DFU"] = 1551] = "EXP_BRAIN_DFU";
|
|
2782
|
+
SerialDeviceType2[SerialDeviceType2["EXP_CONTROLLER"] = 1552] = "EXP_CONTROLLER";
|
|
2783
|
+
SerialDeviceType2[SerialDeviceType2["EXP_CONTROLLER_DFU"] = 1567] = "EXP_CONTROLLER_DFU";
|
|
2784
|
+
SerialDeviceType2[SerialDeviceType2["PIXY"] = 61440] = "PIXY";
|
|
2785
|
+
SerialDeviceType2[SerialDeviceType2["PIXY_DFU"] = 12] = "PIXY_DFU";
|
|
2786
|
+
SerialDeviceType2[SerialDeviceType2["VEXCAM"] = 1287] = "VEXCAM";
|
|
2787
|
+
SerialDeviceType2[SerialDeviceType2["VEXCAM_DFU"] = 1288] = "VEXCAM_DFU";
|
|
2788
|
+
SerialDeviceType2[SerialDeviceType2["SENSOR_TEST"] = 1535] = "SENSOR_TEST";
|
|
2789
|
+
SerialDeviceType2[SerialDeviceType2["CORTEX_PROGCBL"] = 10] = "CORTEX_PROGCBL";
|
|
2790
|
+
SerialDeviceType2[SerialDeviceType2["CORTEX_BRAIN"] = 11] = "CORTEX_BRAIN";
|
|
2791
|
+
SerialDeviceType2[SerialDeviceType2["CORTEX_JOYSTK"] = 12] = "CORTEX_JOYSTK";
|
|
2792
|
+
SerialDeviceType2[SerialDeviceType2["VEXNET_KEY_20"] = 7] = "VEXNET_KEY_20";
|
|
2793
|
+
SerialDeviceType2[SerialDeviceType2["VEXNET_KEY_10"] = 9587] = "VEXNET_KEY_10";
|
|
2794
|
+
SerialDeviceType2[SerialDeviceType2["PROLIFIC"] = 8963] = "PROLIFIC";
|
|
2795
|
+
})(SerialDeviceType ||= {});
|
|
2796
|
+
var SelectDashScreen;
|
|
2797
|
+
((SelectDashScreen2) => {
|
|
2798
|
+
SelectDashScreen2[SelectDashScreen2["HOME"] = 0] = "HOME";
|
|
2799
|
+
SelectDashScreen2[SelectDashScreen2["BATTERY"] = 1] = "BATTERY";
|
|
2800
|
+
SelectDashScreen2[SelectDashScreen2["LED"] = 3] = "LED";
|
|
2801
|
+
SelectDashScreen2[SelectDashScreen2["MATCH_CONFIG"] = 4] = "MATCH_CONFIG";
|
|
2802
|
+
SelectDashScreen2[SelectDashScreen2["MATCH_CONFIG_MORE"] = 5] = "MATCH_CONFIG_MORE";
|
|
2803
|
+
SelectDashScreen2[SelectDashScreen2["WIRING"] = 6] = "WIRING";
|
|
2804
|
+
SelectDashScreen2[SelectDashScreen2["RADIO"] = 8] = "RADIO";
|
|
2805
|
+
SelectDashScreen2[SelectDashScreen2["BRAIN"] = 10] = "BRAIN";
|
|
2806
|
+
SelectDashScreen2[SelectDashScreen2["RUN_PROGRAM"] = 13] = "RUN_PROGRAM";
|
|
2807
|
+
SelectDashScreen2[SelectDashScreen2["DRIVE_PROGRAM_CONTROL_LEFT_MAPPING"] = 14] = "DRIVE_PROGRAM_CONTROL_LEFT_MAPPING";
|
|
2808
|
+
SelectDashScreen2[SelectDashScreen2["DRIVE_PROGRAM_MENU"] = 15] = "DRIVE_PROGRAM_MENU";
|
|
2809
|
+
SelectDashScreen2[SelectDashScreen2["DEVICES"] = 16] = "DEVICES";
|
|
2810
|
+
SelectDashScreen2[SelectDashScreen2["USER_PROGRAM_FOLDER"] = 17] = "USER_PROGRAM_FOLDER";
|
|
2811
|
+
SelectDashScreen2[SelectDashScreen2["VEX_PROGRAM_FOLDER"] = 18] = "VEX_PROGRAM_FOLDER";
|
|
2812
|
+
SelectDashScreen2[SelectDashScreen2["SETTINGS"] = 19] = "SETTINGS";
|
|
2813
|
+
SelectDashScreen2[SelectDashScreen2["SCARY_CONFIGURATION"] = 20] = "SCARY_CONFIGURATION";
|
|
2814
|
+
SelectDashScreen2[SelectDashScreen2["LANGUAGE"] = 21] = "LANGUAGE";
|
|
2815
|
+
SelectDashScreen2[SelectDashScreen2["DRIVE_MOTOR_CONFIG"] = 22] = "DRIVE_MOTOR_CONFIG";
|
|
2816
|
+
SelectDashScreen2[SelectDashScreen2["PROGRAM_MENU"] = 24] = "PROGRAM_MENU";
|
|
2817
|
+
SelectDashScreen2[SelectDashScreen2["SHUTDOWN"] = 25] = "SHUTDOWN";
|
|
2818
|
+
SelectDashScreen2[SelectDashScreen2["CONTROLLER_2_MAPPING"] = 26] = "CONTROLLER_2_MAPPING";
|
|
2819
|
+
SelectDashScreen2[SelectDashScreen2["SCARY_CONFIGURATION_MORE"] = 27] = "SCARY_CONFIGURATION_MORE";
|
|
2820
|
+
SelectDashScreen2[SelectDashScreen2["CONFIRM_XX"] = 28] = "CONFIRM_XX";
|
|
2821
|
+
SelectDashScreen2[SelectDashScreen2["CONTROLLER_1_MAPPING"] = 29] = "CONTROLLER_1_MAPPING";
|
|
2822
|
+
SelectDashScreen2[SelectDashScreen2["DRIVE_PROGRAM_CONTROL_DUAL_MAPPING"] = 30] = "DRIVE_PROGRAM_CONTROL_DUAL_MAPPING";
|
|
2823
|
+
SelectDashScreen2[SelectDashScreen2["DRIVE_PROGRAM_CONTROL_SPLIT_MAPPING"] = 31] = "DRIVE_PROGRAM_CONTROL_SPLIT_MAPPING";
|
|
2824
|
+
SelectDashScreen2[SelectDashScreen2["DRIVE_PROGRAM_CONTROL_RIGHT_MAPPING"] = 32] = "DRIVE_PROGRAM_CONTROL_RIGHT_MAPPING";
|
|
2825
|
+
SelectDashScreen2[SelectDashScreen2["MATCH_2_4_PLAYERS"] = 33] = "MATCH_2_4_PLAYERS";
|
|
2826
|
+
SelectDashScreen2[SelectDashScreen2["EVENT_LOG"] = 34] = "EVENT_LOG";
|
|
2827
|
+
SelectDashScreen2[SelectDashScreen2["USER_PROGRAM_WIRING"] = 40] = "USER_PROGRAM_WIRING";
|
|
2828
|
+
SelectDashScreen2[SelectDashScreen2["CLAWBOT_PROGRAM_MENU"] = 41] = "CLAWBOT_PROGRAM_MENU";
|
|
2829
|
+
SelectDashScreen2[SelectDashScreen2["ABOUT"] = 42] = "ABOUT";
|
|
2830
|
+
SelectDashScreen2[SelectDashScreen2["LANGUAGE_MORE"] = 43] = "LANGUAGE_MORE";
|
|
2831
|
+
SelectDashScreen2[SelectDashScreen2["OBJECT_COLOR"] = 45] = "OBJECT_COLOR";
|
|
2832
|
+
SelectDashScreen2[SelectDashScreen2["SIGNATURE_ID"] = 46] = "SIGNATURE_ID";
|
|
2833
|
+
SelectDashScreen2[SelectDashScreen2["LOG_DATA"] = 47] = "LOG_DATA";
|
|
2834
|
+
})(SelectDashScreen ||= {});
|
|
2835
|
+
|
|
2836
|
+
class VexSerialError extends Error {
|
|
2837
|
+
kind;
|
|
2838
|
+
ackType = undefined;
|
|
2839
|
+
constructor(kind, message) {
|
|
2840
|
+
super(message);
|
|
2841
|
+
this.name = "VexSerialError";
|
|
2842
|
+
this.kind = kind;
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
|
|
2846
|
+
class VexNotConnectedError extends VexSerialError {
|
|
2847
|
+
constructor(message = "no connection to a V5 device") {
|
|
2848
|
+
super("not-connected", message);
|
|
2849
|
+
this.name = "VexNotConnectedError";
|
|
2916
2850
|
}
|
|
2917
|
-
|
|
2918
|
-
|
|
2851
|
+
}
|
|
2852
|
+
|
|
2853
|
+
class VexInvalidArgumentError extends VexSerialError {
|
|
2854
|
+
constructor(message) {
|
|
2855
|
+
super("invalid-argument", message);
|
|
2856
|
+
this.name = "VexInvalidArgumentError";
|
|
2919
2857
|
}
|
|
2920
|
-
|
|
2921
|
-
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2860
|
+
class VexProtocolError extends VexSerialError {
|
|
2861
|
+
ackType;
|
|
2862
|
+
constructor(message, ackType) {
|
|
2863
|
+
super("protocol", message);
|
|
2864
|
+
this.name = "VexProtocolError";
|
|
2865
|
+
this.ackType = ackType;
|
|
2922
2866
|
}
|
|
2923
|
-
|
|
2924
|
-
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
class VexTransferError extends VexSerialError {
|
|
2870
|
+
constructor(message) {
|
|
2871
|
+
super("transfer", message);
|
|
2872
|
+
this.name = "VexTransferError";
|
|
2925
2873
|
}
|
|
2926
|
-
|
|
2927
|
-
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2876
|
+
class VexDownloadError extends VexSerialError {
|
|
2877
|
+
constructor(message) {
|
|
2878
|
+
super("download", message);
|
|
2879
|
+
this.name = "VexDownloadError";
|
|
2928
2880
|
}
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2881
|
+
}
|
|
2882
|
+
|
|
2883
|
+
class VexFirmwareError extends VexSerialError {
|
|
2884
|
+
constructor(message) {
|
|
2885
|
+
super("firmware", message);
|
|
2886
|
+
this.name = "VexFirmwareError";
|
|
2934
2887
|
}
|
|
2935
|
-
|
|
2936
|
-
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2890
|
+
class VexIoError extends VexSerialError {
|
|
2891
|
+
constructor(message) {
|
|
2892
|
+
super("io", message);
|
|
2893
|
+
this.name = "VexIoError";
|
|
2937
2894
|
}
|
|
2938
|
-
|
|
2939
|
-
|
|
2895
|
+
}
|
|
2896
|
+
function toVexSerialError(error, fallback = "io") {
|
|
2897
|
+
if (error instanceof VexSerialError)
|
|
2898
|
+
return error;
|
|
2899
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2900
|
+
return new VexSerialError(fallback, message);
|
|
2901
|
+
}
|
|
2902
|
+
|
|
2903
|
+
class VexEventEmitter {
|
|
2904
|
+
handlerMap;
|
|
2905
|
+
constructor() {
|
|
2906
|
+
this.handlerMap = new Map;
|
|
2940
2907
|
}
|
|
2941
|
-
|
|
2942
|
-
|
|
2908
|
+
on(eventName, listener) {
|
|
2909
|
+
let listeners = this.handlerMap.get(eventName);
|
|
2910
|
+
listeners ??= [];
|
|
2911
|
+
listeners.push(listener);
|
|
2912
|
+
this.handlerMap.set(eventName, listeners);
|
|
2943
2913
|
}
|
|
2944
|
-
|
|
2945
|
-
|
|
2914
|
+
remove(eventName, listener) {
|
|
2915
|
+
let listeners = this.handlerMap.get(eventName);
|
|
2916
|
+
listeners ??= [];
|
|
2917
|
+
const index = listeners.indexOf(listener);
|
|
2918
|
+
if (index > -1) {
|
|
2919
|
+
listeners.splice(index, 1);
|
|
2920
|
+
}
|
|
2921
|
+
this.handlerMap.set(eventName, listeners);
|
|
2946
2922
|
}
|
|
2947
|
-
|
|
2948
|
-
|
|
2923
|
+
emit(eventName, data) {
|
|
2924
|
+
const listeners = this.handlerMap.get(eventName);
|
|
2925
|
+
if (listeners === undefined || listeners.length === 0)
|
|
2926
|
+
return;
|
|
2927
|
+
if (listeners.length === 1) {
|
|
2928
|
+
listeners[0](data);
|
|
2929
|
+
return;
|
|
2930
|
+
}
|
|
2931
|
+
const errors = [];
|
|
2932
|
+
for (const callback of [...listeners]) {
|
|
2933
|
+
try {
|
|
2934
|
+
callback(data);
|
|
2935
|
+
} catch (error) {
|
|
2936
|
+
errors.push(error);
|
|
2937
|
+
}
|
|
2938
|
+
}
|
|
2939
|
+
if (errors.length === 1)
|
|
2940
|
+
throw errors[0];
|
|
2941
|
+
if (errors.length > 1) {
|
|
2942
|
+
throw new AggregateError(errors, `listeners for ${String(eventName)} failed`);
|
|
2943
|
+
}
|
|
2949
2944
|
}
|
|
2950
|
-
|
|
2951
|
-
|
|
2945
|
+
clearListeners() {
|
|
2946
|
+
this.handlerMap.clear();
|
|
2952
2947
|
}
|
|
2953
|
-
|
|
2954
|
-
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
class VexEventTarget {
|
|
2951
|
+
emitter;
|
|
2952
|
+
constructor() {
|
|
2953
|
+
this.emitter = new VexEventEmitter;
|
|
2955
2954
|
}
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
return function* () {
|
|
2959
|
-
yield err(error);
|
|
2960
|
-
throw new Error("Do not use this generator out of `safeTry`");
|
|
2961
|
-
}();
|
|
2955
|
+
emit(eventName, data) {
|
|
2956
|
+
this.emitter.emit(eventName, data);
|
|
2962
2957
|
}
|
|
2963
|
-
|
|
2964
|
-
|
|
2958
|
+
on(eventName, listener) {
|
|
2959
|
+
this.emitter.on(eventName, listener);
|
|
2965
2960
|
}
|
|
2966
|
-
|
|
2967
|
-
|
|
2961
|
+
remove(eventName, listener) {
|
|
2962
|
+
this.emitter.remove(eventName, listener);
|
|
2968
2963
|
}
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
yield self;
|
|
2972
|
-
return self;
|
|
2964
|
+
clearListeners() {
|
|
2965
|
+
this.emitter.clearListeners();
|
|
2973
2966
|
}
|
|
2974
2967
|
}
|
|
2975
|
-
var fromThrowable = Result.fromThrowable;
|
|
2976
2968
|
var MATCH_STATUS_ALT_ACK = 167;
|
|
2977
2969
|
|
|
2978
2970
|
class Packet {
|
|
@@ -3054,86 +3046,122 @@ class CrcGenerator {
|
|
|
3054
3046
|
}
|
|
3055
3047
|
return acc & 65535;
|
|
3056
3048
|
}
|
|
3057
|
-
crc32(buf, initValue) {
|
|
3058
|
-
let acc = initValue;
|
|
3059
|
-
for (let j = 0;j < buf.length; j++) {
|
|
3060
|
-
acc = (acc << 8 ^ CRC32_TABLE[(acc >>> 24 ^ buf[j]) & 255]) >>> 0;
|
|
3061
|
-
}
|
|
3062
|
-
return acc >>> 0;
|
|
3049
|
+
crc32(buf, initValue) {
|
|
3050
|
+
let acc = initValue;
|
|
3051
|
+
for (let j = 0;j < buf.length; j++) {
|
|
3052
|
+
acc = (acc << 8 ^ CRC32_TABLE[(acc >>> 24 ^ buf[j]) & 255]) >>> 0;
|
|
3053
|
+
}
|
|
3054
|
+
return acc >>> 0;
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
var textEncoder = new TextEncoder;
|
|
3058
|
+
var HEADER_TO_DEVICE = Uint8Array.of(201, 54, 184, 71);
|
|
3059
|
+
function encodeFixedText(value, field, maxBytes) {
|
|
3060
|
+
const encoded = textEncoder.encode(value);
|
|
3061
|
+
if (encoded.byteLength > maxBytes) {
|
|
3062
|
+
throw new RangeError(`${field} must be at most ${maxBytes} UTF-8 bytes`);
|
|
3063
|
+
}
|
|
3064
|
+
return encoded;
|
|
3065
|
+
}
|
|
3066
|
+
|
|
3067
|
+
class PacketEncoder {
|
|
3068
|
+
static HEADERS_LENGTH = 4;
|
|
3069
|
+
static HEADER_TO_DEVICE = [201, 54, 184, 71];
|
|
3070
|
+
static HEADER_TO_HOST = [170, 85];
|
|
3071
|
+
static J2000_EPOCH = 946684800;
|
|
3072
|
+
vexVersion = 0;
|
|
3073
|
+
crcgen = new CrcGenerator;
|
|
3074
|
+
allPacketsTable = new Map;
|
|
3075
|
+
static getInstance() {
|
|
3076
|
+
Packet.ENCODER ??= new PacketEncoder;
|
|
3077
|
+
return Packet.ENCODER;
|
|
3078
|
+
}
|
|
3079
|
+
constructor() {}
|
|
3080
|
+
registerPacketTypes(types) {
|
|
3081
|
+
for (const type of types) {
|
|
3082
|
+
let byExtendedId = this.allPacketsTable.get(type.COMMAND_ID);
|
|
3083
|
+
if (byExtendedId === undefined) {
|
|
3084
|
+
byExtendedId = new Map;
|
|
3085
|
+
this.allPacketsTable.set(type.COMMAND_ID, byExtendedId);
|
|
3086
|
+
}
|
|
3087
|
+
byExtendedId.set(type.COMMAND_EXTENDED_ID, type);
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3090
|
+
getPacketType(commandId, commandExtendedId) {
|
|
3091
|
+
if (commandId === undefined)
|
|
3092
|
+
return;
|
|
3093
|
+
return this.allPacketsTable.get(commandId)?.get(commandExtendedId);
|
|
3094
|
+
}
|
|
3095
|
+
createHeader(buf) {
|
|
3096
|
+
if (buf === undefined || buf.byteLength < PacketEncoder.HEADERS_LENGTH) {
|
|
3097
|
+
buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH);
|
|
3098
|
+
}
|
|
3099
|
+
const h = new Uint8Array(buf);
|
|
3100
|
+
h.set(HEADER_TO_DEVICE);
|
|
3101
|
+
return h;
|
|
3102
|
+
}
|
|
3103
|
+
cdcCommand(cmd) {
|
|
3104
|
+
const h = new Uint8Array(5);
|
|
3105
|
+
h.set(HEADER_TO_DEVICE);
|
|
3106
|
+
h[4] = cmd;
|
|
3107
|
+
return h;
|
|
3108
|
+
}
|
|
3109
|
+
cdcCommandWithData(cmd, data) {
|
|
3110
|
+
const h = new Uint8Array(6 + data.length);
|
|
3111
|
+
h.set(HEADER_TO_DEVICE);
|
|
3112
|
+
h[4] = cmd;
|
|
3113
|
+
h[5] = data.length;
|
|
3114
|
+
h.set(data, 6);
|
|
3115
|
+
return h;
|
|
3116
|
+
}
|
|
3117
|
+
cdc2Command(cmd, ext) {
|
|
3118
|
+
const h = new Uint8Array(9);
|
|
3119
|
+
h.set(HEADER_TO_DEVICE);
|
|
3120
|
+
h[4] = cmd;
|
|
3121
|
+
h[5] = ext;
|
|
3122
|
+
h[6] = 0;
|
|
3123
|
+
this.appendCrc16(h);
|
|
3124
|
+
return h;
|
|
3125
|
+
}
|
|
3126
|
+
cdc2CommandBufferLength(data) {
|
|
3127
|
+
return PacketEncoder.HEADERS_LENGTH + data.length + 5 + (data.length > 127 ? 1 : 0);
|
|
3128
|
+
}
|
|
3129
|
+
cdc2CommandWithData(cmd, ext, data) {
|
|
3130
|
+
const h = new Uint8Array(this.cdc2CommandBufferLength(data));
|
|
3131
|
+
h.set(HEADER_TO_DEVICE);
|
|
3132
|
+
h[4] = cmd;
|
|
3133
|
+
h[5] = ext;
|
|
3134
|
+
if (data.length < 128) {
|
|
3135
|
+
h[6] = data.length;
|
|
3136
|
+
h.set(data, 7);
|
|
3137
|
+
} else {
|
|
3138
|
+
h[6] = data.length >>> 8 | 128;
|
|
3139
|
+
h[7] = data.length & 255;
|
|
3140
|
+
h.set(data, 8);
|
|
3141
|
+
}
|
|
3142
|
+
this.appendCrc16(h);
|
|
3143
|
+
return h;
|
|
3144
|
+
}
|
|
3145
|
+
appendCrc16(h) {
|
|
3146
|
+
const crc2 = this.crcgen.crc16(h.subarray(0, h.length - 2), 0);
|
|
3147
|
+
h[h.length - 2] = crc2 >>> 8;
|
|
3148
|
+
h[h.length - 1] = crc2 & 255;
|
|
3149
|
+
}
|
|
3150
|
+
validateHeader(data) {
|
|
3151
|
+
return data[0] === PacketEncoder.HEADER_TO_HOST[0] && data[1] === PacketEncoder.HEADER_TO_HOST[1];
|
|
3152
|
+
}
|
|
3153
|
+
validateMessageCdc(data) {
|
|
3154
|
+
const crc2 = (data[data.byteLength - 2] << 8) + data[data.byteLength - 1];
|
|
3155
|
+
return this.crcgen.crc16(data.subarray(0, data.byteLength - 2), 0) === crc2;
|
|
3156
|
+
}
|
|
3157
|
+
getPayloadSize(data) {
|
|
3158
|
+
const a2 = data[3];
|
|
3159
|
+
return (a2 & 128) === 0 ? a2 : ((a2 & 127) << 8) + data[4];
|
|
3160
|
+
}
|
|
3161
|
+
getHostHeaderLength(data) {
|
|
3162
|
+
return (data[3] & 128) === 0 ? 4 : 5;
|
|
3063
3163
|
}
|
|
3064
3164
|
}
|
|
3065
|
-
var exports_VexPacketModels = {};
|
|
3066
|
-
__export2(exports_VexPacketModels, {
|
|
3067
|
-
WriteKeyValueReplyD2HPacket: () => WriteKeyValueReplyD2HPacket,
|
|
3068
|
-
WriteKeyValueH2DPacket: () => WriteKeyValueH2DPacket,
|
|
3069
|
-
WriteFileReplyD2HPacket: () => WriteFileReplyD2HPacket,
|
|
3070
|
-
WriteFileH2DPacket: () => WriteFileH2DPacket,
|
|
3071
|
-
UpdateMatchModeH2DPacket: () => UpdateMatchModeH2DPacket,
|
|
3072
|
-
SystemVersionReplyD2HPacket: () => SystemVersionReplyD2HPacket,
|
|
3073
|
-
SystemVersionH2DPacket: () => SystemVersionH2DPacket,
|
|
3074
|
-
SendDashTouchReplyD2HPacket: () => SendDashTouchReplyD2HPacket,
|
|
3075
|
-
SendDashTouchH2DPacket: () => SendDashTouchH2DPacket,
|
|
3076
|
-
SelectDashReplyD2HPacket: () => SelectDashReplyD2HPacket,
|
|
3077
|
-
SelectDashH2DPacket: () => SelectDashH2DPacket,
|
|
3078
|
-
ScreenCaptureReplyD2HPacket: () => ScreenCaptureReplyD2HPacket,
|
|
3079
|
-
ScreenCaptureH2DPacket: () => ScreenCaptureH2DPacket,
|
|
3080
|
-
ReadLogPageReplyD2HPacket: () => ReadLogPageReplyD2HPacket,
|
|
3081
|
-
ReadLogPageH2DPacket: () => ReadLogPageH2DPacket,
|
|
3082
|
-
ReadKeyValueReplyD2HPacket: () => ReadKeyValueReplyD2HPacket,
|
|
3083
|
-
ReadKeyValueH2DPacket: () => ReadKeyValueH2DPacket,
|
|
3084
|
-
ReadFileReplyD2HPacket: () => ReadFileReplyD2HPacket,
|
|
3085
|
-
ReadFileH2DPacket: () => ReadFileH2DPacket,
|
|
3086
|
-
Query1ReplyD2HPacket: () => Query1ReplyD2HPacket,
|
|
3087
|
-
Query1H2DPacket: () => Query1H2DPacket,
|
|
3088
|
-
MatchStatusReplyD2HPacket: () => MatchStatusReplyD2HPacket,
|
|
3089
|
-
MatchModeReplyD2HPacket: () => MatchModeReplyD2HPacket,
|
|
3090
|
-
LoadFileActionReplyD2HPacket: () => LoadFileActionReplyD2HPacket,
|
|
3091
|
-
LoadFileActionH2DPacket: () => LoadFileActionH2DPacket,
|
|
3092
|
-
LinkFileReplyD2HPacket: () => LinkFileReplyD2HPacket,
|
|
3093
|
-
LinkFileH2DPacket: () => LinkFileH2DPacket,
|
|
3094
|
-
InitFileTransferReplyD2HPacket: () => InitFileTransferReplyD2HPacket,
|
|
3095
|
-
InitFileTransferH2DPacket: () => InitFileTransferH2DPacket,
|
|
3096
|
-
GetSystemStatusReplyD2HPacket: () => GetSystemStatusReplyD2HPacket,
|
|
3097
|
-
GetSystemStatusH2DPacket: () => GetSystemStatusH2DPacket,
|
|
3098
|
-
GetSystemFlagsReplyD2HPacket: () => GetSystemFlagsReplyD2HPacket,
|
|
3099
|
-
GetSystemFlagsH2DPacket: () => GetSystemFlagsH2DPacket,
|
|
3100
|
-
GetSlot5to8InfoReplyD2HPacket: () => GetSlot5to8InfoReplyD2HPacket,
|
|
3101
|
-
GetSlot5to8InfoH2DPacket: () => GetSlot5to8InfoH2DPacket,
|
|
3102
|
-
GetSlot1to4InfoReplyD2HPacket: () => GetSlot1to4InfoReplyD2HPacket,
|
|
3103
|
-
GetSlot1to4InfoH2DPacket: () => GetSlot1to4InfoH2DPacket,
|
|
3104
|
-
GetRadioStatusReplyD2HPacket: () => GetRadioStatusReplyD2HPacket,
|
|
3105
|
-
GetRadioStatusH2DPacket: () => GetRadioStatusH2DPacket,
|
|
3106
|
-
GetRadioModeH2DPacket: () => GetRadioModeH2DPacket,
|
|
3107
|
-
GetProgramSlotInfoReplyD2HPacket: () => GetProgramSlotInfoReplyD2HPacket,
|
|
3108
|
-
GetProgramSlotInfoH2DPacket: () => GetProgramSlotInfoH2DPacket,
|
|
3109
|
-
GetMatchStatusH2DPacket: () => GetMatchStatusH2DPacket,
|
|
3110
|
-
GetLogCountReplyD2HPacket: () => GetLogCountReplyD2HPacket,
|
|
3111
|
-
GetLogCountH2DPacket: () => GetLogCountH2DPacket,
|
|
3112
|
-
GetFileMetadataReplyD2HPacket: () => GetFileMetadataReplyD2HPacket,
|
|
3113
|
-
GetFileMetadataH2DPacket: () => GetFileMetadataH2DPacket,
|
|
3114
|
-
GetFdtStatusReplyD2HPacket: () => GetFdtStatusReplyD2HPacket,
|
|
3115
|
-
GetFdtStatusH2DPacket: () => GetFdtStatusH2DPacket,
|
|
3116
|
-
GetDirectoryFileCountReplyD2HPacket: () => GetDirectoryFileCountReplyD2HPacket,
|
|
3117
|
-
GetDirectoryFileCountH2DPacket: () => GetDirectoryFileCountH2DPacket,
|
|
3118
|
-
GetDirectoryEntryReplyD2HPacket: () => GetDirectoryEntryReplyD2HPacket,
|
|
3119
|
-
GetDirectoryEntryH2DPacket: () => GetDirectoryEntryH2DPacket,
|
|
3120
|
-
GetDeviceStatusReplyD2HPacket: () => GetDeviceStatusReplyD2HPacket,
|
|
3121
|
-
GetDeviceStatusH2DPacket: () => GetDeviceStatusH2DPacket,
|
|
3122
|
-
FileFormatReplyD2HPacket: () => FileFormatReplyD2HPacket,
|
|
3123
|
-
FileFormatH2DPacket: () => FileFormatH2DPacket,
|
|
3124
|
-
FileControlReplyD2HPacket: () => FileControlReplyD2HPacket,
|
|
3125
|
-
FileControlH2DPacket: () => FileControlH2DPacket,
|
|
3126
|
-
FileClearUpReplyD2HPacket: () => FileClearUpReplyD2HPacket,
|
|
3127
|
-
FileClearUpH2DPacket: () => FileClearUpH2DPacket,
|
|
3128
|
-
FactoryStatusReplyD2HPacket: () => FactoryStatusReplyD2HPacket,
|
|
3129
|
-
FactoryStatusH2DPacket: () => FactoryStatusH2DPacket,
|
|
3130
|
-
FactoryEnableReplyD2HPacket: () => FactoryEnableReplyD2HPacket,
|
|
3131
|
-
FactoryEnableH2DPacket: () => FactoryEnableH2DPacket,
|
|
3132
|
-
ExitFileTransferReplyD2HPacket: () => ExitFileTransferReplyD2HPacket,
|
|
3133
|
-
ExitFileTransferH2DPacket: () => ExitFileTransferH2DPacket,
|
|
3134
|
-
EraseFileReplyD2HPacket: () => EraseFileReplyD2HPacket,
|
|
3135
|
-
EraseFileH2DPacket: () => EraseFileH2DPacket
|
|
3136
|
-
});
|
|
3137
3165
|
|
|
3138
3166
|
class VexFirmwareVersion {
|
|
3139
3167
|
major;
|
|
@@ -3201,7 +3229,7 @@ class PacketView extends DataView {
|
|
|
3201
3229
|
super(buffer, offset, length);
|
|
3202
3230
|
}
|
|
3203
3231
|
static fromPacket(packet) {
|
|
3204
|
-
const view = new PacketView(packet.data.buffer, packet.data.byteOffset);
|
|
3232
|
+
const view = new PacketView(packet.data.buffer, packet.data.byteOffset, packet.data.byteLength);
|
|
3205
3233
|
view.position = packet.ackIndex + 1;
|
|
3206
3234
|
return view;
|
|
3207
3235
|
}
|
|
@@ -3261,12 +3289,12 @@ class PacketView extends DataView {
|
|
|
3261
3289
|
return result;
|
|
3262
3290
|
}
|
|
3263
3291
|
}
|
|
3264
|
-
var
|
|
3292
|
+
var textEncoder2 = new TextEncoder;
|
|
3265
3293
|
function filePayload(a2, b, fileName) {
|
|
3266
3294
|
const payload = new Uint8Array(26);
|
|
3267
3295
|
payload[0] = a2;
|
|
3268
3296
|
payload[1] = b;
|
|
3269
|
-
payload.set(encodeFixedText(fileName, "Filename",
|
|
3297
|
+
payload.set(encodeFixedText(fileName, "Filename", 24), 2);
|
|
3270
3298
|
return payload;
|
|
3271
3299
|
}
|
|
3272
3300
|
var clamp100 = (value) => value !== undefined && value > 100 ? 100 : value;
|
|
@@ -3297,15 +3325,6 @@ class GetMatchStatusH2DPacket extends DeviceBoundPacket {
|
|
|
3297
3325
|
static COMMAND_ID = 88;
|
|
3298
3326
|
static COMMAND_EXTENDED_ID = 194;
|
|
3299
3327
|
}
|
|
3300
|
-
|
|
3301
|
-
class GetRadioModeH2DPacket extends DeviceBoundPacket {
|
|
3302
|
-
static COMMAND_ID = 88;
|
|
3303
|
-
static COMMAND_EXTENDED_ID = 65;
|
|
3304
|
-
constructor(mode) {
|
|
3305
|
-
super(Uint8Array.of(mode));
|
|
3306
|
-
}
|
|
3307
|
-
}
|
|
3308
|
-
|
|
3309
3328
|
class FileControlH2DPacket extends DeviceBoundPacket {
|
|
3310
3329
|
static COMMAND_ID = 86;
|
|
3311
3330
|
static COMMAND_EXTENDED_ID = 16;
|
|
@@ -3334,7 +3353,7 @@ class InitFileTransferH2DPacket extends DeviceBoundPacket {
|
|
|
3334
3353
|
const timestamp = (Date.now() / 1000 >>> 0) - PacketEncoder.J2000_EPOCH;
|
|
3335
3354
|
view.setUint32(20, timestamp, true);
|
|
3336
3355
|
payload.set(version.toUint8Array(), 24);
|
|
3337
|
-
payload.set(encodeFixedText(name, "Filename",
|
|
3356
|
+
payload.set(encodeFixedText(name, "Filename", 24), 28);
|
|
3338
3357
|
super(payload);
|
|
3339
3358
|
}
|
|
3340
3359
|
}
|
|
@@ -3402,15 +3421,6 @@ class LoadFileActionH2DPacket extends DeviceBoundPacket {
|
|
|
3402
3421
|
super(filePayload(vendor, actionId, fileName));
|
|
3403
3422
|
}
|
|
3404
3423
|
}
|
|
3405
|
-
|
|
3406
|
-
class GetFileMetadataH2DPacket extends DeviceBoundPacket {
|
|
3407
|
-
static COMMAND_ID = 86;
|
|
3408
|
-
static COMMAND_EXTENDED_ID = 25;
|
|
3409
|
-
constructor(vendor, fileName, options) {
|
|
3410
|
-
super(filePayload(vendor, options, fileName));
|
|
3411
|
-
}
|
|
3412
|
-
}
|
|
3413
|
-
|
|
3414
3424
|
class EraseFileH2DPacket extends DeviceBoundPacket {
|
|
3415
3425
|
static COMMAND_ID = 86;
|
|
3416
3426
|
static COMMAND_EXTENDED_ID = 27;
|
|
@@ -3434,15 +3444,6 @@ class FileClearUpH2DPacket extends DeviceBoundPacket {
|
|
|
3434
3444
|
super(Uint8Array.of(vendor, 0));
|
|
3435
3445
|
}
|
|
3436
3446
|
}
|
|
3437
|
-
|
|
3438
|
-
class FileFormatH2DPacket extends DeviceBoundPacket {
|
|
3439
|
-
static COMMAND_ID = 86;
|
|
3440
|
-
static COMMAND_EXTENDED_ID = 31;
|
|
3441
|
-
constructor() {
|
|
3442
|
-
super(Uint8Array.of(68, 67, 66, 65));
|
|
3443
|
-
}
|
|
3444
|
-
}
|
|
3445
|
-
|
|
3446
3447
|
class GetSystemFlagsH2DPacket extends DeviceBoundPacket {
|
|
3447
3448
|
static COMMAND_ID = 86;
|
|
3448
3449
|
static COMMAND_EXTENDED_ID = 32;
|
|
@@ -3457,29 +3458,6 @@ class GetSystemStatusH2DPacket extends DeviceBoundPacket {
|
|
|
3457
3458
|
static COMMAND_ID = 86;
|
|
3458
3459
|
static COMMAND_EXTENDED_ID = 34;
|
|
3459
3460
|
}
|
|
3460
|
-
|
|
3461
|
-
class GetFdtStatusH2DPacket extends DeviceBoundPacket {
|
|
3462
|
-
static COMMAND_ID = 86;
|
|
3463
|
-
static COMMAND_EXTENDED_ID = 35;
|
|
3464
|
-
}
|
|
3465
|
-
|
|
3466
|
-
class GetLogCountH2DPacket extends DeviceBoundPacket {
|
|
3467
|
-
static COMMAND_ID = 86;
|
|
3468
|
-
static COMMAND_EXTENDED_ID = 36;
|
|
3469
|
-
}
|
|
3470
|
-
|
|
3471
|
-
class ReadLogPageH2DPacket extends DeviceBoundPacket {
|
|
3472
|
-
static COMMAND_ID = 86;
|
|
3473
|
-
static COMMAND_EXTENDED_ID = 37;
|
|
3474
|
-
constructor(offset, count) {
|
|
3475
|
-
const payload = new Uint8Array(8);
|
|
3476
|
-
const view = new DataView(payload.buffer);
|
|
3477
|
-
view.setUint32(0, offset, true);
|
|
3478
|
-
view.setUint32(4, count, true);
|
|
3479
|
-
super(payload);
|
|
3480
|
-
}
|
|
3481
|
-
}
|
|
3482
|
-
|
|
3483
3461
|
class GetRadioStatusH2DPacket extends DeviceBoundPacket {
|
|
3484
3462
|
static COMMAND_ID = 86;
|
|
3485
3463
|
static COMMAND_EXTENDED_ID = 38;
|
|
@@ -3529,7 +3507,7 @@ class WriteKeyValueH2DPacket extends DeviceBoundPacket {
|
|
|
3529
3507
|
static COMMAND_EXTENDED_ID = 47;
|
|
3530
3508
|
constructor(key, value) {
|
|
3531
3509
|
const strk = encodeFixedText(key, "Key", 31);
|
|
3532
|
-
const strv =
|
|
3510
|
+
const strv = textEncoder2.encode(value);
|
|
3533
3511
|
if (strk.byteLength + strv.byteLength + 20 > 32767) {
|
|
3534
3512
|
throw new RangeError("Key and value are too large for a protocol packet");
|
|
3535
3513
|
}
|
|
@@ -3539,17 +3517,6 @@ class WriteKeyValueH2DPacket extends DeviceBoundPacket {
|
|
|
3539
3517
|
super(payload);
|
|
3540
3518
|
}
|
|
3541
3519
|
}
|
|
3542
|
-
|
|
3543
|
-
class GetSlot1to4InfoH2DPacket extends DeviceBoundPacket {
|
|
3544
|
-
static COMMAND_ID = 86;
|
|
3545
|
-
static COMMAND_EXTENDED_ID = 49;
|
|
3546
|
-
}
|
|
3547
|
-
|
|
3548
|
-
class GetSlot5to8InfoH2DPacket extends DeviceBoundPacket {
|
|
3549
|
-
static COMMAND_ID = 86;
|
|
3550
|
-
static COMMAND_EXTENDED_ID = 50;
|
|
3551
|
-
}
|
|
3552
|
-
|
|
3553
3520
|
class FactoryStatusH2DPacket extends DeviceBoundPacket {
|
|
3554
3521
|
static COMMAND_ID = 86;
|
|
3555
3522
|
static COMMAND_EXTENDED_ID = 241;
|
|
@@ -3692,7 +3659,7 @@ class ReadFileReplyD2HPacket extends HostBoundPacket {
|
|
|
3692
3659
|
const view = PacketView.fromPacket(this);
|
|
3693
3660
|
this.addr = view.nextUint32();
|
|
3694
3661
|
this.length = this.payloadSize - 8;
|
|
3695
|
-
this.buf = this.data.
|
|
3662
|
+
this.buf = this.data.subarray(view.position, view.position + this.length);
|
|
3696
3663
|
}
|
|
3697
3664
|
}
|
|
3698
3665
|
|
|
@@ -3737,28 +3704,6 @@ class LoadFileActionReplyD2HPacket extends HostBoundPacket {
|
|
|
3737
3704
|
static COMMAND_ID = 86;
|
|
3738
3705
|
static COMMAND_EXTENDED_ID = 24;
|
|
3739
3706
|
}
|
|
3740
|
-
|
|
3741
|
-
class GetFileMetadataReplyD2HPacket extends HostBoundPacket {
|
|
3742
|
-
static COMMAND_ID = 86;
|
|
3743
|
-
static COMMAND_EXTENDED_ID = 25;
|
|
3744
|
-
file;
|
|
3745
|
-
constructor(data) {
|
|
3746
|
-
super(data);
|
|
3747
|
-
if (this.payloadSize <= 4)
|
|
3748
|
-
return;
|
|
3749
|
-
const view = PacketView.fromPacket(this);
|
|
3750
|
-
view.nextUint8();
|
|
3751
|
-
this.file = {
|
|
3752
|
-
size: view.nextUint32(),
|
|
3753
|
-
loadAddress: view.nextUint32(),
|
|
3754
|
-
crc32: view.nextUint32(),
|
|
3755
|
-
type: view.nextString(4),
|
|
3756
|
-
timestamp: view.nextUint32() + PacketEncoder.J2000_EPOCH,
|
|
3757
|
-
version: view.nextVersion()
|
|
3758
|
-
};
|
|
3759
|
-
}
|
|
3760
|
-
}
|
|
3761
|
-
|
|
3762
3707
|
class EraseFileReplyD2HPacket extends HostBoundPacket {
|
|
3763
3708
|
static COMMAND_ID = 86;
|
|
3764
3709
|
static COMMAND_EXTENDED_ID = 27;
|
|
@@ -3781,12 +3726,6 @@ class FileClearUpReplyD2HPacket extends HostBoundPacket {
|
|
|
3781
3726
|
static COMMAND_ID = 86;
|
|
3782
3727
|
static COMMAND_EXTENDED_ID = 30;
|
|
3783
3728
|
}
|
|
3784
|
-
|
|
3785
|
-
class FileFormatReplyD2HPacket extends HostBoundPacket {
|
|
3786
|
-
static COMMAND_ID = 86;
|
|
3787
|
-
static COMMAND_EXTENDED_ID = 31;
|
|
3788
|
-
}
|
|
3789
|
-
|
|
3790
3729
|
class GetSystemFlagsReplyD2HPacket extends HostBoundPacket {
|
|
3791
3730
|
static COMMAND_ID = 86;
|
|
3792
3731
|
static COMMAND_EXTENDED_ID = 32;
|
|
@@ -3889,69 +3828,6 @@ class GetSystemStatusReplyD2HPacket extends HostBoundPacket {
|
|
|
3889
3828
|
}
|
|
3890
3829
|
}
|
|
3891
3830
|
}
|
|
3892
|
-
|
|
3893
|
-
class GetFdtStatusReplyD2HPacket extends HostBoundPacket {
|
|
3894
|
-
static COMMAND_ID = 86;
|
|
3895
|
-
static COMMAND_EXTENDED_ID = 35;
|
|
3896
|
-
count;
|
|
3897
|
-
status;
|
|
3898
|
-
constructor(data) {
|
|
3899
|
-
super(data);
|
|
3900
|
-
const view = PacketView.fromPacket(this);
|
|
3901
|
-
this.count = view.nextUint8();
|
|
3902
|
-
this.status = [];
|
|
3903
|
-
for (let i2 = 0;i2 < this.count; i2++) {
|
|
3904
|
-
this.status.push({
|
|
3905
|
-
index: view.nextUint8(),
|
|
3906
|
-
type: view.nextUint8(),
|
|
3907
|
-
status: view.nextUint8(),
|
|
3908
|
-
betaversion: view.nextUint8(),
|
|
3909
|
-
version: view.nextUint16(),
|
|
3910
|
-
bootversion: view.nextUint16()
|
|
3911
|
-
});
|
|
3912
|
-
}
|
|
3913
|
-
}
|
|
3914
|
-
}
|
|
3915
|
-
|
|
3916
|
-
class GetLogCountReplyD2HPacket extends HostBoundPacket {
|
|
3917
|
-
static COMMAND_ID = 86;
|
|
3918
|
-
static COMMAND_EXTENDED_ID = 36;
|
|
3919
|
-
count;
|
|
3920
|
-
constructor(data) {
|
|
3921
|
-
super(data);
|
|
3922
|
-
const view = PacketView.fromPacket(this);
|
|
3923
|
-
view.nextUint8();
|
|
3924
|
-
this.count = view.nextUint32();
|
|
3925
|
-
}
|
|
3926
|
-
}
|
|
3927
|
-
|
|
3928
|
-
class ReadLogPageReplyD2HPacket extends HostBoundPacket {
|
|
3929
|
-
static COMMAND_ID = 86;
|
|
3930
|
-
static COMMAND_EXTENDED_ID = 37;
|
|
3931
|
-
offset;
|
|
3932
|
-
count;
|
|
3933
|
-
entries;
|
|
3934
|
-
constructor(data) {
|
|
3935
|
-
super(data);
|
|
3936
|
-
const view = PacketView.fromPacket(this);
|
|
3937
|
-
const size = view.nextUint8();
|
|
3938
|
-
this.offset = view.nextUint32();
|
|
3939
|
-
this.count = view.nextUint16();
|
|
3940
|
-
this.entries = [];
|
|
3941
|
-
let j = this.ackIndex + 8;
|
|
3942
|
-
for (let i2 = 0;i2 < this.count; i2++) {
|
|
3943
|
-
this.entries.push({
|
|
3944
|
-
code: view.getUint8(j),
|
|
3945
|
-
type: view.getUint8(j + 1),
|
|
3946
|
-
desc: view.getUint8(j + 2),
|
|
3947
|
-
spare: view.getUint8(j + 3),
|
|
3948
|
-
time: view.getUint32(j + 4, true)
|
|
3949
|
-
});
|
|
3950
|
-
j += size;
|
|
3951
|
-
}
|
|
3952
|
-
}
|
|
3953
|
-
}
|
|
3954
|
-
|
|
3955
3831
|
class GetRadioStatusReplyD2HPacket extends HostBoundPacket {
|
|
3956
3832
|
static COMMAND_ID = 86;
|
|
3957
3833
|
static COMMAND_EXTENDED_ID = 38;
|
|
@@ -4000,40 +3876,6 @@ class WriteKeyValueReplyD2HPacket extends HostBoundPacket {
|
|
|
4000
3876
|
static COMMAND_ID = 86;
|
|
4001
3877
|
static COMMAND_EXTENDED_ID = 47;
|
|
4002
3878
|
}
|
|
4003
|
-
|
|
4004
|
-
class GetSlot1to4InfoReplyD2HPacket extends HostBoundPacket {
|
|
4005
|
-
static COMMAND_ID = 86;
|
|
4006
|
-
static COMMAND_EXTENDED_ID = 49;
|
|
4007
|
-
slotFlags;
|
|
4008
|
-
slots;
|
|
4009
|
-
constructor(data, start = 1) {
|
|
4010
|
-
super(data);
|
|
4011
|
-
const view = PacketView.fromPacket(this);
|
|
4012
|
-
this.slotFlags = view.nextUint8();
|
|
4013
|
-
this.slots = [];
|
|
4014
|
-
for (let i2 = 0;i2 < 4; i2++) {
|
|
4015
|
-
if ((this.slotFlags & 1 << start - 1 + i2) === 0)
|
|
4016
|
-
continue;
|
|
4017
|
-
const icon = view.nextUint16();
|
|
4018
|
-
const nameLen = view.nextUint8();
|
|
4019
|
-
this.slots.push({
|
|
4020
|
-
slot: start + i2,
|
|
4021
|
-
icon,
|
|
4022
|
-
name: view.nextString(nameLen)
|
|
4023
|
-
});
|
|
4024
|
-
}
|
|
4025
|
-
}
|
|
4026
|
-
}
|
|
4027
|
-
|
|
4028
|
-
class GetSlot5to8InfoReplyD2HPacket extends GetSlot1to4InfoReplyD2HPacket {
|
|
4029
|
-
static COMMAND_ID = 86;
|
|
4030
|
-
static COMMAND_EXTENDED_ID = 50;
|
|
4031
|
-
slotStartIndex = 5;
|
|
4032
|
-
constructor(data) {
|
|
4033
|
-
super(data, 5);
|
|
4034
|
-
}
|
|
4035
|
-
}
|
|
4036
|
-
|
|
4037
3879
|
class FactoryStatusReplyD2HPacket extends HostBoundPacket {
|
|
4038
3880
|
static COMMAND_ID = 86;
|
|
4039
3881
|
static COMMAND_EXTENDED_ID = 241;
|
|
@@ -4051,122 +3893,32 @@ class FactoryEnableReplyD2HPacket extends HostBoundPacket {
|
|
|
4051
3893
|
static COMMAND_ID = 86;
|
|
4052
3894
|
static COMMAND_EXTENDED_ID = 255;
|
|
4053
3895
|
}
|
|
4054
|
-
var textEncoder2 = new TextEncoder;
|
|
4055
|
-
var HEADER_TO_DEVICE = Uint8Array.of(201, 54, 184, 71);
|
|
4056
|
-
function encodeFixedText(value, field, maxBytes) {
|
|
4057
|
-
const encoded = textEncoder2.encode(value);
|
|
4058
|
-
if (encoded.byteLength > maxBytes) {
|
|
4059
|
-
throw new RangeError(`${field} must be at most ${maxBytes} UTF-8 bytes`);
|
|
4060
|
-
}
|
|
4061
|
-
return encoded;
|
|
4062
|
-
}
|
|
4063
|
-
|
|
4064
|
-
class PacketEncoder {
|
|
4065
|
-
static HEADERS_LENGTH = 4;
|
|
4066
|
-
static HEADER_TO_DEVICE = [201, 54, 184, 71];
|
|
4067
|
-
static HEADER_TO_HOST = [170, 85];
|
|
4068
|
-
static J2000_EPOCH = 946684800;
|
|
4069
|
-
vexVersion = 0;
|
|
4070
|
-
crcgen = new CrcGenerator;
|
|
4071
|
-
allPacketsTable = new Map;
|
|
4072
|
-
static getInstance() {
|
|
4073
|
-
Packet.ENCODER ??= new PacketEncoder;
|
|
4074
|
-
return Packet.ENCODER;
|
|
4075
|
-
}
|
|
4076
|
-
constructor() {
|
|
4077
|
-
for (const packet of Object.values(exports_VexPacketModels)) {
|
|
4078
|
-
if (typeof packet === "function" && packet.prototype instanceof HostBoundPacket) {
|
|
4079
|
-
const type = packet;
|
|
4080
|
-
let byExtendedId = this.allPacketsTable.get(type.COMMAND_ID);
|
|
4081
|
-
if (byExtendedId === undefined) {
|
|
4082
|
-
byExtendedId = new Map;
|
|
4083
|
-
this.allPacketsTable.set(type.COMMAND_ID, byExtendedId);
|
|
4084
|
-
}
|
|
4085
|
-
byExtendedId.set(type.COMMAND_EXTENDED_ID, type);
|
|
4086
|
-
}
|
|
4087
|
-
}
|
|
4088
|
-
}
|
|
4089
|
-
getPacketType(commandId, commandExtendedId) {
|
|
4090
|
-
if (commandId === undefined)
|
|
4091
|
-
return;
|
|
4092
|
-
return this.allPacketsTable.get(commandId)?.get(commandExtendedId);
|
|
4093
|
-
}
|
|
4094
|
-
createHeader(buf) {
|
|
4095
|
-
if (buf === undefined || buf.byteLength < PacketEncoder.HEADERS_LENGTH) {
|
|
4096
|
-
buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH);
|
|
4097
|
-
}
|
|
4098
|
-
const h = new Uint8Array(buf);
|
|
4099
|
-
h.set(HEADER_TO_DEVICE);
|
|
4100
|
-
return h;
|
|
4101
|
-
}
|
|
4102
|
-
cdcCommand(cmd) {
|
|
4103
|
-
const h = new Uint8Array(5);
|
|
4104
|
-
h.set(HEADER_TO_DEVICE);
|
|
4105
|
-
h[4] = cmd;
|
|
4106
|
-
return h;
|
|
4107
|
-
}
|
|
4108
|
-
cdcCommandWithData(cmd, data) {
|
|
4109
|
-
const h = new Uint8Array(6 + data.length);
|
|
4110
|
-
h.set(HEADER_TO_DEVICE);
|
|
4111
|
-
h[4] = cmd;
|
|
4112
|
-
h[5] = data.length;
|
|
4113
|
-
h.set(data, 6);
|
|
4114
|
-
return h;
|
|
4115
|
-
}
|
|
4116
|
-
cdc2Command(cmd, ext) {
|
|
4117
|
-
const h = new Uint8Array(9);
|
|
4118
|
-
h.set(HEADER_TO_DEVICE);
|
|
4119
|
-
h[4] = cmd;
|
|
4120
|
-
h[5] = ext;
|
|
4121
|
-
h[6] = 0;
|
|
4122
|
-
this.appendCrc16(h);
|
|
4123
|
-
return h;
|
|
4124
|
-
}
|
|
4125
|
-
cdc2CommandBufferLength(data) {
|
|
4126
|
-
return PacketEncoder.HEADERS_LENGTH + data.length + 5 + (data.length > 127 ? 1 : 0);
|
|
4127
|
-
}
|
|
4128
|
-
cdc2CommandWithData(cmd, ext, data) {
|
|
4129
|
-
const h = new Uint8Array(this.cdc2CommandBufferLength(data));
|
|
4130
|
-
h.set(HEADER_TO_DEVICE);
|
|
4131
|
-
h[4] = cmd;
|
|
4132
|
-
h[5] = ext;
|
|
4133
|
-
if (data.length < 128) {
|
|
4134
|
-
h[6] = data.length;
|
|
4135
|
-
h.set(data, 7);
|
|
4136
|
-
} else {
|
|
4137
|
-
h[6] = data.length >>> 8 | 128;
|
|
4138
|
-
h[7] = data.length & 255;
|
|
4139
|
-
h.set(data, 8);
|
|
4140
|
-
}
|
|
4141
|
-
this.appendCrc16(h);
|
|
4142
|
-
return h;
|
|
4143
|
-
}
|
|
4144
|
-
appendCrc16(h) {
|
|
4145
|
-
const crc2 = this.crcgen.crc16(h.subarray(0, h.length - 2), 0);
|
|
4146
|
-
h[h.length - 2] = crc2 >>> 8;
|
|
4147
|
-
h[h.length - 1] = crc2 & 255;
|
|
4148
|
-
}
|
|
4149
|
-
validateHeader(data) {
|
|
4150
|
-
return data[0] === PacketEncoder.HEADER_TO_HOST[0] && data[1] === PacketEncoder.HEADER_TO_HOST[1];
|
|
4151
|
-
}
|
|
4152
|
-
validateMessageCdc(data) {
|
|
4153
|
-
const crc2 = (data[data.byteLength - 2] << 8) + data[data.byteLength - 1];
|
|
4154
|
-
return this.crcgen.crc16(data.subarray(0, data.byteLength - 2), 0) === crc2;
|
|
4155
|
-
}
|
|
4156
|
-
getPayloadSize(data) {
|
|
4157
|
-
const a2 = data[3];
|
|
4158
|
-
return (a2 & 128) === 0 ? a2 : ((a2 & 127) << 8) + data[4];
|
|
4159
|
-
}
|
|
4160
|
-
getHostHeaderLength(data) {
|
|
4161
|
-
return (data[3] & 128) === 0 ? 4 : 5;
|
|
4162
|
-
}
|
|
4163
|
-
}
|
|
4164
|
-
var thePacketEncoder = PacketEncoder.getInstance();
|
|
4165
3896
|
var SCREEN_CAPTURE_HEIGHT = 272;
|
|
4166
3897
|
var SCREEN_CAPTURE_WIDTH = 480;
|
|
4167
3898
|
var SCREEN_CAPTURE_CHANNELS = 3;
|
|
4168
3899
|
var SCREEN_CAPTURE_MESSAGE_WIDTH = 512;
|
|
4169
3900
|
var SCREEN_CAPTURE_MESSAGE_CHANNELS = 4;
|
|
3901
|
+
var SCREEN_CAPTURE_FRAMEBUFFER_SIZE = SCREEN_CAPTURE_MESSAGE_WIDTH * SCREEN_CAPTURE_HEIGHT * SCREEN_CAPTURE_MESSAGE_CHANNELS;
|
|
3902
|
+
function convertScreenCapture(framebuffer) {
|
|
3903
|
+
if (framebuffer.length !== SCREEN_CAPTURE_FRAMEBUFFER_SIZE) {
|
|
3904
|
+
throw new Error(`bad screen capture framebuffer size: ${framebuffer.length}; expected ${SCREEN_CAPTURE_FRAMEBUFFER_SIZE}`);
|
|
3905
|
+
}
|
|
3906
|
+
const pixels = new Uint8Array(SCREEN_CAPTURE_WIDTH * SCREEN_CAPTURE_HEIGHT * SCREEN_CAPTURE_CHANNELS);
|
|
3907
|
+
let source = 0;
|
|
3908
|
+
let target = 0;
|
|
3909
|
+
for (let row = 0;row < SCREEN_CAPTURE_HEIGHT; row++) {
|
|
3910
|
+
for (let column = 0;column < SCREEN_CAPTURE_WIDTH; column++) {
|
|
3911
|
+
pixels[target] = framebuffer[source + 2];
|
|
3912
|
+
pixels[target + 1] = framebuffer[source + 1];
|
|
3913
|
+
pixels[target + 2] = framebuffer[source];
|
|
3914
|
+
source += SCREEN_CAPTURE_MESSAGE_CHANNELS;
|
|
3915
|
+
target += SCREEN_CAPTURE_CHANNELS;
|
|
3916
|
+
}
|
|
3917
|
+
source += (SCREEN_CAPTURE_MESSAGE_WIDTH - SCREEN_CAPTURE_WIDTH) * SCREEN_CAPTURE_MESSAGE_CHANNELS;
|
|
3918
|
+
}
|
|
3919
|
+
return pixels;
|
|
3920
|
+
}
|
|
3921
|
+
var thePacketEncoder = PacketEncoder.getInstance();
|
|
4170
3922
|
|
|
4171
3923
|
class VexSerialConnection extends VexEventTarget {
|
|
4172
3924
|
filters = [{ usbVendorId: 10376 }];
|
|
@@ -4174,12 +3926,31 @@ class VexSerialConnection extends VexEventTarget {
|
|
|
4174
3926
|
reader;
|
|
4175
3927
|
port;
|
|
4176
3928
|
serial;
|
|
4177
|
-
|
|
3929
|
+
pendingCallbacks = new Map;
|
|
3930
|
+
rawCallbacks = {
|
|
3931
|
+
head: undefined,
|
|
3932
|
+
tail: undefined
|
|
3933
|
+
};
|
|
3934
|
+
pendingCommandTails = new Map;
|
|
4178
3935
|
_onPortDisconnect = null;
|
|
4179
3936
|
_closePromise = null;
|
|
3937
|
+
_openPromise = null;
|
|
3938
|
+
_isClosing = false;
|
|
4180
3939
|
_wasConnected = false;
|
|
4181
3940
|
fileTransferTail = Promise.resolve();
|
|
4182
3941
|
fileTransferDepth = 0;
|
|
3942
|
+
get callbacksQueue() {
|
|
3943
|
+
const callbacks = [];
|
|
3944
|
+
for (const queue of this.pendingCallbacks.values()) {
|
|
3945
|
+
for (let callback = queue.head;callback; callback = callback.next) {
|
|
3946
|
+
callbacks.push(callback);
|
|
3947
|
+
}
|
|
3948
|
+
}
|
|
3949
|
+
for (let callback = this.rawCallbacks.head;callback; callback = callback.next) {
|
|
3950
|
+
callbacks.push(callback);
|
|
3951
|
+
}
|
|
3952
|
+
return callbacks;
|
|
3953
|
+
}
|
|
4183
3954
|
get isConnected() {
|
|
4184
3955
|
return this.port !== undefined && this.reader !== undefined && this.writer !== undefined;
|
|
4185
3956
|
}
|
|
@@ -4191,27 +3962,45 @@ class VexSerialConnection extends VexEventTarget {
|
|
|
4191
3962
|
this.serial = serial;
|
|
4192
3963
|
}
|
|
4193
3964
|
reportWarning(message, details) {
|
|
4194
|
-
this.
|
|
3965
|
+
this.emitSafely("warning", {
|
|
3966
|
+
message,
|
|
3967
|
+
details
|
|
3968
|
+
});
|
|
3969
|
+
}
|
|
3970
|
+
emitSafely(eventName, data) {
|
|
3971
|
+
try {
|
|
3972
|
+
this.emit(eventName, data);
|
|
3973
|
+
} catch {}
|
|
4195
3974
|
}
|
|
4196
3975
|
async close() {
|
|
4197
3976
|
if (this._closePromise)
|
|
4198
3977
|
return this._closePromise;
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
this._closePromise =
|
|
3978
|
+
this._isClosing = true;
|
|
3979
|
+
const closing = this._closeAfterOpen();
|
|
3980
|
+
this._closePromise = closing;
|
|
4202
3981
|
try {
|
|
4203
|
-
await
|
|
3982
|
+
await closing;
|
|
4204
3983
|
} finally {
|
|
4205
|
-
this._closePromise
|
|
3984
|
+
if (this._closePromise === closing)
|
|
3985
|
+
this._closePromise = null;
|
|
3986
|
+
this._isClosing = false;
|
|
4206
3987
|
}
|
|
4207
3988
|
}
|
|
3989
|
+
async _closeAfterOpen() {
|
|
3990
|
+
const opening = this._openPromise;
|
|
3991
|
+
if (opening !== null)
|
|
3992
|
+
await opening;
|
|
3993
|
+
if (!this._hasOpenResources())
|
|
3994
|
+
return;
|
|
3995
|
+
await this._doClose();
|
|
3996
|
+
}
|
|
4208
3997
|
_hasOpenResources() {
|
|
4209
|
-
return this.port !== undefined || this.reader !== undefined || this.writer !== undefined || this._onPortDisconnect !== null || this.
|
|
3998
|
+
return this.port !== undefined || this.reader !== undefined || this.writer !== undefined || this._onPortDisconnect !== null || this.hasPendingCallbacks();
|
|
4210
3999
|
}
|
|
4211
4000
|
async _doClose() {
|
|
4212
|
-
for (const callback of this.
|
|
4001
|
+
for (const callback of this.drainPendingCallbacks()) {
|
|
4213
4002
|
clearTimeout(callback.timeout);
|
|
4214
|
-
callback.callback(
|
|
4003
|
+
callback.callback(258);
|
|
4215
4004
|
}
|
|
4216
4005
|
const onDisconnect = this._onPortDisconnect;
|
|
4217
4006
|
this._onPortDisconnect = null;
|
|
@@ -4260,11 +4049,22 @@ class VexSerialConnection extends VexEventTarget {
|
|
|
4260
4049
|
}
|
|
4261
4050
|
if (this._wasConnected) {
|
|
4262
4051
|
this._wasConnected = false;
|
|
4263
|
-
this.
|
|
4052
|
+
this.emitSafely("disconnected", undefined);
|
|
4264
4053
|
}
|
|
4265
4054
|
}
|
|
4266
4055
|
open(use = 0, askUser = true) {
|
|
4267
|
-
|
|
4056
|
+
if (this._openPromise !== null)
|
|
4057
|
+
return new ResultAsync(this._openPromise);
|
|
4058
|
+
const opening = this._open(use, askUser);
|
|
4059
|
+
this._openPromise = opening;
|
|
4060
|
+
opening.then(() => {
|
|
4061
|
+
if (this._openPromise === opening)
|
|
4062
|
+
this._openPromise = null;
|
|
4063
|
+
}, () => {
|
|
4064
|
+
if (this._openPromise === opening)
|
|
4065
|
+
this._openPromise = null;
|
|
4066
|
+
});
|
|
4067
|
+
return new ResultAsync(opening);
|
|
4268
4068
|
}
|
|
4269
4069
|
async _open(use, askUser) {
|
|
4270
4070
|
if (this._closePromise !== null)
|
|
@@ -4297,38 +4097,63 @@ class VexSerialConnection extends VexEventTarget {
|
|
|
4297
4097
|
this.reader = this.port.readable.getReader();
|
|
4298
4098
|
this.startReader();
|
|
4299
4099
|
this._wasConnected = true;
|
|
4300
|
-
this.
|
|
4100
|
+
this.emitSafely("connected", undefined);
|
|
4301
4101
|
return ok("opened");
|
|
4302
4102
|
} catch (e) {
|
|
4303
|
-
await this.
|
|
4103
|
+
await this._doClose();
|
|
4304
4104
|
return err(toVexSerialError(e, "io"));
|
|
4305
4105
|
}
|
|
4306
4106
|
}
|
|
4307
4107
|
async writeDataAsync(rawData, timeout = 1000) {
|
|
4108
|
+
if (rawData instanceof DeviceBoundPacket) {
|
|
4109
|
+
return this.serializeCommand(rawData.commandId, rawData.commandExtendedId, () => this.writeDataAsyncUnserialized(rawData, timeout));
|
|
4110
|
+
}
|
|
4111
|
+
return this.writeDataAsyncUnserialized(rawData, timeout);
|
|
4112
|
+
}
|
|
4113
|
+
async serializeCommand(commandId, commandExtendedId, operation) {
|
|
4114
|
+
const key = `${commandId}:${commandExtendedId ?? ""}`;
|
|
4115
|
+
const previous = this.pendingCommandTails.get(key) ?? Promise.resolve();
|
|
4116
|
+
let release = () => {};
|
|
4117
|
+
const current = new Promise((resolve) => {
|
|
4118
|
+
release = resolve;
|
|
4119
|
+
});
|
|
4120
|
+
this.pendingCommandTails.set(key, current);
|
|
4121
|
+
await previous;
|
|
4122
|
+
try {
|
|
4123
|
+
return await operation();
|
|
4124
|
+
} finally {
|
|
4125
|
+
release();
|
|
4126
|
+
if (this.pendingCommandTails.get(key) === current) {
|
|
4127
|
+
this.pendingCommandTails.delete(key);
|
|
4128
|
+
}
|
|
4129
|
+
}
|
|
4130
|
+
}
|
|
4131
|
+
async writeDataAsyncUnserialized(rawData, timeout) {
|
|
4308
4132
|
return new Promise((resolve) => {
|
|
4309
|
-
if (this.writer === undefined) {
|
|
4310
|
-
resolve(
|
|
4133
|
+
if (this.writer === undefined || this._isClosing) {
|
|
4134
|
+
resolve(258);
|
|
4311
4135
|
return;
|
|
4312
4136
|
}
|
|
4313
4137
|
const data = rawData instanceof DeviceBoundPacket ? rawData.data : rawData;
|
|
4138
|
+
const queue = rawData instanceof DeviceBoundPacket ? this.getPendingQueue(rawData.commandId, rawData.commandExtendedId, true) : this.rawCallbacks;
|
|
4314
4139
|
const cb = {
|
|
4140
|
+
active: true,
|
|
4315
4141
|
callback: resolve,
|
|
4316
4142
|
timeout: setTimeout(() => {
|
|
4317
|
-
|
|
4318
|
-
if (index === -1)
|
|
4143
|
+
if (!this.removePendingCallback(cb))
|
|
4319
4144
|
return;
|
|
4320
|
-
this.callbacksQueue.splice(index, 1);
|
|
4321
4145
|
cb.callback(256);
|
|
4322
4146
|
}, timeout),
|
|
4147
|
+
next: undefined,
|
|
4148
|
+
previous: undefined,
|
|
4149
|
+
queue,
|
|
4323
4150
|
wantedCommandId: rawData instanceof DeviceBoundPacket ? rawData.commandId : undefined,
|
|
4324
4151
|
wantedCommandExId: rawData instanceof DeviceBoundPacket ? rawData.commandExtendedId : undefined
|
|
4325
4152
|
};
|
|
4326
|
-
this.
|
|
4153
|
+
this.enqueuePendingCallback(cb);
|
|
4327
4154
|
this.writer.write(data).catch(() => {
|
|
4328
|
-
|
|
4329
|
-
if (index === -1)
|
|
4155
|
+
if (!this.removePendingCallback(cb))
|
|
4330
4156
|
return;
|
|
4331
|
-
this.callbacksQueue.splice(index, 1);
|
|
4332
4157
|
clearTimeout(cb.timeout);
|
|
4333
4158
|
resolve(257);
|
|
4334
4159
|
});
|
|
@@ -4339,6 +4164,9 @@ class VexSerialConnection extends VexEventTarget {
|
|
|
4339
4164
|
const result = await this.writeDataAsync(packet, timeout);
|
|
4340
4165
|
if (result instanceof ReplyType)
|
|
4341
4166
|
return ok(result);
|
|
4167
|
+
if (result === 258) {
|
|
4168
|
+
return err(new VexNotConnectedError);
|
|
4169
|
+
}
|
|
4342
4170
|
return err(new VexProtocolError(expectedReplyMessage(packet, ReplyType, result), typeof result === "number" ? result : undefined));
|
|
4343
4171
|
})());
|
|
4344
4172
|
}
|
|
@@ -4349,56 +4177,48 @@ class VexSerialConnection extends VexEventTarget {
|
|
|
4349
4177
|
const { value: readData, done: isDone } = await this.reader.read();
|
|
4350
4178
|
if (isDone)
|
|
4351
4179
|
throw new Error("No data");
|
|
4352
|
-
cache
|
|
4180
|
+
cache.append(readData);
|
|
4353
4181
|
}
|
|
4354
|
-
return cache;
|
|
4355
4182
|
}
|
|
4356
4183
|
async startReader() {
|
|
4357
|
-
|
|
4184
|
+
const cache = new ReceiveBuffer;
|
|
4358
4185
|
let sliceIdx = 0;
|
|
4359
4186
|
for (;; )
|
|
4360
4187
|
try {
|
|
4361
|
-
|
|
4188
|
+
await this.readData(cache, 5);
|
|
4362
4189
|
sliceIdx = 0;
|
|
4363
|
-
while (!thePacketEncoder.validateHeader(cache)) {
|
|
4364
|
-
const
|
|
4190
|
+
while (!thePacketEncoder.validateHeader(cache.bytes)) {
|
|
4191
|
+
const bytes = cache.bytes;
|
|
4192
|
+
const nextHeader = bytes.findIndex((byte, index) => index > 0 && byte === PacketEncoder.HEADER_TO_HOST[0] && bytes[index + 1] === PacketEncoder.HEADER_TO_HOST[1]);
|
|
4365
4193
|
if (nextHeader >= 0) {
|
|
4366
|
-
cache
|
|
4194
|
+
cache.discard(nextHeader);
|
|
4367
4195
|
} else {
|
|
4368
|
-
cache
|
|
4196
|
+
cache.discard(bytes.at(-1) === PacketEncoder.HEADER_TO_HOST[0] ? -1 : bytes.length);
|
|
4369
4197
|
}
|
|
4370
|
-
|
|
4198
|
+
await this.readData(cache, 5);
|
|
4371
4199
|
}
|
|
4372
|
-
const payloadExpectedSize = thePacketEncoder.getPayloadSize(cache);
|
|
4373
|
-
const n2 = thePacketEncoder.getHostHeaderLength(cache);
|
|
4200
|
+
const payloadExpectedSize = thePacketEncoder.getPayloadSize(cache.bytes);
|
|
4201
|
+
const n2 = thePacketEncoder.getHostHeaderLength(cache.bytes);
|
|
4374
4202
|
const totalSize = n2 + payloadExpectedSize;
|
|
4375
|
-
|
|
4203
|
+
await this.readData(cache, totalSize);
|
|
4376
4204
|
sliceIdx = totalSize;
|
|
4377
|
-
const
|
|
4205
|
+
const packet = cache.copy(totalSize);
|
|
4206
|
+
const cmdId = packet[2];
|
|
4378
4207
|
const hasExtId = cmdId === 88 || cmdId === 86;
|
|
4379
|
-
const cmdExId = hasExtId ?
|
|
4380
|
-
const ack =
|
|
4208
|
+
const cmdExId = hasExtId ? packet[n2] : undefined;
|
|
4209
|
+
const ack = packet[n2 + 1];
|
|
4381
4210
|
if (hasExtId) {
|
|
4382
|
-
if (!thePacketEncoder.validateMessageCdc(
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
const candidate = this.callbacksQueue[i2];
|
|
4389
|
-
if (candidate.wantedCommandId === undefined && candidate.wantedCommandExId === undefined) {
|
|
4390
|
-
if (untypedIdx === -1)
|
|
4391
|
-
untypedIdx = i2;
|
|
4211
|
+
if (!thePacketEncoder.validateMessageCdc(packet)) {
|
|
4212
|
+
this.reportWarning("discarding a reply with an invalid CDC CRC", {
|
|
4213
|
+
commandId: cmdId,
|
|
4214
|
+
commandExtendedId: cmdExId,
|
|
4215
|
+
ack
|
|
4216
|
+
});
|
|
4392
4217
|
continue;
|
|
4393
4218
|
}
|
|
4394
|
-
if ((candidate.wantedCommandId === undefined || candidate.wantedCommandId === cmdId) && (candidate.wantedCommandExId === undefined || candidate.wantedCommandExId === cmdExId)) {
|
|
4395
|
-
matchIdx = i2;
|
|
4396
|
-
break;
|
|
4397
|
-
}
|
|
4398
4219
|
}
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
if (matchIdx === -1) {
|
|
4220
|
+
const callbackInfo = this.shiftPendingCallback(cmdId, cmdExId) ?? this.shiftRawCallback();
|
|
4221
|
+
if (callbackInfo === undefined) {
|
|
4402
4222
|
this.reportWarning("received a reply with no matching request", {
|
|
4403
4223
|
commandId: cmdId,
|
|
4404
4224
|
commandExtendedId: cmdExId,
|
|
@@ -4406,38 +4226,117 @@ class VexSerialConnection extends VexEventTarget {
|
|
|
4406
4226
|
});
|
|
4407
4227
|
continue;
|
|
4408
4228
|
}
|
|
4409
|
-
const callbackInfo = this.callbacksQueue[matchIdx];
|
|
4410
4229
|
const wantedCmdId = callbackInfo.wantedCommandId;
|
|
4411
4230
|
const wantedCmdExId = callbackInfo.wantedCommandExId;
|
|
4412
|
-
const data = cache.slice(0, sliceIdx);
|
|
4413
4231
|
const PackageType = thePacketEncoder.getPacketType(wantedCmdId, wantedCmdExId);
|
|
4414
4232
|
if (wantedCmdId === undefined || PackageType === undefined) {
|
|
4415
4233
|
if (wantedCmdId !== undefined) {
|
|
4416
4234
|
this.reportWarning("no packet class is registered for the wanted command", { commandId: wantedCmdId, commandExtendedId: wantedCmdExId });
|
|
4417
4235
|
}
|
|
4418
|
-
callbackInfo.callback(
|
|
4236
|
+
callbackInfo.callback(packet.buffer);
|
|
4419
4237
|
} else {
|
|
4420
|
-
if (
|
|
4421
|
-
callbackInfo.callback(new PackageType(
|
|
4238
|
+
if (PackageType.isValidPacket(packet, n2)) {
|
|
4239
|
+
callbackInfo.callback(new PackageType(packet));
|
|
4422
4240
|
} else {
|
|
4423
4241
|
this.reportWarning("reply failed packet validation; delivering its ack instead", { commandId: cmdId, commandExtendedId: cmdExId, ack });
|
|
4424
4242
|
callbackInfo.callback(ack);
|
|
4425
4243
|
}
|
|
4426
4244
|
}
|
|
4427
4245
|
clearTimeout(callbackInfo.timeout);
|
|
4428
|
-
this.callbacksQueue.splice(matchIdx, 1);
|
|
4429
4246
|
} catch (e) {
|
|
4430
4247
|
if (!(e instanceof Error && e.message === "No data")) {
|
|
4431
4248
|
this.reportWarning("reader loop stopped by a read error", {
|
|
4432
4249
|
error: e,
|
|
4433
|
-
pendingBytes: cache
|
|
4250
|
+
pendingBytes: cache.bytes
|
|
4434
4251
|
});
|
|
4435
4252
|
}
|
|
4436
4253
|
await this.close();
|
|
4437
4254
|
break;
|
|
4438
4255
|
} finally {
|
|
4439
|
-
cache
|
|
4256
|
+
cache.discard(sliceIdx);
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
pendingKey(commandId, commandExtendedId) {
|
|
4260
|
+
return `${commandId}:${commandExtendedId ?? ""}`;
|
|
4261
|
+
}
|
|
4262
|
+
getPendingQueue(commandId, commandExtendedId, create) {
|
|
4263
|
+
const key = this.pendingKey(commandId, commandExtendedId);
|
|
4264
|
+
let queue = this.pendingCallbacks.get(key);
|
|
4265
|
+
if (queue === undefined && create) {
|
|
4266
|
+
const created = { head: undefined, tail: undefined };
|
|
4267
|
+
this.pendingCallbacks.set(key, created);
|
|
4268
|
+
queue = created;
|
|
4269
|
+
}
|
|
4270
|
+
return queue ?? { head: undefined, tail: undefined };
|
|
4271
|
+
}
|
|
4272
|
+
enqueuePendingCallback(callback) {
|
|
4273
|
+
const tail = callback.queue.tail;
|
|
4274
|
+
callback.previous = tail;
|
|
4275
|
+
if (tail === undefined)
|
|
4276
|
+
callback.queue.head = callback;
|
|
4277
|
+
else
|
|
4278
|
+
tail.next = callback;
|
|
4279
|
+
callback.queue.tail = callback;
|
|
4280
|
+
}
|
|
4281
|
+
removePendingCallback(callback) {
|
|
4282
|
+
if (!callback.active)
|
|
4283
|
+
return false;
|
|
4284
|
+
callback.active = false;
|
|
4285
|
+
const { queue, previous, next } = callback;
|
|
4286
|
+
if (previous === undefined)
|
|
4287
|
+
queue.head = next;
|
|
4288
|
+
else
|
|
4289
|
+
previous.next = next;
|
|
4290
|
+
if (next === undefined)
|
|
4291
|
+
queue.tail = previous;
|
|
4292
|
+
else
|
|
4293
|
+
next.previous = previous;
|
|
4294
|
+
callback.previous = undefined;
|
|
4295
|
+
callback.next = undefined;
|
|
4296
|
+
if (queue !== this.rawCallbacks && queue.head === undefined && callback.wantedCommandId !== undefined) {
|
|
4297
|
+
this.pendingCallbacks.delete(this.pendingKey(callback.wantedCommandId, callback.wantedCommandExId));
|
|
4298
|
+
}
|
|
4299
|
+
return true;
|
|
4300
|
+
}
|
|
4301
|
+
shiftPendingCallback(commandId, commandExtendedId) {
|
|
4302
|
+
const queue = this.getPendingQueue(commandId, commandExtendedId, false);
|
|
4303
|
+
const callback = queue.head;
|
|
4304
|
+
if (callback !== undefined)
|
|
4305
|
+
this.removePendingCallback(callback);
|
|
4306
|
+
return callback;
|
|
4307
|
+
}
|
|
4308
|
+
shiftRawCallback() {
|
|
4309
|
+
const callback = this.rawCallbacks.head;
|
|
4310
|
+
if (callback !== undefined)
|
|
4311
|
+
this.removePendingCallback(callback);
|
|
4312
|
+
return callback;
|
|
4313
|
+
}
|
|
4314
|
+
hasPendingCallbacks() {
|
|
4315
|
+
return this.pendingCallbacks.size > 0 || this.rawCallbacks.head !== undefined;
|
|
4316
|
+
}
|
|
4317
|
+
drainPendingCallbacks() {
|
|
4318
|
+
const callbacks = [];
|
|
4319
|
+
for (const queue of this.pendingCallbacks.values()) {
|
|
4320
|
+
for (let callback = queue.head;callback; ) {
|
|
4321
|
+
const next = callback.next;
|
|
4322
|
+
callback.active = false;
|
|
4323
|
+
callback.previous = undefined;
|
|
4324
|
+
callback.next = undefined;
|
|
4325
|
+
callbacks.push(callback);
|
|
4326
|
+
callback = next;
|
|
4440
4327
|
}
|
|
4328
|
+
}
|
|
4329
|
+
for (let callback = this.rawCallbacks.head;callback; ) {
|
|
4330
|
+
const next = callback.next;
|
|
4331
|
+
callback.active = false;
|
|
4332
|
+
callback.previous = undefined;
|
|
4333
|
+
callback.next = undefined;
|
|
4334
|
+
callbacks.push(callback);
|
|
4335
|
+
callback = next;
|
|
4336
|
+
}
|
|
4337
|
+
this.pendingCallbacks.clear();
|
|
4338
|
+
this.rawCallbacks = { head: undefined, tail: undefined };
|
|
4339
|
+
return callbacks;
|
|
4441
4340
|
}
|
|
4442
4341
|
query1() {
|
|
4443
4342
|
return this.request(new Query1H2DPacket, Query1ReplyD2HPacket, 100);
|
|
@@ -4555,7 +4454,9 @@ class V5SerialConnection extends VexSerialConnection {
|
|
|
4555
4454
|
let bufferOffset = 0;
|
|
4556
4455
|
const fileBuf = new Uint8Array(fileSize);
|
|
4557
4456
|
while (bufferOffset < fileSize) {
|
|
4558
|
-
const
|
|
4457
|
+
const remainingSize = fileSize - bufferOffset;
|
|
4458
|
+
const chunkSize = Math.min(bufferChunkSize, remainingSize);
|
|
4459
|
+
const requestedSize = chunkSize + 3 & ~3;
|
|
4559
4460
|
const p2Result = await this.request(new ReadFileH2DPacket(nextAddress, requestedSize), ReadFileReplyD2HPacket, 3000);
|
|
4560
4461
|
if (p2Result.isErr())
|
|
4561
4462
|
throw p2Result.error;
|
|
@@ -4566,9 +4467,10 @@ class V5SerialConnection extends VexSerialConnection {
|
|
|
4566
4467
|
if (p2.length <= 0 || p2.length > requestedSize || p2.buf.byteLength !== p2.length) {
|
|
4567
4468
|
throw new VexTransferError(`ReadFileReplyD2HPacket returned invalid length ${p2.length}`);
|
|
4568
4469
|
}
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4470
|
+
const receivedSize = Math.min(p2.length, remainingSize);
|
|
4471
|
+
fileBuf.set(p2.buf.subarray(0, receivedSize), bufferOffset);
|
|
4472
|
+
bufferOffset += receivedSize;
|
|
4473
|
+
nextAddress += receivedSize;
|
|
4572
4474
|
progressCallback?.(bufferOffset, fileSize);
|
|
4573
4475
|
}
|
|
4574
4476
|
transferFailed = false;
|
|
@@ -4723,7 +4625,7 @@ class V5SerialConnection extends VexSerialConnection {
|
|
|
4723
4625
|
filename: "screen",
|
|
4724
4626
|
vendor: 15,
|
|
4725
4627
|
loadAddress: 0,
|
|
4726
|
-
size:
|
|
4628
|
+
size: SCREEN_CAPTURE_FRAMEBUFFER_SIZE
|
|
4727
4629
|
}, 2, progressCallback);
|
|
4728
4630
|
if (framebuffer.isErr())
|
|
4729
4631
|
return err(framebuffer.error);
|
|
@@ -4748,34 +4650,60 @@ class V5SerialConnection extends VexSerialConnection {
|
|
|
4748
4650
|
return this.request(new SelectDashH2DPacket(screen, port), SelectDashReplyD2HPacket);
|
|
4749
4651
|
}
|
|
4750
4652
|
}
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4653
|
+
|
|
4654
|
+
class ReceiveBuffer {
|
|
4655
|
+
storage = new Uint8Array(0);
|
|
4656
|
+
start = 0;
|
|
4657
|
+
end = 0;
|
|
4658
|
+
get byteLength() {
|
|
4659
|
+
return this.end - this.start;
|
|
4660
|
+
}
|
|
4661
|
+
get bytes() {
|
|
4662
|
+
return this.storage.subarray(this.start, this.end);
|
|
4663
|
+
}
|
|
4664
|
+
append(chunk) {
|
|
4665
|
+
this.reserve(chunk.byteLength);
|
|
4666
|
+
this.storage.set(chunk, this.end);
|
|
4667
|
+
this.end += chunk.byteLength;
|
|
4668
|
+
}
|
|
4669
|
+
copy(length) {
|
|
4670
|
+
return this.bytes.slice(0, length);
|
|
4671
|
+
}
|
|
4672
|
+
discard(length) {
|
|
4673
|
+
this.start += length < 0 ? this.byteLength + length : length;
|
|
4674
|
+
if (this.start < 0)
|
|
4675
|
+
this.start = 0;
|
|
4676
|
+
if (this.start > this.end)
|
|
4677
|
+
this.start = this.end;
|
|
4678
|
+
if (this.start === this.end) {
|
|
4679
|
+
this.start = 0;
|
|
4680
|
+
this.end = 0;
|
|
4681
|
+
} else if (this.start >= 4096 && this.start * 2 >= this.storage.length) {
|
|
4682
|
+
this.storage.copyWithin(0, this.start, this.end);
|
|
4683
|
+
this.end -= this.start;
|
|
4684
|
+
this.start = 0;
|
|
4685
|
+
}
|
|
4686
|
+
}
|
|
4687
|
+
reserve(additional) {
|
|
4688
|
+
const required = this.byteLength + additional;
|
|
4689
|
+
if (this.storage.length - this.end >= additional)
|
|
4690
|
+
return;
|
|
4691
|
+
if (this.storage.length >= required) {
|
|
4692
|
+
this.storage.copyWithin(0, this.start, this.end);
|
|
4693
|
+
this.end = this.byteLength;
|
|
4694
|
+
this.start = 0;
|
|
4695
|
+
return;
|
|
4696
|
+
}
|
|
4697
|
+
const storage = new Uint8Array(Math.max(required, Math.max(64, this.storage.length * 2)));
|
|
4698
|
+
storage.set(this.bytes);
|
|
4699
|
+
this.end = this.byteLength;
|
|
4700
|
+
this.start = 0;
|
|
4701
|
+
this.storage = storage;
|
|
4702
|
+
}
|
|
4762
4703
|
}
|
|
4763
4704
|
function getTransferChunkSize(windowSize) {
|
|
4764
4705
|
return windowSize > 0 && windowSize <= USER_PROG_CHUNK_SIZE ? windowSize : USER_PROG_CHUNK_SIZE;
|
|
4765
4706
|
}
|
|
4766
|
-
function convertScreenCapture(framebuffer) {
|
|
4767
|
-
const pixels = new Uint8Array(SCREEN_CAPTURE_WIDTH * SCREEN_CAPTURE_HEIGHT * SCREEN_CAPTURE_CHANNELS);
|
|
4768
|
-
for (let row = 0;row < SCREEN_CAPTURE_HEIGHT; row++) {
|
|
4769
|
-
for (let column = 0;column < SCREEN_CAPTURE_WIDTH; column++) {
|
|
4770
|
-
const source = (row * SCREEN_CAPTURE_MESSAGE_WIDTH + column) * SCREEN_CAPTURE_MESSAGE_CHANNELS;
|
|
4771
|
-
const target = (row * SCREEN_CAPTURE_WIDTH + column) * SCREEN_CAPTURE_CHANNELS;
|
|
4772
|
-
pixels[target] = framebuffer[source + 2] ?? 0;
|
|
4773
|
-
pixels[target + 1] = framebuffer[source + 1] ?? 0;
|
|
4774
|
-
pixels[target + 2] = framebuffer[source] ?? 0;
|
|
4775
|
-
}
|
|
4776
|
-
}
|
|
4777
|
-
return pixels;
|
|
4778
|
-
}
|
|
4779
4707
|
function wrapTransfer(conn, operation) {
|
|
4780
4708
|
return new ResultAsync(conn.withFileTransfer(async () => {
|
|
4781
4709
|
try {
|
|
@@ -4945,7 +4873,7 @@ async function flashFactoryImage(conn, options, pcb) {
|
|
|
4945
4873
|
autoRun: true,
|
|
4946
4874
|
linkedFile: undefined
|
|
4947
4875
|
};
|
|
4948
|
-
const upload = await conn.
|
|
4876
|
+
const upload = await conn.uploadFileToDeviceUnlocked(writeRequest, (c, t2) => {
|
|
4949
4877
|
pcb(`UPLOAD ${label}`, c, t2);
|
|
4950
4878
|
});
|
|
4951
4879
|
if (upload.isErr())
|
|
@@ -5072,29 +5000,35 @@ async function runUploadFirmware(state, publicUrl, usingVersion, progressCallbac
|
|
|
5072
5000
|
}
|
|
5073
5001
|
pcb("UNZIP VEXOS", 1, 1);
|
|
5074
5002
|
return state.withRefreshPaused(async () => {
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5003
|
+
try {
|
|
5004
|
+
return await conn.withFileTransfer(async () => {
|
|
5005
|
+
const boot = images.find((image) => image.name.endsWith("BOOT.bin"));
|
|
5006
|
+
if (boot === undefined) {
|
|
5007
|
+
return err(new VexFirmwareError("VEXos archive is missing BOOT.bin"));
|
|
5008
|
+
}
|
|
5009
|
+
const assertImage = images.find((image) => image.name.endsWith("assets.bin"));
|
|
5010
|
+
if (assertImage === undefined) {
|
|
5011
|
+
return err(new VexFirmwareError("VEXos archive is missing assets.bin"));
|
|
5012
|
+
}
|
|
5013
|
+
const bootFlash = await flashFactoryImage(conn, {
|
|
5014
|
+
image: boot,
|
|
5015
|
+
label: "BOOT",
|
|
5016
|
+
downloadTarget: 14
|
|
5017
|
+
}, pcb);
|
|
5018
|
+
if (bootFlash.isErr())
|
|
5019
|
+
return err(bootFlash.error);
|
|
5020
|
+
const assetsFlash = await flashFactoryImage(conn, {
|
|
5021
|
+
image: assertImage,
|
|
5022
|
+
label: "ASSETS",
|
|
5023
|
+
downloadTarget: 13
|
|
5024
|
+
}, pcb);
|
|
5025
|
+
if (assetsFlash.isErr())
|
|
5026
|
+
return err(assetsFlash.error);
|
|
5027
|
+
return ok(true);
|
|
5028
|
+
});
|
|
5029
|
+
} catch (e) {
|
|
5030
|
+
return err(toVexSerialError(e, "firmware"));
|
|
5031
|
+
}
|
|
5098
5032
|
});
|
|
5099
5033
|
}
|
|
5100
5034
|
function getValue(state, key) {
|
|
@@ -5634,6 +5568,11 @@ function unrefTimerIfPossible(timer) {
|
|
|
5634
5568
|
if (typeof unref === "function")
|
|
5635
5569
|
unref.call(timer);
|
|
5636
5570
|
}
|
|
5571
|
+
function describePort(port) {
|
|
5572
|
+
const info = port.getInfo();
|
|
5573
|
+
const identifier = info.path ?? info.id ?? info.serialNumber;
|
|
5574
|
+
return typeof identifier === "string" ? identifier : undefined;
|
|
5575
|
+
}
|
|
5637
5576
|
|
|
5638
5577
|
class V5SerialDevice extends VexSerialDevice {
|
|
5639
5578
|
autoReconnect = true;
|
|
@@ -5643,8 +5582,11 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
5643
5582
|
_refreshInterval;
|
|
5644
5583
|
state = new V5SerialDeviceState(this);
|
|
5645
5584
|
_disposed = false;
|
|
5585
|
+
_lifecycleGeneration = 0;
|
|
5586
|
+
_disconnectListener;
|
|
5646
5587
|
_refreshGeneration = 0;
|
|
5647
5588
|
_autoRefresh = false;
|
|
5589
|
+
_refreshIntervalMs = 200;
|
|
5648
5590
|
_isLastRefreshComplete = true;
|
|
5649
5591
|
_brain = new V5Brain(this.state);
|
|
5650
5592
|
_controllers = [
|
|
@@ -5653,8 +5595,15 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
5653
5595
|
];
|
|
5654
5596
|
_radio = new V5Radio(this.state);
|
|
5655
5597
|
_deviceFacades = [];
|
|
5656
|
-
|
|
5598
|
+
_emitSafely(eventName, data) {
|
|
5599
|
+
try {
|
|
5600
|
+
this.emit(eventName, data);
|
|
5601
|
+
} catch {}
|
|
5602
|
+
}
|
|
5603
|
+
constructor(defaultSerial, options = false) {
|
|
5657
5604
|
super(defaultSerial);
|
|
5605
|
+
const autoRefresh = typeof options === "boolean" ? options : options.autoRefresh ?? false;
|
|
5606
|
+
this.refreshIntervalMs = typeof options === "boolean" ? 200 : options.refreshIntervalMs ?? 200;
|
|
5658
5607
|
this.autoRefresh = autoRefresh;
|
|
5659
5608
|
}
|
|
5660
5609
|
get autoRefresh() {
|
|
@@ -5670,6 +5619,21 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
5670
5619
|
this._stopRefreshInterval();
|
|
5671
5620
|
}
|
|
5672
5621
|
}
|
|
5622
|
+
get refreshIntervalMs() {
|
|
5623
|
+
return this._refreshIntervalMs;
|
|
5624
|
+
}
|
|
5625
|
+
set refreshIntervalMs(value) {
|
|
5626
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
5627
|
+
throw new VexInvalidArgumentError("refreshIntervalMs must be a positive finite number");
|
|
5628
|
+
}
|
|
5629
|
+
if (this._refreshIntervalMs === value)
|
|
5630
|
+
return;
|
|
5631
|
+
this._refreshIntervalMs = value;
|
|
5632
|
+
if (this._refreshInterval !== undefined) {
|
|
5633
|
+
this._stopRefreshInterval();
|
|
5634
|
+
this._startRefreshInterval();
|
|
5635
|
+
}
|
|
5636
|
+
}
|
|
5673
5637
|
_startRefreshInterval() {
|
|
5674
5638
|
if (this._refreshInterval !== undefined || this._disposed)
|
|
5675
5639
|
return;
|
|
@@ -5687,16 +5651,16 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
5687
5651
|
try {
|
|
5688
5652
|
const r2 = await this.refresh();
|
|
5689
5653
|
if (r2.isErr())
|
|
5690
|
-
this.
|
|
5654
|
+
this._emitSafely("error", r2.error);
|
|
5691
5655
|
} catch (error) {
|
|
5692
|
-
this.
|
|
5656
|
+
this._emitSafely("error", error);
|
|
5693
5657
|
} finally {
|
|
5694
5658
|
this._isLastRefreshComplete = true;
|
|
5695
5659
|
}
|
|
5696
5660
|
})();
|
|
5697
5661
|
}
|
|
5698
5662
|
}
|
|
5699
|
-
},
|
|
5663
|
+
}, this._refreshIntervalMs);
|
|
5700
5664
|
unrefTimerIfPossible(this._refreshInterval);
|
|
5701
5665
|
}
|
|
5702
5666
|
_stopRefreshInterval() {
|
|
@@ -5759,58 +5723,125 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
5759
5723
|
})());
|
|
5760
5724
|
}
|
|
5761
5725
|
connect(conn) {
|
|
5762
|
-
|
|
5726
|
+
if (this._disposed) {
|
|
5727
|
+
return new ResultAsync(Promise.resolve(this._staleLifecycleResult()));
|
|
5728
|
+
}
|
|
5729
|
+
if (this.isConnected)
|
|
5730
|
+
return new ResultAsync(Promise.resolve(ok(undefined)));
|
|
5731
|
+
const generation = ++this._lifecycleGeneration;
|
|
5732
|
+
return new ResultAsync(this._connect(conn, generation));
|
|
5763
5733
|
}
|
|
5764
|
-
async _connect(conn) {
|
|
5734
|
+
async _connect(conn, generation = this._lifecycleGeneration) {
|
|
5735
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
5736
|
+
return this._staleLifecycleResult();
|
|
5737
|
+
}
|
|
5765
5738
|
if (this.isConnected)
|
|
5766
5739
|
return ok(undefined);
|
|
5767
5740
|
if (conn != null) {
|
|
5768
5741
|
if (!conn.isConnected) {
|
|
5769
5742
|
const opened = await conn.open();
|
|
5743
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
5744
|
+
await conn.close();
|
|
5745
|
+
return this._staleLifecycleResult();
|
|
5746
|
+
}
|
|
5770
5747
|
if (opened.isErr() || opened.value !== "opened") {
|
|
5771
5748
|
return err(new VexIoError("failed to open the supplied connection"));
|
|
5772
5749
|
}
|
|
5773
5750
|
}
|
|
5774
5751
|
const q = await conn.query1();
|
|
5752
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
5753
|
+
await conn.close();
|
|
5754
|
+
return this._staleLifecycleResult();
|
|
5755
|
+
}
|
|
5775
5756
|
if (q.isErr()) {
|
|
5776
5757
|
await conn.close();
|
|
5777
5758
|
return err(q.error);
|
|
5778
5759
|
}
|
|
5779
|
-
this.
|
|
5760
|
+
if (!this._commitConnection(conn, generation)) {
|
|
5761
|
+
await conn.close();
|
|
5762
|
+
return this._staleLifecycleResult();
|
|
5763
|
+
}
|
|
5780
5764
|
} else {
|
|
5781
5765
|
let tryIdx = 0;
|
|
5766
|
+
let canRequestPort = true;
|
|
5767
|
+
const attemptedPorts = new Set;
|
|
5768
|
+
const attemptedPortNames = [];
|
|
5782
5769
|
while (true) {
|
|
5783
|
-
|
|
5784
|
-
|
|
5770
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
5771
|
+
return this._staleLifecycleResult();
|
|
5772
|
+
}
|
|
5773
|
+
const c = this.createConnection();
|
|
5774
|
+
let result = await c.open(tryIdx++, false);
|
|
5775
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
5776
|
+
await c.close();
|
|
5777
|
+
return this._staleLifecycleResult();
|
|
5778
|
+
}
|
|
5779
|
+
if (result.isOk() && result.value === "no-port" && canRequestPort) {
|
|
5780
|
+
canRequestPort = false;
|
|
5781
|
+
result = await c.open(tryIdx, true);
|
|
5782
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
5783
|
+
await c.close();
|
|
5784
|
+
return this._staleLifecycleResult();
|
|
5785
|
+
}
|
|
5786
|
+
}
|
|
5785
5787
|
if (result.isErr()) {
|
|
5786
5788
|
await c.close();
|
|
5787
5789
|
return err(result.error);
|
|
5788
5790
|
}
|
|
5789
5791
|
if (result.value === "no-port") {
|
|
5790
|
-
|
|
5792
|
+
const attempted = attemptedPortNames.length ? `; attempted ${attemptedPortNames.join(", ")}` : "";
|
|
5793
|
+
return err(new VexNotConnectedError(`no responsive V5 device was found${attempted}`));
|
|
5791
5794
|
}
|
|
5792
5795
|
if (result.value === "busy") {
|
|
5793
5796
|
await c.close();
|
|
5794
|
-
|
|
5797
|
+
return err(new VexNotConnectedError("the selected V5 serial port is busy"));
|
|
5798
|
+
}
|
|
5799
|
+
const port = c.port;
|
|
5800
|
+
if (port !== undefined && attemptedPorts.has(port)) {
|
|
5801
|
+
await c.close();
|
|
5802
|
+
const portName = describePort(port);
|
|
5803
|
+
return err(new VexNotConnectedError(portName === undefined ? "the selected serial port did not respond as a V5 device" : `serial port ${portName} did not respond as a V5 device`));
|
|
5804
|
+
}
|
|
5805
|
+
if (port !== undefined) {
|
|
5806
|
+
attemptedPorts.add(port);
|
|
5807
|
+
const portName = describePort(port);
|
|
5808
|
+
if (portName !== undefined)
|
|
5809
|
+
attemptedPortNames.push(portName);
|
|
5795
5810
|
}
|
|
5796
5811
|
const q = await c.query1();
|
|
5812
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
5813
|
+
await c.close();
|
|
5814
|
+
return this._staleLifecycleResult();
|
|
5815
|
+
}
|
|
5797
5816
|
if (q.isErr()) {
|
|
5798
5817
|
await c.close();
|
|
5799
5818
|
continue;
|
|
5800
5819
|
}
|
|
5801
|
-
this.
|
|
5820
|
+
if (!this._commitConnection(c, generation)) {
|
|
5821
|
+
await c.close();
|
|
5822
|
+
return this._staleLifecycleResult();
|
|
5823
|
+
}
|
|
5802
5824
|
break;
|
|
5803
5825
|
}
|
|
5804
5826
|
}
|
|
5805
|
-
|
|
5827
|
+
const connection = this.connection;
|
|
5828
|
+
if (!this._isLifecycleCurrent(generation) || connection == null) {
|
|
5829
|
+
return this._staleLifecycleResult();
|
|
5830
|
+
}
|
|
5831
|
+
if (!connection.isConnected)
|
|
5806
5832
|
return err(new VexNotConnectedError);
|
|
5807
|
-
await this.doAfterConnect();
|
|
5833
|
+
const initialized = await this.doAfterConnect(connection, generation);
|
|
5834
|
+
if (initialized.isErr())
|
|
5835
|
+
return initialized;
|
|
5808
5836
|
return ok(undefined);
|
|
5809
5837
|
}
|
|
5810
5838
|
async disconnect() {
|
|
5839
|
+
this._lifecycleGeneration++;
|
|
5840
|
+
this._refreshGeneration++;
|
|
5811
5841
|
this._isDisconnecting = true;
|
|
5812
5842
|
const connection = this.connection;
|
|
5813
5843
|
this.connection = undefined;
|
|
5844
|
+
this._detachDisconnectListener();
|
|
5814
5845
|
try {
|
|
5815
5846
|
await connection?.close();
|
|
5816
5847
|
} finally {
|
|
@@ -5824,9 +5855,21 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
5824
5855
|
await this.disconnect();
|
|
5825
5856
|
}
|
|
5826
5857
|
reconnect(timeout = 0) {
|
|
5827
|
-
|
|
5858
|
+
if (this._disposed) {
|
|
5859
|
+
return new ResultAsync(Promise.resolve(this._staleLifecycleResult()));
|
|
5860
|
+
}
|
|
5861
|
+
if (timeout < 0) {
|
|
5862
|
+
return new ResultAsync(Promise.resolve(err(new VexInvalidArgumentError("timeout must be non-negative"))));
|
|
5863
|
+
}
|
|
5864
|
+
if (this.isConnected)
|
|
5865
|
+
return new ResultAsync(Promise.resolve(ok(undefined)));
|
|
5866
|
+
const generation = this._isReconnecting ? this._lifecycleGeneration : ++this._lifecycleGeneration;
|
|
5867
|
+
return new ResultAsync(this._reconnect(timeout, generation));
|
|
5828
5868
|
}
|
|
5829
|
-
async _reconnect(timeout) {
|
|
5869
|
+
async _reconnect(timeout, generation = this._lifecycleGeneration) {
|
|
5870
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
5871
|
+
return this._staleLifecycleResult();
|
|
5872
|
+
}
|
|
5830
5873
|
if (this.isConnected)
|
|
5831
5874
|
return ok(undefined);
|
|
5832
5875
|
if (timeout < 0) {
|
|
@@ -5842,6 +5885,9 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
5842
5885
|
return err(new VexNotConnectedError);
|
|
5843
5886
|
}
|
|
5844
5887
|
}
|
|
5888
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
5889
|
+
return this._staleLifecycleResult();
|
|
5890
|
+
}
|
|
5845
5891
|
if (this.isConnected)
|
|
5846
5892
|
return ok(undefined);
|
|
5847
5893
|
}
|
|
@@ -5850,8 +5896,15 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
5850
5896
|
while (timeout === 0 || Date.now() < endTime) {
|
|
5851
5897
|
let tryIdx = 0;
|
|
5852
5898
|
while (true) {
|
|
5853
|
-
|
|
5899
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
5900
|
+
return this._staleLifecycleResult();
|
|
5901
|
+
}
|
|
5902
|
+
const c = this.createConnection();
|
|
5854
5903
|
const result = await c.open(tryIdx++, false);
|
|
5904
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
5905
|
+
await c.close();
|
|
5906
|
+
return this._staleLifecycleResult();
|
|
5907
|
+
}
|
|
5855
5908
|
if (result.isErr()) {
|
|
5856
5909
|
await c.close();
|
|
5857
5910
|
return err(result.error);
|
|
@@ -5863,6 +5916,10 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
5863
5916
|
continue;
|
|
5864
5917
|
}
|
|
5865
5918
|
const status = await c.getSystemStatus(200);
|
|
5919
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
5920
|
+
await c.close();
|
|
5921
|
+
return this._staleLifecycleResult();
|
|
5922
|
+
}
|
|
5866
5923
|
if (status.isErr()) {
|
|
5867
5924
|
await c.close();
|
|
5868
5925
|
continue;
|
|
@@ -5871,23 +5928,38 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
5871
5928
|
await c.close();
|
|
5872
5929
|
continue;
|
|
5873
5930
|
}
|
|
5874
|
-
this.
|
|
5931
|
+
if (!this._commitConnection(c, generation)) {
|
|
5932
|
+
await c.close();
|
|
5933
|
+
return this._staleLifecycleResult();
|
|
5934
|
+
}
|
|
5875
5935
|
break;
|
|
5876
5936
|
}
|
|
5877
5937
|
if (this.isConnected)
|
|
5878
5938
|
break;
|
|
5879
5939
|
const getPortCount = async () => (await this.defaultSerial.getPorts()).length;
|
|
5880
5940
|
const portsCount = await getPortCount();
|
|
5941
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
5942
|
+
return this._staleLifecycleResult();
|
|
5943
|
+
}
|
|
5881
5944
|
await sleepUntilAsync(async () => await getPortCount() !== portsCount, 1000);
|
|
5945
|
+
if (!this._isLifecycleCurrent(generation)) {
|
|
5946
|
+
return this._staleLifecycleResult();
|
|
5947
|
+
}
|
|
5882
5948
|
}
|
|
5883
5949
|
} catch (e) {
|
|
5884
5950
|
return err(toVexSerialError(e));
|
|
5885
5951
|
} finally {
|
|
5886
5952
|
this._isReconnecting = false;
|
|
5887
5953
|
}
|
|
5888
|
-
|
|
5954
|
+
const connection = this.connection;
|
|
5955
|
+
if (!this._isLifecycleCurrent(generation) || connection == null) {
|
|
5956
|
+
return this._staleLifecycleResult();
|
|
5957
|
+
}
|
|
5958
|
+
if (!connection.isConnected)
|
|
5889
5959
|
return err(new VexNotConnectedError);
|
|
5890
|
-
await this.doAfterConnect();
|
|
5960
|
+
const initialized = await this.doAfterConnect(connection, generation);
|
|
5961
|
+
if (initialized.isErr())
|
|
5962
|
+
return initialized;
|
|
5891
5963
|
return ok(undefined);
|
|
5892
5964
|
}
|
|
5893
5965
|
async waitForReconnectToFinish() {
|
|
@@ -5897,18 +5969,69 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
5897
5969
|
return;
|
|
5898
5970
|
}
|
|
5899
5971
|
}
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5972
|
+
createConnection() {
|
|
5973
|
+
return new V5SerialConnection(this.defaultSerial);
|
|
5974
|
+
}
|
|
5975
|
+
_isLifecycleCurrent(generation) {
|
|
5976
|
+
return generation === this._lifecycleGeneration && !this._disposed;
|
|
5977
|
+
}
|
|
5978
|
+
_staleLifecycleResult() {
|
|
5979
|
+
return err(new VexNotConnectedError("connection attempt was superseded"));
|
|
5980
|
+
}
|
|
5981
|
+
_commitConnection(connection, generation) {
|
|
5982
|
+
if (!this._isLifecycleCurrent(generation))
|
|
5983
|
+
return false;
|
|
5984
|
+
this._detachDisconnectListener();
|
|
5985
|
+
this.connection = connection;
|
|
5986
|
+
return true;
|
|
5987
|
+
}
|
|
5988
|
+
_detachDisconnectListener() {
|
|
5989
|
+
const subscription = this._disconnectListener;
|
|
5990
|
+
this._disconnectListener = undefined;
|
|
5991
|
+
subscription?.connection.remove("disconnected", subscription.listener);
|
|
5992
|
+
}
|
|
5993
|
+
async doAfterConnect(connection, generation) {
|
|
5994
|
+
if (!this._isLifecycleCurrent(generation) || this.connection !== connection) {
|
|
5995
|
+
return this._staleLifecycleResult();
|
|
5996
|
+
}
|
|
5997
|
+
const listener = () => {
|
|
5998
|
+
if (this._isDisconnecting || !this._isLifecycleCurrent(generation) || this.connection !== connection) {
|
|
5905
5999
|
return;
|
|
5906
|
-
this.emit("disconnected", undefined);
|
|
5907
|
-
if (this.autoReconnect) {
|
|
5908
|
-
this.reconnect().mapErr((e) => this.emit("error", e));
|
|
5909
6000
|
}
|
|
5910
|
-
|
|
5911
|
-
|
|
6001
|
+
this._lifecycleGeneration++;
|
|
6002
|
+
this._refreshGeneration++;
|
|
6003
|
+
this.connection = undefined;
|
|
6004
|
+
this._detachDisconnectListener();
|
|
6005
|
+
this._emitSafely("disconnected", undefined);
|
|
6006
|
+
if (this.autoReconnect && !this._disposed) {
|
|
6007
|
+
this.reconnect().mapErr((error) => this._emitSafely("error", error));
|
|
6008
|
+
}
|
|
6009
|
+
};
|
|
6010
|
+
connection.on("disconnected", listener);
|
|
6011
|
+
this._disconnectListener = { connection, listener };
|
|
6012
|
+
const refreshed = await this.refresh();
|
|
6013
|
+
if (!this._isLifecycleCurrent(generation) || this.connection !== connection || !connection.isConnected) {
|
|
6014
|
+
return this._staleLifecycleResult();
|
|
6015
|
+
}
|
|
6016
|
+
if (refreshed.isErr()) {
|
|
6017
|
+
await this._discardConnection(connection, generation);
|
|
6018
|
+
return err(refreshed.error);
|
|
6019
|
+
}
|
|
6020
|
+
if (!refreshed.value) {
|
|
6021
|
+
await this._discardConnection(connection, generation);
|
|
6022
|
+
return err(new VexNotConnectedError("initial device refresh did not produce a current snapshot"));
|
|
6023
|
+
}
|
|
6024
|
+
return ok(undefined);
|
|
6025
|
+
}
|
|
6026
|
+
async _discardConnection(connection, generation) {
|
|
6027
|
+
if (!this._isLifecycleCurrent(generation) || this.connection !== connection) {
|
|
6028
|
+
return;
|
|
6029
|
+
}
|
|
6030
|
+
this._lifecycleGeneration++;
|
|
6031
|
+
this._refreshGeneration++;
|
|
6032
|
+
this.connection = undefined;
|
|
6033
|
+
this._detachDisconnectListener();
|
|
6034
|
+
await connection.close();
|
|
5912
6035
|
}
|
|
5913
6036
|
refresh() {
|
|
5914
6037
|
return new ResultAsync(this._refresh());
|
|
@@ -5922,31 +6045,15 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
5922
6045
|
this._applySnapshotIfCurrent(generation, { isAvailable: false });
|
|
5923
6046
|
return ok(false);
|
|
5924
6047
|
}
|
|
5925
|
-
const ssPacket = await
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
}
|
|
5932
|
-
const sfPacket = await conn.getSystemFlags();
|
|
5933
|
-
if (generation !== this._refreshGeneration || this._disposed)
|
|
5934
|
-
return ok(false);
|
|
5935
|
-
if (sfPacket.isErr()) {
|
|
5936
|
-
this._applySnapshotIfCurrent(generation, { isAvailable: false });
|
|
5937
|
-
return ok(false);
|
|
5938
|
-
}
|
|
5939
|
-
const rdPacket = await conn.getRadioStatus();
|
|
5940
|
-
if (generation !== this._refreshGeneration || this._disposed)
|
|
5941
|
-
return ok(false);
|
|
5942
|
-
if (rdPacket.isErr()) {
|
|
5943
|
-
this._applySnapshotIfCurrent(generation, { isAvailable: false });
|
|
5944
|
-
return ok(false);
|
|
5945
|
-
}
|
|
5946
|
-
const dsPacket = await conn.getDeviceStatus();
|
|
6048
|
+
const [ssPacket, sfPacket, rdPacket, dsPacket] = await Promise.all([
|
|
6049
|
+
conn.getSystemStatus(),
|
|
6050
|
+
conn.getSystemFlags(),
|
|
6051
|
+
conn.getRadioStatus(),
|
|
6052
|
+
conn.getDeviceStatus()
|
|
6053
|
+
]);
|
|
5947
6054
|
if (generation !== this._refreshGeneration || this._disposed)
|
|
5948
6055
|
return ok(false);
|
|
5949
|
-
if (dsPacket.isErr()) {
|
|
6056
|
+
if (ssPacket.isErr() || sfPacket.isErr() || rdPacket.isErr() || dsPacket.isErr()) {
|
|
5950
6057
|
this._applySnapshotIfCurrent(generation, { isAvailable: false });
|
|
5951
6058
|
return ok(false);
|
|
5952
6059
|
}
|
|
@@ -6003,7 +6110,7 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
6003
6110
|
{
|
|
6004
6111
|
battery: controller1Battery,
|
|
6005
6112
|
isAvailable: controller1Available,
|
|
6006
|
-
isCharging:
|
|
6113
|
+
isCharging: undefined
|
|
6007
6114
|
}
|
|
6008
6115
|
],
|
|
6009
6116
|
radio: {
|
|
@@ -6030,7 +6137,26 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
6030
6137
|
}
|
|
6031
6138
|
this.state.matchMode = snapshot.matchMode;
|
|
6032
6139
|
this.state.isFieldControllerConnected = snapshot.isFieldControllerConnected;
|
|
6033
|
-
|
|
6140
|
+
const brain = this.state.brain;
|
|
6141
|
+
brain.activeProgram = snapshot.brain.activeProgram;
|
|
6142
|
+
brain.battery.batteryPercent = snapshot.brain.battery.batteryPercent;
|
|
6143
|
+
brain.battery.isCharging = snapshot.brain.battery.isCharging;
|
|
6144
|
+
brain.button.isPressed = snapshot.brain.button.isPressed;
|
|
6145
|
+
brain.button.isDoublePressed = snapshot.brain.button.isDoublePressed;
|
|
6146
|
+
if (brain.cpu0Version.compare(snapshot.brain.cpu0Version) !== 0) {
|
|
6147
|
+
brain.cpu0Version = snapshot.brain.cpu0Version;
|
|
6148
|
+
}
|
|
6149
|
+
if (brain.cpu1Version.compare(snapshot.brain.cpu1Version) !== 0) {
|
|
6150
|
+
brain.cpu1Version = snapshot.brain.cpu1Version;
|
|
6151
|
+
}
|
|
6152
|
+
brain.isAvailable = snapshot.brain.isAvailable;
|
|
6153
|
+
brain.settings.isScreenReversed = snapshot.brain.settings.isScreenReversed;
|
|
6154
|
+
brain.settings.isWhiteTheme = snapshot.brain.settings.isWhiteTheme;
|
|
6155
|
+
brain.settings.usingLanguage = snapshot.brain.settings.usingLanguage;
|
|
6156
|
+
if (brain.systemVersion.compare(snapshot.brain.systemVersion) !== 0) {
|
|
6157
|
+
brain.systemVersion = snapshot.brain.systemVersion;
|
|
6158
|
+
}
|
|
6159
|
+
brain.uniqueId = snapshot.brain.uniqueId;
|
|
6034
6160
|
Object.assign(this.state.controllers[0], snapshot.controllers[0]);
|
|
6035
6161
|
Object.assign(this.state.controllers[1], snapshot.controllers[1]);
|
|
6036
6162
|
Object.assign(this.state.radio, snapshot.radio);
|
|
@@ -6039,10 +6165,18 @@ class V5SerialDevice extends VexSerialDevice {
|
|
|
6039
6165
|
if (device != null)
|
|
6040
6166
|
next[device.port] = device;
|
|
6041
6167
|
}
|
|
6042
|
-
this.state.devices
|
|
6168
|
+
if (!sameSmartDeviceSlots(this.state.devices, next)) {
|
|
6169
|
+
this.state.devices = next;
|
|
6170
|
+
}
|
|
6043
6171
|
return true;
|
|
6044
6172
|
}
|
|
6045
6173
|
}
|
|
6174
|
+
function sameSmartDeviceSlots(left, right) {
|
|
6175
|
+
return left.length === right.length && left.every((device, index) => {
|
|
6176
|
+
const next = right[index];
|
|
6177
|
+
return device === next || device !== undefined && next !== undefined && device.port === next.port && device.type === next.type && device.status === next.status && device.betaversion === next.betaversion && device.version === next.version && device.bootversion === next.bootversion;
|
|
6178
|
+
});
|
|
6179
|
+
}
|
|
6046
6180
|
|
|
6047
6181
|
class BaseIniBuilder {
|
|
6048
6182
|
str = "";
|
|
@@ -6051,7 +6185,7 @@ class BaseIniBuilder {
|
|
|
6051
6185
|
`;
|
|
6052
6186
|
}
|
|
6053
6187
|
addComment(comment) {
|
|
6054
|
-
this.addLine("; " + comment);
|
|
6188
|
+
this.addLine(comment.length === 0 ? ";" : "; " + comment);
|
|
6055
6189
|
return this;
|
|
6056
6190
|
}
|
|
6057
6191
|
getContent() {
|
|
@@ -6069,18 +6203,23 @@ class IniSectionBuilder extends BaseIniBuilder {
|
|
|
6069
6203
|
this.object = object;
|
|
6070
6204
|
this.keyTransform = keyTransform;
|
|
6071
6205
|
}
|
|
6072
|
-
addSingleObjProperty(key, maxValueLength) {
|
|
6073
|
-
const
|
|
6074
|
-
if (
|
|
6206
|
+
addSingleObjProperty(key, maxValueLength, omitIfEmpty = false) {
|
|
6207
|
+
const rawValue = this.object[key];
|
|
6208
|
+
if (rawValue == null)
|
|
6209
|
+
return;
|
|
6210
|
+
const value = rawValue.toString();
|
|
6211
|
+
if (omitIfEmpty && value.length === 0)
|
|
6075
6212
|
return;
|
|
6213
|
+
if (/["\u0000-\u001f\u007f]/.test(value)) {
|
|
6214
|
+
throw new Error(`INI value for ${this.name}.${String(key)} contains an unsupported character`);
|
|
6215
|
+
}
|
|
6076
6216
|
const formattedKey = this.keyTransform(key).padEnd(12).slice(0, 12);
|
|
6077
|
-
const
|
|
6078
|
-
|
|
6079
|
-
this.addLine(`${formattedKey} = "${escapedVal}"`);
|
|
6217
|
+
const trimmedValue = value.slice(0, maxValueLength);
|
|
6218
|
+
this.addLine(`${formattedKey} = "${trimmedValue}"`);
|
|
6080
6219
|
}
|
|
6081
|
-
addObjProperty(key, maxValueLength) {
|
|
6220
|
+
addObjProperty(key, maxValueLength, omitIfEmpty = false) {
|
|
6082
6221
|
for (const k of Array.isArray(key) ? key : [key]) {
|
|
6083
|
-
this.addSingleObjProperty(k, maxValueLength);
|
|
6222
|
+
this.addSingleObjProperty(k, maxValueLength, omitIfEmpty);
|
|
6084
6223
|
}
|
|
6085
6224
|
return this;
|
|
6086
6225
|
}
|
|
@@ -6098,6 +6237,11 @@ class IniFileBuilder extends BaseIniBuilder {
|
|
|
6098
6237
|
this.str += section.getContent();
|
|
6099
6238
|
return this;
|
|
6100
6239
|
}
|
|
6240
|
+
addOptionalSection(section) {
|
|
6241
|
+
if (section.getContent().length === 0)
|
|
6242
|
+
return this;
|
|
6243
|
+
return this.addComment("").addSection(section);
|
|
6244
|
+
}
|
|
6101
6245
|
}
|
|
6102
6246
|
|
|
6103
6247
|
class ProgramIniConfig {
|
|
@@ -6128,7 +6272,7 @@ class ProgramIniConfig {
|
|
|
6128
6272
|
if (this.program.date.length === 0) {
|
|
6129
6273
|
this.setProgramDate(new Date);
|
|
6130
6274
|
}
|
|
6131
|
-
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("
|
|
6275
|
+
return new IniFileBuilder().addComment("").addComment("VEX program ini file").addComment("Generated by Vex V5 Serial Protocol Library").addComment("").addSection(new IniSectionBuilder("project", this.project).addObjProperty("version").addObjProperty("ide", 16).addObjProperty("file")).addComment("").addSection(new IniSectionBuilder("program", this.program).addObjProperty("version").addObjProperty("name", 32).addObjProperty("slot").addObjProperty("icon", 16).addObjProperty("iconalt", 16, true).addObjProperty("description", 256).addObjProperty("date").addObjProperty("timezone")).addComment("").addSection(new IniSectionBuilder("config", this.config, (k) => "port_" + this.dec2(k)).addAllObjProps()).addOptionalSection(new IniSectionBuilder("controller_1", this.controller1).addAllObjProps()).addOptionalSection(new IniSectionBuilder("controller_2", this.controller2).addAllObjProps()).getContent();
|
|
6132
6276
|
}
|
|
6133
6277
|
dec2(value) {
|
|
6134
6278
|
return (value % 100).toString(10).padStart(2, "0").toUpperCase();
|
|
@@ -6138,6 +6282,60 @@ class ProgramIniConfig {
|
|
|
6138
6282
|
// src/utils/detect.ts
|
|
6139
6283
|
import { join } from "path";
|
|
6140
6284
|
|
|
6285
|
+
// src/errors.ts
|
|
6286
|
+
var CLI_EXIT_CODE = {
|
|
6287
|
+
FAILURE: 1,
|
|
6288
|
+
USAGE: 2,
|
|
6289
|
+
NO_DEVICE: 3,
|
|
6290
|
+
DEVICE: 4,
|
|
6291
|
+
IO: 5
|
|
6292
|
+
};
|
|
6293
|
+
|
|
6294
|
+
class CliError extends Error {
|
|
6295
|
+
exitCode;
|
|
6296
|
+
constructor(message, exitCode = CLI_EXIT_CODE.FAILURE, options) {
|
|
6297
|
+
super(message, options);
|
|
6298
|
+
this.exitCode = exitCode;
|
|
6299
|
+
this.name = "CliError";
|
|
6300
|
+
}
|
|
6301
|
+
}
|
|
6302
|
+
function exitCodeForSerialError(kind) {
|
|
6303
|
+
switch (kind) {
|
|
6304
|
+
case "invalid-argument":
|
|
6305
|
+
return CLI_EXIT_CODE.USAGE;
|
|
6306
|
+
case "not-connected":
|
|
6307
|
+
return CLI_EXIT_CODE.NO_DEVICE;
|
|
6308
|
+
case "protocol":
|
|
6309
|
+
case "transfer":
|
|
6310
|
+
case "firmware":
|
|
6311
|
+
return CLI_EXIT_CODE.DEVICE;
|
|
6312
|
+
case "download":
|
|
6313
|
+
case "io":
|
|
6314
|
+
return CLI_EXIT_CODE.IO;
|
|
6315
|
+
}
|
|
6316
|
+
}
|
|
6317
|
+
function isVerbose(argv = process.argv, environment = process.env) {
|
|
6318
|
+
return argv.includes("--verbose") || environment.V5X_DEBUG === "1";
|
|
6319
|
+
}
|
|
6320
|
+
function isJsonOutput(argv = process.argv) {
|
|
6321
|
+
return argv.includes("--json");
|
|
6322
|
+
}
|
|
6323
|
+
function formatCliJsonError(error) {
|
|
6324
|
+
return JSON.stringify({
|
|
6325
|
+
error: {
|
|
6326
|
+
message: error instanceof Error ? error.message : String(error),
|
|
6327
|
+
exitCode: cliExitCode(error)
|
|
6328
|
+
}
|
|
6329
|
+
});
|
|
6330
|
+
}
|
|
6331
|
+
function formatCliError(error, verbose) {
|
|
6332
|
+
const detail = verbose && error instanceof Error && error.stack ? error.stack : error instanceof Error ? error.message : String(error);
|
|
6333
|
+
return `${source_default.red("error:")} ${detail}`;
|
|
6334
|
+
}
|
|
6335
|
+
function cliExitCode(error) {
|
|
6336
|
+
return error instanceof CliError ? error.exitCode : CLI_EXIT_CODE.FAILURE;
|
|
6337
|
+
}
|
|
6338
|
+
|
|
6141
6339
|
// src/utils/guards.ts
|
|
6142
6340
|
function isRecord(value) {
|
|
6143
6341
|
return typeof value === "object" && value !== null;
|
|
@@ -6145,6 +6343,12 @@ function isRecord(value) {
|
|
|
6145
6343
|
function hasErrorCode(error, code) {
|
|
6146
6344
|
return isRecord(error) && error.code === code;
|
|
6147
6345
|
}
|
|
6346
|
+
function requireOptionValue(value, option) {
|
|
6347
|
+
if (typeof value === "boolean") {
|
|
6348
|
+
throw new CliError(`${option} requires a value`, CLI_EXIT_CODE.USAGE);
|
|
6349
|
+
}
|
|
6350
|
+
return value;
|
|
6351
|
+
}
|
|
6148
6352
|
|
|
6149
6353
|
// src/utils/detect.ts
|
|
6150
6354
|
function hasVexideDependency(manifest) {
|
|
@@ -6206,7 +6410,40 @@ ${stderr}` : message, stderr);
|
|
|
6206
6410
|
}
|
|
6207
6411
|
}
|
|
6208
6412
|
|
|
6413
|
+
// src/utils/concurrency.ts
|
|
6414
|
+
async function mapWithConcurrency(values, concurrency, mapper) {
|
|
6415
|
+
if (!Number.isInteger(concurrency) || concurrency < 1) {
|
|
6416
|
+
throw new Error("concurrency must be a positive integer");
|
|
6417
|
+
}
|
|
6418
|
+
if (values.length === 0)
|
|
6419
|
+
return [];
|
|
6420
|
+
const results = new Array(values.length);
|
|
6421
|
+
let nextIndex = 0;
|
|
6422
|
+
let failed = false;
|
|
6423
|
+
async function worker() {
|
|
6424
|
+
while (!failed) {
|
|
6425
|
+
const index = nextIndex++;
|
|
6426
|
+
if (index >= values.length)
|
|
6427
|
+
return;
|
|
6428
|
+
const value = values[index];
|
|
6429
|
+
try {
|
|
6430
|
+
results[index] = await mapper(value, index);
|
|
6431
|
+
} catch (error) {
|
|
6432
|
+
failed = true;
|
|
6433
|
+
throw error;
|
|
6434
|
+
}
|
|
6435
|
+
}
|
|
6436
|
+
}
|
|
6437
|
+
const workers2 = Array.from({ length: Math.min(concurrency, values.length) }, () => worker());
|
|
6438
|
+
const settled = await Promise.allSettled(workers2);
|
|
6439
|
+
const rejection = settled.find((result) => result.status === "rejected");
|
|
6440
|
+
if (rejection !== undefined)
|
|
6441
|
+
throw rejection.reason;
|
|
6442
|
+
return results;
|
|
6443
|
+
}
|
|
6444
|
+
|
|
6209
6445
|
// src/utils/project.ts
|
|
6446
|
+
var ARTIFACT_DISCOVERY_CONCURRENCY = 8;
|
|
6210
6447
|
function stringAt(value, keys) {
|
|
6211
6448
|
let current = value;
|
|
6212
6449
|
for (const key of keys) {
|
|
@@ -6320,21 +6557,44 @@ async function existingFile(path) {
|
|
|
6320
6557
|
return;
|
|
6321
6558
|
}))?.isFile() ? path : undefined;
|
|
6322
6559
|
}
|
|
6323
|
-
|
|
6324
|
-
|
|
6560
|
+
var binaryDiscoveryOperations = {
|
|
6561
|
+
stat,
|
|
6562
|
+
scan(root, name) {
|
|
6563
|
+
return new Bun.Glob(`**/${name}.bin`).scan({ cwd: root, onlyFiles: true });
|
|
6564
|
+
}
|
|
6565
|
+
};
|
|
6566
|
+
function newestCandidate(candidates) {
|
|
6567
|
+
return candidates.filter((candidate) => candidate !== undefined).sort((left, right) => right.modified - left.modified || (left.path < right.path ? -1 : left.path > right.path ? 1 : 0))[0]?.path;
|
|
6568
|
+
}
|
|
6569
|
+
async function newestNamedBinary(root, name, operations = binaryDiscoveryOperations) {
|
|
6570
|
+
if (!(await operations.stat(root).catch(() => {
|
|
6325
6571
|
return;
|
|
6326
6572
|
}))?.isDirectory())
|
|
6327
6573
|
return;
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
-
|
|
6574
|
+
const conventionalPaths = [
|
|
6575
|
+
resolve(root, "armv7a-vex-v5", "release", `${name}.bin`),
|
|
6576
|
+
resolve(root, "release", `${name}.bin`)
|
|
6577
|
+
];
|
|
6578
|
+
const conventional = await mapWithConcurrency(conventionalPaths, ARTIFACT_DISCOVERY_CONCURRENCY, async (path) => {
|
|
6579
|
+
const info = await operations.stat(path).catch(() => {
|
|
6580
|
+
return;
|
|
6581
|
+
});
|
|
6582
|
+
return info?.isFile() ? { path, modified: info.mtimeMs } : undefined;
|
|
6583
|
+
});
|
|
6584
|
+
const paths = [];
|
|
6585
|
+
const conventionalPathSet = new Set(conventionalPaths);
|
|
6586
|
+
for await (const relativePath of operations.scan(root, name)) {
|
|
6331
6587
|
const path = resolve(root, relativePath);
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
newest = { path, modified: mtimeMs };
|
|
6335
|
-
}
|
|
6588
|
+
if (!conventionalPathSet.has(path))
|
|
6589
|
+
paths.push(path);
|
|
6336
6590
|
}
|
|
6337
|
-
|
|
6591
|
+
const candidates = await mapWithConcurrency(paths, ARTIFACT_DISCOVERY_CONCURRENCY, async (path) => {
|
|
6592
|
+
const info = await operations.stat(path).catch(() => {
|
|
6593
|
+
return;
|
|
6594
|
+
});
|
|
6595
|
+
return info?.isFile() ? { path, modified: info.mtimeMs } : undefined;
|
|
6596
|
+
});
|
|
6597
|
+
return newestCandidate([...conventional, ...candidates]);
|
|
6338
6598
|
}
|
|
6339
6599
|
async function findProgramArtifact(project, explicitPath) {
|
|
6340
6600
|
if (explicitPath !== undefined) {
|
|
@@ -6376,9 +6636,17 @@ async function validateProgramArtifact(path, role) {
|
|
|
6376
6636
|
return { path, size: info.size };
|
|
6377
6637
|
}
|
|
6378
6638
|
async function validateProgramArtifacts(artifacts) {
|
|
6639
|
+
const [hot, cold] = await Promise.allSettled([
|
|
6640
|
+
validateProgramArtifact(artifacts.hot, "hot"),
|
|
6641
|
+
artifacts.cold === undefined ? Promise.resolve(undefined) : validateProgramArtifact(artifacts.cold, "cold")
|
|
6642
|
+
]);
|
|
6643
|
+
if (hot.status === "rejected")
|
|
6644
|
+
throw hot.reason;
|
|
6645
|
+
if (cold.status === "rejected")
|
|
6646
|
+
throw cold.reason;
|
|
6379
6647
|
return {
|
|
6380
|
-
hot:
|
|
6381
|
-
cold:
|
|
6648
|
+
hot: hot.value,
|
|
6649
|
+
cold: cold.value
|
|
6382
6650
|
};
|
|
6383
6651
|
}
|
|
6384
6652
|
async function findProgramArtifacts(project, explicitPath) {
|
|
@@ -7768,8 +8036,9 @@ function formatSerialFailure(message, error) {
|
|
|
7768
8036
|
return detail === "" ? `${message}: ${error.kind}` : `${message}: ${error.kind}: ${detail}`;
|
|
7769
8037
|
}
|
|
7770
8038
|
function unwrapSerial(result, message) {
|
|
7771
|
-
if (result.isErr())
|
|
7772
|
-
throw new
|
|
8039
|
+
if (result.isErr()) {
|
|
8040
|
+
throw new CliError(formatSerialFailure(message, result.error), exitCodeForSerialError(result.error.kind), { cause: result.error });
|
|
8041
|
+
}
|
|
7773
8042
|
return result.value;
|
|
7774
8043
|
}
|
|
7775
8044
|
|
|
@@ -7845,6 +8114,13 @@ async function listPorts() {
|
|
|
7845
8114
|
return (await Promise.resolve().then(() => (init_src(), exports_src))).list();
|
|
7846
8115
|
}
|
|
7847
8116
|
var readTextFile = (path) => Bun.file(path).text();
|
|
8117
|
+
var LINUX_DISCOVERY_CONCURRENCY = 8;
|
|
8118
|
+
var linuxDiscoveryOperations = {
|
|
8119
|
+
readdir: readdir2,
|
|
8120
|
+
realpath,
|
|
8121
|
+
readlink: readlink2,
|
|
8122
|
+
readUsbAttributes: readLinuxUsbDeviceAttributes
|
|
8123
|
+
};
|
|
7848
8124
|
async function readLinuxUsbDeviceAttributes(device, readText = readTextFile) {
|
|
7849
8125
|
let current = device;
|
|
7850
8126
|
for (let i2 = 0;i2 < 5; i2++, current = join4(current, "..")) {
|
|
@@ -7873,6 +8149,9 @@ class WebSerialPortAdapter extends EventTarget {
|
|
|
7873
8149
|
ondisconnect = () => {};
|
|
7874
8150
|
port = null;
|
|
7875
8151
|
controller = null;
|
|
8152
|
+
dataListener = null;
|
|
8153
|
+
errorListener = null;
|
|
8154
|
+
nativePaused = false;
|
|
7876
8155
|
_readable = null;
|
|
7877
8156
|
_writable = null;
|
|
7878
8157
|
constructor(path, info) {
|
|
@@ -7903,12 +8182,43 @@ class WebSerialPortAdapter extends EventTarget {
|
|
|
7903
8182
|
this._readable = new ReadableStream({
|
|
7904
8183
|
start: (controller) => {
|
|
7905
8184
|
this.controller = controller;
|
|
7906
|
-
|
|
7907
|
-
|
|
8185
|
+
this.dataListener = (data) => {
|
|
8186
|
+
if (this.port !== port || this.controller !== controller)
|
|
8187
|
+
return;
|
|
8188
|
+
if ((controller.desiredSize ?? 1) <= 0) {
|
|
8189
|
+
const pause = port.pause;
|
|
8190
|
+
if (typeof pause === "function" && !this.nativePaused) {
|
|
8191
|
+
pause.call(port);
|
|
8192
|
+
this.nativePaused = true;
|
|
8193
|
+
} else {
|
|
8194
|
+
this.failReadableBackpressure(port, controller);
|
|
8195
|
+
return;
|
|
8196
|
+
}
|
|
8197
|
+
}
|
|
8198
|
+
try {
|
|
8199
|
+
controller.enqueue(data);
|
|
8200
|
+
} catch {
|
|
8201
|
+
return;
|
|
8202
|
+
}
|
|
8203
|
+
if ((controller.desiredSize ?? 1) <= 0 && !this.nativePaused) {
|
|
8204
|
+
const pause = port.pause;
|
|
8205
|
+
if (typeof pause === "function") {
|
|
8206
|
+
pause.call(port);
|
|
8207
|
+
this.nativePaused = true;
|
|
8208
|
+
}
|
|
8209
|
+
}
|
|
8210
|
+
};
|
|
8211
|
+
this.errorListener = (error) => {
|
|
8212
|
+
if (this.port !== port || this.controller !== controller)
|
|
8213
|
+
return;
|
|
7908
8214
|
controller.error(error);
|
|
8215
|
+
this.controller = null;
|
|
7909
8216
|
this.close().catch(() => {});
|
|
7910
|
-
}
|
|
8217
|
+
};
|
|
8218
|
+
port.on("data", this.dataListener);
|
|
8219
|
+
port.on("error", this.errorListener);
|
|
7911
8220
|
},
|
|
8221
|
+
pull: () => this.resumeNativePort(port),
|
|
7912
8222
|
cancel: () => void this.close()
|
|
7913
8223
|
});
|
|
7914
8224
|
this._writable = new WritableStream({
|
|
@@ -7925,6 +8235,7 @@ class WebSerialPortAdapter extends EventTarget {
|
|
|
7925
8235
|
if (!port)
|
|
7926
8236
|
return;
|
|
7927
8237
|
this.port = null;
|
|
8238
|
+
this.detachNativeListeners(port);
|
|
7928
8239
|
try {
|
|
7929
8240
|
this.controller?.close();
|
|
7930
8241
|
} catch {}
|
|
@@ -7940,6 +8251,28 @@ class WebSerialPortAdapter extends EventTarget {
|
|
|
7940
8251
|
this.dispatchEvent(new Event("disconnect"));
|
|
7941
8252
|
}
|
|
7942
8253
|
}
|
|
8254
|
+
detachNativeListeners(port) {
|
|
8255
|
+
if (this.dataListener !== null)
|
|
8256
|
+
port.off("data", this.dataListener);
|
|
8257
|
+
if (this.errorListener !== null)
|
|
8258
|
+
port.off("error", this.errorListener);
|
|
8259
|
+
this.dataListener = null;
|
|
8260
|
+
this.errorListener = null;
|
|
8261
|
+
this.nativePaused = false;
|
|
8262
|
+
}
|
|
8263
|
+
resumeNativePort(port) {
|
|
8264
|
+
if (this.port !== port || !this.nativePaused)
|
|
8265
|
+
return;
|
|
8266
|
+
this.nativePaused = false;
|
|
8267
|
+
port.resume?.();
|
|
8268
|
+
}
|
|
8269
|
+
failReadableBackpressure(port, controller) {
|
|
8270
|
+
if (this.port !== port || this.controller !== controller)
|
|
8271
|
+
return;
|
|
8272
|
+
controller.error(new Error("serial input exceeded readable-stream capacity; the native backend cannot pause"));
|
|
8273
|
+
this.controller = null;
|
|
8274
|
+
this.close();
|
|
8275
|
+
}
|
|
7943
8276
|
async forget() {
|
|
7944
8277
|
await this.close();
|
|
7945
8278
|
}
|
|
@@ -7948,29 +8281,38 @@ class WebSerialPortAdapter extends EventTarget {
|
|
|
7948
8281
|
class WebSerialAdapter extends EventTarget {
|
|
7949
8282
|
os;
|
|
7950
8283
|
list;
|
|
8284
|
+
linux;
|
|
7951
8285
|
onconnect = () => {};
|
|
7952
8286
|
ondisconnect = () => {};
|
|
7953
8287
|
ports = new Map;
|
|
7954
|
-
constructor(os2 = platform4(), list2 = listPorts) {
|
|
8288
|
+
constructor(os2 = platform4(), list2 = listPorts, linux = linuxDiscoveryOperations) {
|
|
7955
8289
|
super();
|
|
7956
8290
|
this.os = os2;
|
|
7957
8291
|
this.list = list2;
|
|
8292
|
+
this.linux = linux;
|
|
7958
8293
|
}
|
|
7959
8294
|
async listLinuxPorts() {
|
|
7960
|
-
const ttys = await
|
|
7961
|
-
const
|
|
7962
|
-
|
|
8295
|
+
const ttys = await this.linux.readdir("/sys/class/tty").then((names) => names.toSorted()).catch(() => []);
|
|
8296
|
+
const usbAttributes = new Map;
|
|
8297
|
+
const ports = await mapWithConcurrency(ttys, LINUX_DISCOVERY_CONCURRENCY, async (name) => {
|
|
7963
8298
|
try {
|
|
7964
|
-
const device = await realpath(`/sys/class/tty/${name}/device`);
|
|
7965
|
-
const subsystem = await
|
|
8299
|
+
const device = await this.linux.realpath(`/sys/class/tty/${name}/device`);
|
|
8300
|
+
const subsystem = await this.linux.readlink(join4(device, "subsystem")).catch(() => "");
|
|
7966
8301
|
const info = { path: `/dev/${name}` };
|
|
7967
8302
|
if (subsystem.includes("usb")) {
|
|
7968
|
-
|
|
8303
|
+
let attributes = usbAttributes.get(device);
|
|
8304
|
+
if (attributes === undefined) {
|
|
8305
|
+
attributes = this.linux.readUsbAttributes(device);
|
|
8306
|
+
usbAttributes.set(device, attributes);
|
|
8307
|
+
}
|
|
8308
|
+
Object.assign(info, await attributes);
|
|
7969
8309
|
}
|
|
7970
|
-
|
|
7971
|
-
} catch {
|
|
7972
|
-
|
|
7973
|
-
|
|
8310
|
+
return info;
|
|
8311
|
+
} catch {
|
|
8312
|
+
return;
|
|
8313
|
+
}
|
|
8314
|
+
});
|
|
8315
|
+
return ports.filter((port) => port !== undefined);
|
|
7974
8316
|
}
|
|
7975
8317
|
async getPorts() {
|
|
7976
8318
|
if (this.os === "win32") {
|
|
@@ -8020,7 +8362,7 @@ var serial = new WebSerialAdapter;
|
|
|
8020
8362
|
// src/device.ts
|
|
8021
8363
|
var V5X_PORT_ENV = "V5X_PORT";
|
|
8022
8364
|
function normalizePortSelector(selector) {
|
|
8023
|
-
const trimmed = selector?.trim();
|
|
8365
|
+
const trimmed = requireOptionValue(selector, "--port")?.trim();
|
|
8024
8366
|
return trimmed === "" ? undefined : trimmed;
|
|
8025
8367
|
}
|
|
8026
8368
|
function resolvePortSelector(options = {}, environment = process.env) {
|
|
@@ -8065,7 +8407,7 @@ class SelectedSerialAdapter extends EventTarget {
|
|
|
8065
8407
|
});
|
|
8066
8408
|
if (port)
|
|
8067
8409
|
return port;
|
|
8068
|
-
throw new
|
|
8410
|
+
throw new CliError(`No port found matching ${this.selector}`, CLI_EXIT_CODE.NO_DEVICE);
|
|
8069
8411
|
}
|
|
8070
8412
|
}
|
|
8071
8413
|
function selectSerialPort(baseSerial, selector) {
|
|
@@ -8079,7 +8421,7 @@ async function connectV5Device(device = createV5Device()) {
|
|
|
8079
8421
|
try {
|
|
8080
8422
|
const result = await device.connect();
|
|
8081
8423
|
if (result.isErr()) {
|
|
8082
|
-
throw new
|
|
8424
|
+
throw new CliError(`v5 device not connected: ${result.error.message ?? result.error.kind}`, CLI_EXIT_CODE.NO_DEVICE, { cause: result.error });
|
|
8083
8425
|
}
|
|
8084
8426
|
return device;
|
|
8085
8427
|
} catch (error) {
|
|
@@ -8153,13 +8495,28 @@ function formatCatText(bytes) {
|
|
|
8153
8495
|
`) ? text : `${text}
|
|
8154
8496
|
`;
|
|
8155
8497
|
}
|
|
8498
|
+
function toCatJson(file, bytes, output) {
|
|
8499
|
+
return {
|
|
8500
|
+
command: "cat",
|
|
8501
|
+
file,
|
|
8502
|
+
bytes: bytes.length,
|
|
8503
|
+
...output === undefined ? { encoding: "base64", data: Buffer.from(bytes).toString("base64") } : { output }
|
|
8504
|
+
};
|
|
8505
|
+
}
|
|
8156
8506
|
function registerCatCommand(program) {
|
|
8157
|
-
program.command("cat <file>", "read a file from flash").option("-o, --output", "write the file bytes to a local path").option("--port", "serial port path or id, defaults to V5X_PORT").action(async (file, options) => {
|
|
8507
|
+
program.command("cat <file>", "read a file from flash").option("-o, --output", "write the file bytes to a local path").option("--json", "print machine-readable JSON").option("--port", "serial port path or id, defaults to V5X_PORT").action(async (file, options) => {
|
|
8508
|
+
const output = requireOptionValue(options.output, "--output");
|
|
8158
8509
|
const handle = parseBrainFilePath(file);
|
|
8159
8510
|
await withSelectedV5Device(options, async (device) => {
|
|
8160
8511
|
const bytes = unwrapSerial(await device.brain.readFile(handle), `failed to read ${file}`);
|
|
8161
|
-
if (
|
|
8162
|
-
await Bun.write(
|
|
8512
|
+
if (output !== undefined) {
|
|
8513
|
+
await Bun.write(output, bytes);
|
|
8514
|
+
if (options.json === true)
|
|
8515
|
+
printJson(toCatJson(file, bytes, output));
|
|
8516
|
+
return;
|
|
8517
|
+
}
|
|
8518
|
+
if (options.json === true) {
|
|
8519
|
+
printJson(toCatJson(file, bytes));
|
|
8163
8520
|
return;
|
|
8164
8521
|
}
|
|
8165
8522
|
if (process.stdout.isTTY === true)
|
|
@@ -8922,12 +9279,14 @@ function unzipSync(data, opts) {
|
|
|
8922
9279
|
var FETCH_TIMEOUT_MS = 30000;
|
|
8923
9280
|
var PROS_ARCHIVE_LIMIT = 64 * 1024 * 1024;
|
|
8924
9281
|
var PROS_EXTRACTED_LIMIT = 256 * 1024 * 1024;
|
|
9282
|
+
var SCAFFOLD_WRITE_CONCURRENCY = 8;
|
|
8925
9283
|
var DEFAULT_PROS_TEMPLATE = {
|
|
8926
9284
|
tag: "4.2.2",
|
|
8927
9285
|
archiveUrl: "https://github.com/purduesigbots/pros/releases/download/4.2.2/kernel%404.2.2.zip",
|
|
8928
9286
|
sha256: "f019642af93dc3d164d1c3e67a2a7dc75c795ac6a4d550c9221c480e2e7f4899"
|
|
8929
9287
|
};
|
|
8930
9288
|
function parseToolchain(type) {
|
|
9289
|
+
requireOptionValue(type, "--type");
|
|
8931
9290
|
if (type === "pros" || type === "vexide")
|
|
8932
9291
|
return type;
|
|
8933
9292
|
if (type === undefined) {
|
|
@@ -9025,14 +9384,20 @@ async function fetchBytes(url, description, limit) {
|
|
|
9025
9384
|
return Buffer.concat(chunks, length);
|
|
9026
9385
|
}
|
|
9027
9386
|
async function writeFiles(root, files) {
|
|
9028
|
-
|
|
9387
|
+
const entries = Object.entries(files);
|
|
9388
|
+
const paths = entries.map(([relativePath, content]) => {
|
|
9029
9389
|
if (isAbsolute(relativePath) || relativePath.split(/[\\/]/).includes("..")) {
|
|
9030
9390
|
throw new Error(`template contains an unsafe path: ${relativePath}`);
|
|
9031
9391
|
}
|
|
9032
|
-
|
|
9033
|
-
|
|
9392
|
+
return { path: join5(root, relativePath), content };
|
|
9393
|
+
});
|
|
9394
|
+
const directories = [...new Set(paths.map(({ path }) => dirname2(path)))];
|
|
9395
|
+
await mapWithConcurrency(directories, SCAFFOLD_WRITE_CONCURRENCY, async (directory) => {
|
|
9396
|
+
await mkdir(directory, { recursive: true });
|
|
9397
|
+
});
|
|
9398
|
+
await mapWithConcurrency(paths, SCAFFOLD_WRITE_CONCURRENCY, async ({ path, content }) => {
|
|
9034
9399
|
await Bun.write(path, content);
|
|
9035
|
-
}
|
|
9400
|
+
});
|
|
9036
9401
|
}
|
|
9037
9402
|
async function createProsProject(path, names, source) {
|
|
9038
9403
|
const bytes = await fetchBytes(source.archiveUrl, `download PROS kernel ${source.tag}`, PROS_ARCHIVE_LIMIT);
|
|
@@ -9157,10 +9522,10 @@ async function createProject(inputPath, toolchain, nameOrOptions = basename3(res
|
|
|
9157
9522
|
try {
|
|
9158
9523
|
await rename(stagingPath, path);
|
|
9159
9524
|
} catch (error) {
|
|
9160
|
-
const destination = await stat2(path).catch(() => {
|
|
9525
|
+
const destination = await stat2(path, { bigint: true }).catch(() => {
|
|
9161
9526
|
return;
|
|
9162
9527
|
});
|
|
9163
|
-
if (destination?.isDirectory() && (await readdir3(path)).length === 0) {
|
|
9528
|
+
if (reservation !== undefined && destination?.isDirectory() && destination.dev === reservation.device && destination.ino === reservation.inode && (await readdir3(path)).length === 0) {
|
|
9164
9529
|
await rmdir(path);
|
|
9165
9530
|
try {
|
|
9166
9531
|
await rename(stagingPath, path);
|
|
@@ -9294,10 +9659,13 @@ function registerKvCommand(program) {
|
|
|
9294
9659
|
console.log(value);
|
|
9295
9660
|
});
|
|
9296
9661
|
});
|
|
9297
|
-
program.command("kv set <key> <value>", "set a system variable on a brain").option("--port", "serial port path or id, defaults to V5X_PORT").action(async (key, value, options) => {
|
|
9662
|
+
program.command("kv set <key> <value>", "set a system variable on a brain").option("--json", "print machine-readable JSON").option("--port", "serial port path or id, defaults to V5X_PORT").action(async (key, value, options) => {
|
|
9298
9663
|
await withSelectedV5Device(options, async (device) => {
|
|
9299
9664
|
unwrapSerial(await device.brain.setValue(key, value), `failed to set ${key} to ${value}`);
|
|
9300
|
-
|
|
9665
|
+
if (options.json === true)
|
|
9666
|
+
printJson({ command: "kv set", key, value, set: true });
|
|
9667
|
+
else
|
|
9668
|
+
console.log(`set ${key} to ${value}`);
|
|
9301
9669
|
});
|
|
9302
9670
|
});
|
|
9303
9671
|
}
|
|
@@ -9312,8 +9680,9 @@ function assertProjectNameArgument(name) {
|
|
|
9312
9680
|
function registerNewCommand(program) {
|
|
9313
9681
|
program.command("new <name>", "create a new V5 program", { alias: "n" }).option("-t, --type", "project toolchain (required: pros or vexide)").option("-p, --path", "destination path").option("--json", "print machine-readable JSON").action(async (name, options) => {
|
|
9314
9682
|
const toolchain = parseToolchain(options.type);
|
|
9683
|
+
const destinationPath = requireOptionValue(options.path, "--path");
|
|
9315
9684
|
assertProjectNameArgument(name);
|
|
9316
|
-
const destination =
|
|
9685
|
+
const destination = destinationPath === undefined ? join6(process.cwd(), name) : resolve4(destinationPath);
|
|
9317
9686
|
const path = await createProject(destination, toolchain, {
|
|
9318
9687
|
displayName: name,
|
|
9319
9688
|
cargoPackageName: toolchain === "vexide" ? name : basename5(destination),
|
|
@@ -9366,38 +9735,44 @@ function registerProgramsCommand(program) {
|
|
|
9366
9735
|
console.log(renderTable(["slot", "requested", "name", "size", "timestamp", "file"], formatProgramRows(programs)));
|
|
9367
9736
|
});
|
|
9368
9737
|
});
|
|
9369
|
-
program.command("start <slot>", "start a program slot on the V5 brain").option("--port", "serial port path or id, defaults to V5X_PORT").action(async (slot, options) => {
|
|
9738
|
+
program.command("start <slot>", "start a program slot on the V5 brain").option("--json", "print machine-readable JSON").option("--port", "serial port path or id, defaults to V5X_PORT").action(async (slot, options) => {
|
|
9370
9739
|
const slotNumber = parseSlotArgument(slot);
|
|
9371
9740
|
await withSelectedV5Device(options, async (device) => {
|
|
9372
9741
|
unwrapSerial(await device.brain.runProgram(slotNumber), `failed to start slot ${slot}`);
|
|
9373
|
-
|
|
9742
|
+
if (options.json === true)
|
|
9743
|
+
printJson({ command: "start", slot: slotNumber, started: true });
|
|
9744
|
+
else
|
|
9745
|
+
console.log(`started slot ${slot}`);
|
|
9374
9746
|
});
|
|
9375
9747
|
});
|
|
9376
|
-
program.command("stop", "stop the running program on the V5 brain").option("--port", "serial port path or id, defaults to V5X_PORT").action(async (options) => {
|
|
9748
|
+
program.command("stop", "stop the running program on the V5 brain").option("--json", "print machine-readable JSON").option("--port", "serial port path or id, defaults to V5X_PORT").action(async (options) => {
|
|
9377
9749
|
await withSelectedV5Device(options, async (device) => {
|
|
9378
9750
|
unwrapSerial(await device.brain.stopProgram(), "failed to stop program");
|
|
9379
|
-
|
|
9751
|
+
if (options.json === true)
|
|
9752
|
+
printJson({ command: "stop", stopped: true });
|
|
9753
|
+
else
|
|
9754
|
+
console.log("stopped program");
|
|
9380
9755
|
});
|
|
9381
9756
|
});
|
|
9382
9757
|
}
|
|
9383
9758
|
|
|
9384
9759
|
// src/commands/rm.ts
|
|
9385
9760
|
function registerRmCommand(program) {
|
|
9386
|
-
program.command("rm <file>", "erase a file from flash").option("--port", "serial port path or id, defaults to V5X_PORT").action(async (file, options) => {
|
|
9761
|
+
program.command("rm <file>", "erase a file from flash").option("--json", "print machine-readable JSON").option("--port", "serial port path or id, defaults to V5X_PORT").action(async (file, options) => {
|
|
9387
9762
|
const handle = parseBrainFilePath(file);
|
|
9388
9763
|
await withSelectedV5Device(options, async (device) => {
|
|
9389
9764
|
unwrapSerial(await device.brain.removeFile(handle), `failed to erase ${file}`);
|
|
9390
|
-
|
|
9765
|
+
if (options.json === true)
|
|
9766
|
+
printJson({ command: "rm", file, erased: true });
|
|
9767
|
+
else
|
|
9768
|
+
console.log(`erased ${file}`);
|
|
9391
9769
|
});
|
|
9392
9770
|
});
|
|
9393
9771
|
}
|
|
9394
9772
|
|
|
9395
9773
|
// src/utils/upload.ts
|
|
9396
9774
|
function resolveSlotOption(slot) {
|
|
9397
|
-
|
|
9398
|
-
throw new Error("--slot requires a value (e.g. --slot 1); it cannot be passed as a bare flag");
|
|
9399
|
-
}
|
|
9400
|
-
return Number(slot);
|
|
9775
|
+
return Number(requireOptionValue(slot, "--slot"));
|
|
9401
9776
|
}
|
|
9402
9777
|
function resolveBuildOption(build, file) {
|
|
9403
9778
|
if (build !== undefined)
|
|
@@ -9405,14 +9780,18 @@ function resolveBuildOption(build, file) {
|
|
|
9405
9780
|
return file === undefined;
|
|
9406
9781
|
}
|
|
9407
9782
|
async function uploadProgramFromCommand(path, options, runDefault) {
|
|
9783
|
+
const name = requireOptionValue(options.name, "--name");
|
|
9784
|
+
const description = requireOptionValue(options.description, "--description");
|
|
9785
|
+
const icon = requireOptionValue(options.icon, "--icon");
|
|
9786
|
+
const file = requireOptionValue(options.file, "--file");
|
|
9408
9787
|
await uploadProgram2({
|
|
9409
9788
|
path: path ?? process.cwd(),
|
|
9410
9789
|
slot: resolveSlotOption(options.slot),
|
|
9411
|
-
name
|
|
9412
|
-
description
|
|
9413
|
-
icon:
|
|
9414
|
-
artifact:
|
|
9415
|
-
build: resolveBuildOption(options.build,
|
|
9790
|
+
name,
|
|
9791
|
+
description,
|
|
9792
|
+
icon: icon ?? "default.bmp",
|
|
9793
|
+
artifact: file,
|
|
9794
|
+
build: resolveBuildOption(options.build, file),
|
|
9416
9795
|
run: options.run ?? runDefault,
|
|
9417
9796
|
port: options.port,
|
|
9418
9797
|
command: runDefault ? "run" : "upload",
|
|
@@ -9458,11 +9837,17 @@ async function uploadProgram2(options) {
|
|
|
9458
9837
|
run: options.run
|
|
9459
9838
|
});
|
|
9460
9839
|
const validated = await validateProgramArtifacts(artifacts);
|
|
9461
|
-
const bytes = await
|
|
9462
|
-
|
|
9840
|
+
const [bytes, coldBytes] = await Promise.allSettled([
|
|
9841
|
+
Bun.file(validated.hot.path).bytes(),
|
|
9842
|
+
validated.cold ? Bun.file(validated.cold.path).bytes() : Promise.resolve(undefined)
|
|
9843
|
+
]);
|
|
9844
|
+
if (bytes.status === "rejected")
|
|
9845
|
+
throw bytes.reason;
|
|
9846
|
+
if (coldBytes.status === "rejected")
|
|
9847
|
+
throw coldBytes.reason;
|
|
9463
9848
|
await withSelectedV5Device(options, async (device) => {
|
|
9464
9849
|
const progress = reportProgress();
|
|
9465
|
-
const uploaded = await device.brain.uploadProgram(config2, bytes, coldBytes, progress);
|
|
9850
|
+
const uploaded = await device.brain.uploadProgram(config2, bytes.value, coldBytes.value, progress);
|
|
9466
9851
|
progress.finish();
|
|
9467
9852
|
if (uploaded.isErr()) {
|
|
9468
9853
|
throw new Error(formatSerialFailure("the brain rejected the program upload", uploaded.error));
|
|
@@ -9502,18 +9887,25 @@ import { deflateSync } from "zlib";
|
|
|
9502
9887
|
var WIDTH = 480;
|
|
9503
9888
|
var HEIGHT = 272;
|
|
9504
9889
|
var ROW_BYTES = WIDTH * 3;
|
|
9890
|
+
var KITTY_CHUNK_BYTES = 4096;
|
|
9891
|
+
var KITTY_RAW_CHUNK_BYTES = KITTY_CHUNK_BYTES / 4 * 3;
|
|
9892
|
+
var PNG_CRC32_TABLE = new Uint32Array(256);
|
|
9893
|
+
for (let index = 0;index < PNG_CRC32_TABLE.length; index++) {
|
|
9894
|
+
let value = index;
|
|
9895
|
+
for (let bit = 0;bit < 8; bit++) {
|
|
9896
|
+
value = value >>> 1 ^ (value & 1 ? 3988292384 : 0);
|
|
9897
|
+
}
|
|
9898
|
+
PNG_CRC32_TABLE[index] = value >>> 0;
|
|
9899
|
+
}
|
|
9505
9900
|
function assertScreenshotSize(bytes) {
|
|
9506
9901
|
if (bytes.length !== ROW_BYTES * HEIGHT) {
|
|
9507
9902
|
throw new Error(`bad screenshot size: ${bytes.length}`);
|
|
9508
9903
|
}
|
|
9509
9904
|
}
|
|
9510
|
-
function
|
|
9905
|
+
function pngCrc32(bytes) {
|
|
9511
9906
|
let crc2 = 4294967295;
|
|
9512
9907
|
for (const byte of bytes) {
|
|
9513
|
-
crc2
|
|
9514
|
-
for (let bit = 0;bit < 8; bit++) {
|
|
9515
|
-
crc2 = crc2 >>> 1 ^ (crc2 & 1 ? 3988292384 : 0);
|
|
9516
|
-
}
|
|
9908
|
+
crc2 = crc2 >>> 8 ^ PNG_CRC32_TABLE[(crc2 ^ byte) & 255];
|
|
9517
9909
|
}
|
|
9518
9910
|
return (crc2 ^ 4294967295) >>> 0;
|
|
9519
9911
|
}
|
|
@@ -9522,7 +9914,7 @@ function pngChunk(type, data) {
|
|
|
9522
9914
|
chunk.writeUInt32BE(data.length, 0);
|
|
9523
9915
|
chunk.write(type, 4, "ascii");
|
|
9524
9916
|
chunk.set(data, 8);
|
|
9525
|
-
chunk.writeUInt32BE(
|
|
9917
|
+
chunk.writeUInt32BE(pngCrc32(chunk.subarray(4, 8 + data.length)), 8 + data.length);
|
|
9526
9918
|
return chunk;
|
|
9527
9919
|
}
|
|
9528
9920
|
function encodeScreenshotPng(bytes) {
|
|
@@ -9554,6 +9946,7 @@ ${WIDTH} ${HEIGHT}
|
|
|
9554
9946
|
]);
|
|
9555
9947
|
}
|
|
9556
9948
|
function parseScreenshotFormat(format) {
|
|
9949
|
+
requireOptionValue(format, "--format");
|
|
9557
9950
|
if (format === undefined || format === "png" || format === "ppm") {
|
|
9558
9951
|
return format ?? "png";
|
|
9559
9952
|
}
|
|
@@ -9572,36 +9965,51 @@ function assertScreenshotOptions(options) {
|
|
|
9572
9965
|
if (options.json === true && options.output === undefined)
|
|
9573
9966
|
throw new Error("--json requires --output");
|
|
9574
9967
|
}
|
|
9575
|
-
function shouldPrintKittyRgb() {
|
|
9576
|
-
|
|
9968
|
+
function shouldPrintKittyRgb(environment = process.env, isTTY = process.stdout.isTTY) {
|
|
9969
|
+
if (isTTY !== true)
|
|
9970
|
+
return false;
|
|
9971
|
+
const term = environment.TERM?.toLowerCase();
|
|
9972
|
+
const termProgram = environment.TERM_PROGRAM?.toLowerCase();
|
|
9973
|
+
return environment.KITTY_WINDOW_ID !== undefined || environment.WEZTERM_PANE !== undefined || term === "xterm-kitty" || term?.includes("ghostty") === true || termProgram === "kitty" || termProgram === "ghostty" || termProgram === "wezterm";
|
|
9577
9974
|
}
|
|
9578
|
-
function
|
|
9975
|
+
function* iterateKittyRgb(bytes) {
|
|
9579
9976
|
assertScreenshotSize(bytes);
|
|
9580
|
-
|
|
9581
|
-
|
|
9582
|
-
|
|
9977
|
+
for (let offset = 0;offset < bytes.length; offset += KITTY_RAW_CHUNK_BYTES) {
|
|
9978
|
+
const payload = Buffer.from(bytes.subarray(offset, offset + KITTY_RAW_CHUNK_BYTES)).toString("base64");
|
|
9979
|
+
const more = offset + KITTY_RAW_CHUNK_BYTES < bytes.length;
|
|
9980
|
+
const control = offset === 0 ? `a=T,f=24,s=${WIDTH},v=${HEIGHT},c=40,m=${more ? 1 : 0}` : `m=${more ? 1 : 0}`;
|
|
9981
|
+
yield `\x1B_G${control};${payload}\x1B\\${more ? "" : `
|
|
9982
|
+
`}`;
|
|
9983
|
+
}
|
|
9984
|
+
}
|
|
9985
|
+
function printKittyRgb(bytes) {
|
|
9986
|
+
for (const chunk of iterateKittyRgb(bytes))
|
|
9987
|
+
process.stdout.write(chunk);
|
|
9583
9988
|
}
|
|
9584
9989
|
function registerScreenshotCommand(program) {
|
|
9585
9990
|
program.command("screenshot", "take a screen capture of the brain", {
|
|
9586
9991
|
alias: "sc"
|
|
9587
9992
|
}).option("-o, --output", "write the screenshot to a file").option("--format", "file format for --output: png or ppm", "png").option("--port", "serial port path or id, defaults to V5X_PORT").option("--json", "print machine-readable JSON").action(async (options) => {
|
|
9993
|
+
const output = requireOptionValue(options.output, "--output");
|
|
9588
9994
|
const format = parseScreenshotFormat(options.format);
|
|
9589
|
-
assertScreenshotOptions(options);
|
|
9995
|
+
assertScreenshotOptions({ output, json: options.json });
|
|
9590
9996
|
await withSelectedV5Device(options, async (device) => {
|
|
9591
9997
|
const frame = unwrapSerial(await device.brain.captureScreen(), "failed to capture screenshot");
|
|
9592
|
-
if (
|
|
9998
|
+
if (output === undefined) {
|
|
9593
9999
|
if (shouldPrintKittyRgb())
|
|
9594
10000
|
printKittyRgb(frame);
|
|
9595
|
-
else
|
|
10001
|
+
else {
|
|
9596
10002
|
console.error("use --output to write the screenshot to a file");
|
|
10003
|
+
process.exitCode = 1;
|
|
10004
|
+
}
|
|
9597
10005
|
return;
|
|
9598
10006
|
}
|
|
9599
10007
|
const data = format === "png" ? encodeScreenshotPng(frame) : encodeScreenshotPpm(frame);
|
|
9600
|
-
await Bun.write(
|
|
10008
|
+
await Bun.write(output, data);
|
|
9601
10009
|
if (options.json === true)
|
|
9602
|
-
printJson(toScreenshotJson(
|
|
10010
|
+
printJson(toScreenshotJson(output, format, data.length));
|
|
9603
10011
|
else
|
|
9604
|
-
console.log(`wrote ${
|
|
10012
|
+
console.log(`wrote ${output}`);
|
|
9605
10013
|
});
|
|
9606
10014
|
});
|
|
9607
10015
|
}
|
|
@@ -9614,7 +10022,7 @@ function registerUploadCommand(program) {
|
|
|
9614
10022
|
}
|
|
9615
10023
|
|
|
9616
10024
|
// src/index.ts
|
|
9617
|
-
var program = lib_default2("v5x").version(package_default.version).describe(package_default.description);
|
|
10025
|
+
var program = lib_default2("v5x").version(package_default.version).describe(package_default.description).option("--verbose", "print stack traces for errors");
|
|
9618
10026
|
var commands = [
|
|
9619
10027
|
registerBuildCommand,
|
|
9620
10028
|
registerCleanCommand,
|
|
@@ -9637,9 +10045,9 @@ for (const register of commands)
|
|
|
9637
10045
|
try {
|
|
9638
10046
|
await program.parse(process.argv);
|
|
9639
10047
|
} catch (error) {
|
|
9640
|
-
console.error(
|
|
9641
|
-
process.exitCode =
|
|
10048
|
+
console.error(isJsonOutput() ? formatCliJsonError(error) : formatCliError(error, isVerbose()));
|
|
10049
|
+
process.exitCode = cliExitCode(error);
|
|
9642
10050
|
}
|
|
9643
10051
|
|
|
9644
|
-
//# debugId=
|
|
10052
|
+
//# debugId=C77D76845A1AA6D564756E2164756E21
|
|
9645
10053
|
//# sourceMappingURL=index.js.map
|