@v5x/serial 0.5.5 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -19,12 +19,14 @@ var __toESM = (mod, isNodeMode, target) => {
19
19
  }
20
20
  target = mod != null ? __create(__getProtoOf(mod)) : {};
21
21
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
22
- for (let key of __getOwnPropNames(mod))
23
- if (!__hasOwnProp.call(to, key))
24
- __defProp(to, key, {
25
- get: __accessProp.bind(mod, key),
26
- enumerable: true
27
- });
22
+ if (mod && typeof mod === "object" || typeof mod === "function") {
23
+ for (let key of __getOwnPropNames(mod))
24
+ if (!__hasOwnProp.call(to, key))
25
+ __defProp(to, key, {
26
+ get: __accessProp.bind(mod, key),
27
+ enumerable: true
28
+ });
29
+ }
28
30
  if (canCache)
29
31
  cache.set(mod, to);
30
32
  return to;
@@ -62,7 +64,7 @@ var __export = (target, all) => {
62
64
  };
63
65
 
64
66
  // ../../node_modules/.bun/neverthrow@8.2.0/node_modules/neverthrow/dist/index.cjs.js
65
- var require_index_cjs = __commonJS((exports2) => {
67
+ var require_index_cjs = __commonJS(function(exports2) {
66
68
  var defaultErrorConfig = {
67
69
  withStackTrace: false
68
70
  };
@@ -850,6 +852,7 @@ var SelectDashScreen;
850
852
  // src/VexError.ts
851
853
  class VexSerialError extends Error {
852
854
  kind;
855
+ ackType = undefined;
853
856
  constructor(kind, message) {
854
857
  super(message);
855
858
  this.name = "VexSerialError";
@@ -872,9 +875,11 @@ class VexInvalidArgumentError extends VexSerialError {
872
875
  }
873
876
 
874
877
  class VexProtocolError extends VexSerialError {
875
- constructor(message) {
878
+ ackType;
879
+ constructor(message, ackType) {
876
880
  super("protocol", message);
877
881
  this.name = "VexProtocolError";
882
+ this.ackType = ackType;
878
883
  }
879
884
  }
880
885
 
@@ -934,9 +939,19 @@ class VexEventEmitter {
934
939
  this.handlerMap.set(eventName, listeners);
935
940
  }
936
941
  emit(eventName, data) {
937
- (this.handlerMap.get(eventName) ?? []).forEach((callback) => {
938
- callback(data);
939
- });
942
+ const errors = [];
943
+ for (const callback of [...this.handlerMap.get(eventName) ?? []]) {
944
+ try {
945
+ callback(data);
946
+ } catch (error) {
947
+ errors.push(error);
948
+ }
949
+ }
950
+ if (errors.length === 1)
951
+ throw errors[0];
952
+ if (errors.length > 1) {
953
+ throw new AggregateError(errors, `listeners for ${String(eventName)} failed`);
954
+ }
940
955
  }
941
956
  clearListeners() {
942
957
  this.handlerMap.clear();
@@ -949,17 +964,20 @@ class VexEventTarget {
949
964
  this.emitter = new VexEventEmitter;
950
965
  }
951
966
  emit(eventName, data) {
952
- this.emitter.emit(String(eventName), data);
967
+ this.emitter.emit(this.normalizeEventName(eventName), data);
953
968
  }
954
969
  on(eventName, listener) {
955
- this.emitter.on(String(eventName), listener);
970
+ this.emitter.on(this.normalizeEventName(eventName), listener);
956
971
  }
957
972
  remove(eventName, listener) {
958
- this.emitter.remove(String(eventName), listener);
973
+ this.emitter.remove(this.normalizeEventName(eventName), listener);
959
974
  }
960
975
  clearListeners() {
961
976
  this.emitter.clearListeners();
962
977
  }
978
+ normalizeEventName(eventName) {
979
+ return String(eventName);
980
+ }
963
981
  }
964
982
 
965
983
  // src/VexConnection.ts
@@ -977,42 +995,32 @@ class Packet {
977
995
  }
978
996
 
979
997
  class DeviceBoundPacket extends Packet {
998
+ static COMMAND_ID;
999
+ static COMMAND_EXTENDED_ID;
980
1000
  get commandId() {
981
1001
  return this.constructor.COMMAND_ID;
982
1002
  }
983
1003
  get commandExtendedId() {
984
1004
  return this.constructor.COMMAND_EXTENDED_ID;
985
1005
  }
986
- static COMMAND_ID;
987
- static COMMAND_EXTENDED_ID;
988
1006
  constructor(payload) {
989
- super(new Uint8Array);
990
- const me = this.constructor;
991
- if (me.COMMAND_EXTENDED_ID === undefined) {
992
- if (payload === undefined) {
993
- this.data = Packet.ENCODER.cdcCommand(me.COMMAND_ID);
994
- } else {
995
- this.data = Packet.ENCODER.cdcCommandWithData(me.COMMAND_ID, payload);
996
- }
997
- } else {
998
- if (payload === undefined) {
999
- this.data = Packet.ENCODER.cdc2Command(me.COMMAND_ID, me.COMMAND_EXTENDED_ID);
1000
- } else {
1001
- this.data = Packet.ENCODER.cdc2CommandWithData(me.COMMAND_ID, me.COMMAND_EXTENDED_ID, payload);
1002
- }
1003
- }
1007
+ const { COMMAND_ID: cmd, COMMAND_EXTENDED_ID: ext } = new.target;
1008
+ const encoder = Packet.ENCODER;
1009
+ super(ext === undefined ? payload === undefined ? encoder.cdcCommand(cmd) : encoder.cdcCommandWithData(cmd, payload) : payload === undefined ? encoder.cdc2Command(cmd, ext) : encoder.cdc2CommandWithData(cmd, ext, payload));
1004
1010
  }
1005
1011
  }
1006
1012
 
1007
1013
  class HostBoundPacket extends Packet {
1008
- ack = 255 /* CDC2_NACK */;
1014
+ static COMMAND_ID;
1015
+ static COMMAND_EXTENDED_ID;
1016
+ ack;
1009
1017
  payloadSize;
1010
1018
  ackIndex;
1011
1019
  constructor(data) {
1012
1020
  super(data);
1013
1021
  this.payloadSize = Packet.ENCODER.getPayloadSize(this.data);
1014
- const n = Packet.ENCODER.getHostHeaderLength(this.data);
1015
- this.ack = this.data[this.ackIndex = n + 1];
1022
+ this.ackIndex = Packet.ENCODER.getHostHeaderLength(this.data) + 1;
1023
+ this.ack = this.data[this.ackIndex];
1016
1024
  }
1017
1025
  static isValidPacket(data, n) {
1018
1026
  const ack = data[n + 1];
@@ -1021,309 +1029,50 @@ class HostBoundPacket extends Packet {
1021
1029
  }
1022
1030
 
1023
1031
  // src/VexCRC.ts
1024
- var CRC16TABLE = [
1025
- 0,
1026
- 4129,
1027
- 8258,
1028
- 12387,
1029
- 16516,
1030
- 20645,
1031
- 24774,
1032
- 28903,
1033
- 33032,
1034
- 37161,
1035
- 41290,
1036
- 45419,
1037
- 49548,
1038
- 53677,
1039
- 57806,
1040
- 61935,
1041
- 4657,
1042
- 528,
1043
- 12915,
1044
- 8786,
1045
- 21173,
1046
- 17044,
1047
- 29431,
1048
- 25302,
1049
- 37689,
1050
- 33560,
1051
- 45947,
1052
- 41818,
1053
- 54205,
1054
- 50076,
1055
- 62463,
1056
- 58334,
1057
- 9314,
1058
- 13379,
1059
- 1056,
1060
- 5121,
1061
- 25830,
1062
- 29895,
1063
- 17572,
1064
- 21637,
1065
- 42346,
1066
- 46411,
1067
- 34088,
1068
- 38153,
1069
- 58862,
1070
- 62927,
1071
- 50604,
1072
- 54669,
1073
- 13907,
1074
- 9842,
1075
- 5649,
1076
- 1584,
1077
- 30423,
1078
- 26358,
1079
- 22165,
1080
- 18100,
1081
- 46939,
1082
- 42874,
1083
- 38681,
1084
- 34616,
1085
- 63455,
1086
- 59390,
1087
- 55197,
1088
- 51132,
1089
- 18628,
1090
- 22757,
1091
- 26758,
1092
- 30887,
1093
- 2112,
1094
- 6241,
1095
- 10242,
1096
- 14371,
1097
- 51660,
1098
- 55789,
1099
- 59790,
1100
- 63919,
1101
- 35144,
1102
- 39273,
1103
- 43274,
1104
- 47403,
1105
- 23285,
1106
- 19156,
1107
- 31415,
1108
- 27286,
1109
- 6769,
1110
- 2640,
1111
- 14899,
1112
- 10770,
1113
- 56317,
1114
- 52188,
1115
- 64447,
1116
- 60318,
1117
- 39801,
1118
- 35672,
1119
- 47931,
1120
- 43802,
1121
- 27814,
1122
- 31879,
1123
- 19684,
1124
- 23749,
1125
- 11298,
1126
- 15363,
1127
- 3168,
1128
- 7233,
1129
- 60846,
1130
- 64911,
1131
- 52716,
1132
- 56781,
1133
- 44330,
1134
- 48395,
1135
- 36200,
1136
- 40265,
1137
- 32407,
1138
- 28342,
1139
- 24277,
1140
- 20212,
1141
- 15891,
1142
- 11826,
1143
- 7761,
1144
- 3696,
1145
- 65439,
1146
- 61374,
1147
- 57309,
1148
- 53244,
1149
- 48923,
1150
- 44858,
1151
- 40793,
1152
- 36728,
1153
- 37256,
1154
- 33193,
1155
- 45514,
1156
- 41451,
1157
- 53516,
1158
- 49453,
1159
- 61774,
1160
- 57711,
1161
- 4224,
1162
- 161,
1163
- 12482,
1164
- 8419,
1165
- 20484,
1166
- 16421,
1167
- 28742,
1168
- 24679,
1169
- 33721,
1170
- 37784,
1171
- 41979,
1172
- 46042,
1173
- 49981,
1174
- 54044,
1175
- 58239,
1176
- 62302,
1177
- 689,
1178
- 4752,
1179
- 8947,
1180
- 13010,
1181
- 16949,
1182
- 21012,
1183
- 25207,
1184
- 29270,
1185
- 46570,
1186
- 42443,
1187
- 38312,
1188
- 34185,
1189
- 62830,
1190
- 58703,
1191
- 54572,
1192
- 50445,
1193
- 13538,
1194
- 9411,
1195
- 5280,
1196
- 1153,
1197
- 29798,
1198
- 25671,
1199
- 21540,
1200
- 17413,
1201
- 42971,
1202
- 47098,
1203
- 34713,
1204
- 38840,
1205
- 59231,
1206
- 63358,
1207
- 50973,
1208
- 55100,
1209
- 9939,
1210
- 14066,
1211
- 1681,
1212
- 5808,
1213
- 26199,
1214
- 30326,
1215
- 17941,
1216
- 22068,
1217
- 55628,
1218
- 51565,
1219
- 63758,
1220
- 59695,
1221
- 39368,
1222
- 35305,
1223
- 47498,
1224
- 43435,
1225
- 22596,
1226
- 18533,
1227
- 30726,
1228
- 26663,
1229
- 6336,
1230
- 2273,
1231
- 14466,
1232
- 10403,
1233
- 52093,
1234
- 56156,
1235
- 60223,
1236
- 64286,
1237
- 35833,
1238
- 39896,
1239
- 43963,
1240
- 48026,
1241
- 19061,
1242
- 23124,
1243
- 27191,
1244
- 31254,
1245
- 2801,
1246
- 6864,
1247
- 10931,
1248
- 14994,
1249
- 64814,
1250
- 60687,
1251
- 56684,
1252
- 52557,
1253
- 48554,
1254
- 44427,
1255
- 40424,
1256
- 36297,
1257
- 31782,
1258
- 27655,
1259
- 23652,
1260
- 19525,
1261
- 15522,
1262
- 11395,
1263
- 7392,
1264
- 3265,
1265
- 61215,
1266
- 65342,
1267
- 53085,
1268
- 57212,
1269
- 44955,
1270
- 49082,
1271
- 36825,
1272
- 40952,
1273
- 28183,
1274
- 32310,
1275
- 20053,
1276
- 24180,
1277
- 11923,
1278
- 16050,
1279
- 3793,
1280
- 7920
1281
- ];
1032
+ var POLYNOMIAL_CRC32 = 79764919;
1033
+ var POLYNOMIAL_CRC16 = 4129;
1034
+ function genTable16() {
1035
+ const table = new Uint16Array(256);
1036
+ for (let i = 0;i < 256; i++) {
1037
+ let acc = i << 8;
1038
+ for (let j = 0;j < 8; j++) {
1039
+ acc = (acc & 32768) !== 0 ? acc << 1 ^ POLYNOMIAL_CRC16 : acc << 1;
1040
+ }
1041
+ table[i] = acc & 65535;
1042
+ }
1043
+ return table;
1044
+ }
1045
+ function genTable32() {
1046
+ const table = new Uint32Array(256);
1047
+ for (let i = 0;i < 256; i++) {
1048
+ let acc = i << 24;
1049
+ for (let j = 0;j < 8; j++) {
1050
+ acc = (acc & 2147483648) !== 0 ? acc << 1 ^ POLYNOMIAL_CRC32 : acc << 1;
1051
+ }
1052
+ table[i] = acc;
1053
+ }
1054
+ return table;
1055
+ }
1056
+ var CRC16_TABLE = genTable16();
1057
+ var CRC32_TABLE = genTable32();
1282
1058
 
1283
1059
  class CrcGenerator {
1284
- crc32Table;
1285
- static POLYNOMIAL_CRC32 = 79764919;
1286
- static POLYNOMIAL_CRC16 = 4129;
1287
- constructor() {
1288
- this.crc32Table = new Uint32Array(256);
1289
- this.crc32GenTable();
1290
- }
1060
+ crc32Table = CRC32_TABLE;
1061
+ static POLYNOMIAL_CRC32 = POLYNOMIAL_CRC32;
1062
+ static POLYNOMIAL_CRC16 = POLYNOMIAL_CRC16;
1291
1063
  crc16(buf, initValue) {
1292
- const numberOfBytes = buf.byteLength;
1293
- let accumulator = initValue;
1294
- let i;
1295
- let j;
1296
- for (j = 0;j < numberOfBytes; j++) {
1297
- i = (accumulator >>> 8 ^ buf[j]) & 255;
1298
- accumulator = (accumulator << 8 ^ CRC16TABLE[i]) >>> 0;
1299
- }
1300
- return (accumulator & 65535) >>> 0;
1301
- }
1302
- crc32GenTable() {
1303
- let i;
1304
- let j;
1305
- let crcAccumulator;
1306
- for (i = 0;i < 256; i++) {
1307
- crcAccumulator = i << 24;
1308
- for (j = 0;j < 8; j++) {
1309
- if ((crcAccumulator & 2147483648) !== 0)
1310
- crcAccumulator = crcAccumulator << 1 ^ CrcGenerator.POLYNOMIAL_CRC32;
1311
- else
1312
- crcAccumulator = crcAccumulator << 1;
1313
- }
1314
- this.crc32Table[i] = crcAccumulator;
1064
+ let acc = initValue;
1065
+ for (let j = 0;j < buf.length; j++) {
1066
+ acc = (acc << 8 ^ CRC16_TABLE[(acc >>> 8 ^ buf[j]) & 255]) >>> 0;
1315
1067
  }
1068
+ return acc & 65535;
1316
1069
  }
1317
1070
  crc32(buf, initValue) {
1318
- const numberOfBytes = buf.byteLength;
1319
- let crcAccumulator = initValue;
1320
- let i;
1321
- let j;
1322
- for (j = 0;j < numberOfBytes; j++) {
1323
- i = (crcAccumulator >>> 24 ^ buf[j]) & 255;
1324
- crcAccumulator = (crcAccumulator << 8 ^ this.crc32Table[i]) >>> 0;
1071
+ let acc = initValue;
1072
+ for (let j = 0;j < buf.length; j++) {
1073
+ acc = (acc << 8 ^ CRC32_TABLE[(acc >>> 24 ^ buf[j]) & 255]) >>> 0;
1325
1074
  }
1326
- return (crcAccumulator & 4294967295) >>> 0;
1075
+ return acc >>> 0;
1327
1076
  }
1328
1077
  }
1329
1078
 
@@ -1415,9 +1164,8 @@ class VexFirmwareVersion {
1415
1164
  }
1416
1165
  static fromString(version) {
1417
1166
  const parts = version.toLowerCase().replace(/b/g, "").split(".").map((x) => parseInt(x, 10));
1418
- while (parts.length < 4) {
1167
+ while (parts.length < 4)
1419
1168
  parts.push(0);
1420
- }
1421
1169
  return new VexFirmwareVersion(parts[0], parts[1], parts[2], parts[3]);
1422
1170
  }
1423
1171
  static fromUint8Array(data, offset = 0, reverse = false) {
@@ -1447,24 +1195,23 @@ class VexFirmwareVersion {
1447
1195
  return `${this.toUserString()}.b${this.beta}`;
1448
1196
  }
1449
1197
  compare(that) {
1450
- const majorComp = this.major - that.major;
1451
- const minorComp = this.minor - that.minor;
1452
- const buildComp = this.build - that.build;
1453
- const betaComp = this.beta - that.beta;
1454
- if (majorComp !== 0) {
1455
- return majorComp;
1456
- } else if (minorComp !== 0) {
1457
- return minorComp;
1458
- } else if (buildComp !== 0) {
1459
- return buildComp;
1460
- } else if (betaComp !== 0) {
1461
- return betaComp;
1198
+ for (const [a, b] of [
1199
+ [this.major, that.major],
1200
+ [this.minor, that.minor],
1201
+ [this.build, that.build],
1202
+ [this.beta, that.beta]
1203
+ ]) {
1204
+ const delta = a - b;
1205
+ if (delta !== 0)
1206
+ return delta;
1462
1207
  }
1463
1208
  return 0;
1464
1209
  }
1465
1210
  }
1466
1211
 
1467
1212
  // src/VexPacketView.ts
1213
+ var textDecoder = new TextDecoder("UTF-8");
1214
+
1468
1215
  class PacketView extends DataView {
1469
1216
  position = 0;
1470
1217
  littleEndianDefault = true;
@@ -1477,14 +1224,10 @@ class PacketView extends DataView {
1477
1224
  return view;
1478
1225
  }
1479
1226
  nextInt8() {
1480
- const result = this.getInt8(this.position);
1481
- this.position += 1;
1482
- return result;
1227
+ return this.getInt8(this.position++);
1483
1228
  }
1484
1229
  nextUint8() {
1485
- const result = this.getUint8(this.position);
1486
- this.position += 1;
1487
- return result;
1230
+ return this.getUint8(this.position++);
1488
1231
  }
1489
1232
  nextInt16(littleEndian = this.littleEndianDefault) {
1490
1233
  const result = this.getInt16(this.position, littleEndian);
@@ -1507,37 +1250,28 @@ class PacketView extends DataView {
1507
1250
  return result;
1508
1251
  }
1509
1252
  nextString(length) {
1510
- let result = "";
1511
- for (let i = 0;i < length; i++) {
1512
- result += String.fromCharCode(this.nextUint8());
1513
- }
1253
+ const result = textDecoder.decode(new Uint8Array(this.buffer, this.byteOffset + this.position, length));
1254
+ this.position += length;
1514
1255
  return result;
1515
1256
  }
1516
1257
  nextNTBS(length) {
1517
- let result = "";
1518
- const lastPosition = this.position;
1519
- for (let i = 0;i < length; i++) {
1520
- if (this.byteLength <= this.position)
1521
- break;
1522
- const g = this.nextUint8();
1523
- if (g === 0)
1524
- break;
1525
- result += String.fromCharCode(g);
1526
- }
1527
- this.position = lastPosition + length;
1258
+ const start = this.position;
1259
+ const result = this.nextVarNTBS(length);
1260
+ this.position = start + length;
1528
1261
  return result;
1529
1262
  }
1530
1263
  nextVarNTBS(length) {
1531
- let result = "";
1264
+ const start = this.position;
1265
+ let byteLength = 0;
1532
1266
  for (let i = 0;i < length; i++) {
1533
1267
  if (this.byteLength <= this.position)
1534
1268
  break;
1535
1269
  const g = this.nextUint8();
1536
1270
  if (g === 0)
1537
1271
  break;
1538
- result += String.fromCharCode(g);
1272
+ byteLength++;
1539
1273
  }
1540
- return result;
1274
+ return textDecoder.decode(new Uint8Array(this.buffer, this.byteOffset + start, byteLength));
1541
1275
  }
1542
1276
  nextVersion(reverse = false) {
1543
1277
  const result = VexFirmwareVersion.fromUint8Array(new Uint8Array(this.buffer, this.byteOffset, this.byteLength), this.position, reverse);
@@ -1548,42 +1282,33 @@ class PacketView extends DataView {
1548
1282
 
1549
1283
  // src/VexPacketModels.ts
1550
1284
  var textEncoder = new TextEncoder;
1285
+ function filePayload(a, b, fileName) {
1286
+ const payload = new Uint8Array(26);
1287
+ payload[0] = a;
1288
+ payload[1] = b;
1289
+ payload.set(encodeFixedText(fileName, "Filename", 23), 2);
1290
+ return payload;
1291
+ }
1292
+ var clamp100 = (value) => value !== undefined && value > 100 ? 100 : value;
1551
1293
 
1552
1294
  class Query1H2DPacket extends DeviceBoundPacket {
1553
1295
  static COMMAND_ID = 33;
1554
1296
  static COMMAND_EXTENDED_ID = undefined;
1555
- constructor() {
1556
- super(undefined);
1557
- }
1558
1297
  }
1559
1298
 
1560
1299
  class SystemVersionH2DPacket extends DeviceBoundPacket {
1561
1300
  static COMMAND_ID = 164;
1562
1301
  static COMMAND_EXTENDED_ID = undefined;
1563
- constructor() {
1564
- super(undefined);
1565
- }
1566
1302
  }
1567
1303
 
1568
1304
  class UpdateMatchModeH2DPacket extends DeviceBoundPacket {
1569
1305
  static COMMAND_ID = 88;
1570
1306
  static COMMAND_EXTENDED_ID = 193;
1571
1307
  constructor(mode, matchClock) {
1572
- let bit1;
1573
- switch (mode) {
1574
- case "autonomous":
1575
- bit1 = 10;
1576
- break;
1577
- case "driver":
1578
- bit1 = 8;
1579
- break;
1580
- case "disabled":
1581
- bit1 = 11;
1582
- }
1308
+ const bit1 = mode === "autonomous" ? 10 : mode === "driver" ? 8 : 11;
1583
1309
  const payload = new Uint8Array(5);
1584
- const view = new DataView(payload.buffer);
1585
- payload[0] = (15 & bit1) >>> 0;
1586
- view.setUint32(1, matchClock, true);
1310
+ payload[0] = bit1 & 15;
1311
+ new DataView(payload.buffer).setUint32(1, matchClock, true);
1587
1312
  super(payload);
1588
1313
  }
1589
1314
  }
@@ -1591,18 +1316,13 @@ class UpdateMatchModeH2DPacket extends DeviceBoundPacket {
1591
1316
  class GetMatchStatusH2DPacket extends DeviceBoundPacket {
1592
1317
  static COMMAND_ID = 88;
1593
1318
  static COMMAND_EXTENDED_ID = 194;
1594
- constructor() {
1595
- super(undefined);
1596
- }
1597
1319
  }
1598
1320
 
1599
1321
  class GetRadioModeH2DPacket extends DeviceBoundPacket {
1600
1322
  static COMMAND_ID = 88;
1601
1323
  static COMMAND_EXTENDED_ID = 65;
1602
1324
  constructor(mode) {
1603
- const payload = new Uint8Array(1);
1604
- payload[0] = mode;
1605
- super(payload);
1325
+ super(Uint8Array.of(mode));
1606
1326
  }
1607
1327
  }
1608
1328
 
@@ -1610,9 +1330,7 @@ class FileControlH2DPacket extends DeviceBoundPacket {
1610
1330
  static COMMAND_ID = 86;
1611
1331
  static COMMAND_EXTENDED_ID = 16;
1612
1332
  constructor(a, b) {
1613
- const payload = new Uint8Array(2);
1614
- payload.set([a, b], 0);
1615
- super(payload);
1333
+ super(Uint8Array.of(a, b));
1616
1334
  }
1617
1335
  }
1618
1336
 
@@ -1622,25 +1340,21 @@ class InitFileTransferH2DPacket extends DeviceBoundPacket {
1622
1340
  constructor(operation, target, vendor, options, binary, addr, name, type, version = new VexFirmwareVersion(1, 0, 0, 0)) {
1623
1341
  const payload = new Uint8Array(52);
1624
1342
  const view = new DataView(payload.buffer);
1625
- view.setUint8(0, operation);
1626
- view.setUint8(1, target);
1627
- view.setUint8(2, vendor);
1628
- view.setUint8(3, options);
1343
+ payload[0] = operation;
1344
+ payload[1] = target;
1345
+ payload[2] = vendor;
1346
+ payload[3] = options;
1629
1347
  view.setUint32(4, binary.length, true);
1630
1348
  view.setUint32(8, addr, true);
1631
1349
  view.setUint32(12, operation === 1 /* WRITE */ ? Packet.ENCODER.crcgen.crc32(binary, 0) : 0, true);
1632
- const re = /(?:\.([^.]+))?$/;
1633
- const reResult = re.exec(name);
1634
- let ext = reResult != null ? reResult[1] : undefined;
1635
- ext ??= "";
1636
- ext = ext === "gz" ? "bin" : ext;
1350
+ let ext = /(?:\.([^.]+))?$/.exec(name)?.[1] ?? "";
1351
+ if (ext === "gz")
1352
+ ext = "bin";
1637
1353
  payload.set(encodeFixedText(type ?? ext, "File type", 4), 16);
1638
1354
  const timestamp = (Date.now() / 1000 >>> 0) - PacketEncoder.J2000_EPOCH;
1639
1355
  view.setUint32(20, timestamp, true);
1640
1356
  payload.set(version.toUint8Array(), 24);
1641
- const nameEncoded = encodeFixedText(name, "Filename", 23);
1642
- payload.set(nameEncoded, 28);
1643
- view.setUint8(51, 0);
1357
+ payload.set(encodeFixedText(name, "Filename", 23), 28);
1644
1358
  super(payload);
1645
1359
  }
1646
1360
  }
@@ -1649,9 +1363,7 @@ class ExitFileTransferH2DPacket extends DeviceBoundPacket {
1649
1363
  static COMMAND_ID = 86;
1650
1364
  static COMMAND_EXTENDED_ID = 18;
1651
1365
  constructor(action) {
1652
- const payload = new Uint8Array(1);
1653
- payload[0] = action;
1654
- super(payload);
1366
+ super(Uint8Array.of(action));
1655
1367
  }
1656
1368
  }
1657
1369
 
@@ -1660,8 +1372,7 @@ class WriteFileH2DPacket extends DeviceBoundPacket {
1660
1372
  static COMMAND_EXTENDED_ID = 19;
1661
1373
  constructor(addr, buf) {
1662
1374
  const payload = new Uint8Array(4 + buf.length);
1663
- const view = new DataView(payload.buffer);
1664
- view.setUint32(0, addr, true);
1375
+ new DataView(payload.buffer).setUint32(0, addr, true);
1665
1376
  payload.set(buf, 4);
1666
1377
  super(payload);
1667
1378
  }
@@ -1683,11 +1394,7 @@ class LinkFileH2DPacket extends DeviceBoundPacket {
1683
1394
  static COMMAND_ID = 86;
1684
1395
  static COMMAND_EXTENDED_ID = 21;
1685
1396
  constructor(vendor, fileName, options) {
1686
- const str = encodeFixedText(fileName, "Filename", 23);
1687
- const payload = new Uint8Array(26);
1688
- payload.set([vendor, options], 0);
1689
- payload.set(str, 2);
1690
- super(payload);
1397
+ super(filePayload(vendor, options, fileName));
1691
1398
  }
1692
1399
  }
1693
1400
 
@@ -1695,9 +1402,7 @@ class GetDirectoryFileCountH2DPacket extends DeviceBoundPacket {
1695
1402
  static COMMAND_ID = 86;
1696
1403
  static COMMAND_EXTENDED_ID = 22;
1697
1404
  constructor(vendor) {
1698
- const payload = new Uint8Array(2);
1699
- payload.set([vendor, 0], 0);
1700
- super(payload);
1405
+ super(Uint8Array.of(vendor, 0));
1701
1406
  }
1702
1407
  }
1703
1408
 
@@ -1705,9 +1410,7 @@ class GetDirectoryEntryH2DPacket extends DeviceBoundPacket {
1705
1410
  static COMMAND_ID = 86;
1706
1411
  static COMMAND_EXTENDED_ID = 23;
1707
1412
  constructor(index) {
1708
- const payload = new Uint8Array(2);
1709
- payload.set([index, 0], 0);
1710
- super(payload);
1413
+ super(Uint8Array.of(index, 0));
1711
1414
  }
1712
1415
  }
1713
1416
 
@@ -1715,17 +1418,8 @@ class LoadFileActionH2DPacket extends DeviceBoundPacket {
1715
1418
  static COMMAND_ID = 86;
1716
1419
  static COMMAND_EXTENDED_ID = 24;
1717
1420
  constructor(vendor, actionId, fileNameOrSlotNumber) {
1718
- let fileName;
1719
- if (typeof fileNameOrSlotNumber === "string") {
1720
- fileName = fileNameOrSlotNumber;
1721
- } else {
1722
- fileName = "___s_" + (fileNameOrSlotNumber - 1) + ".bin";
1723
- }
1724
- const encodedName = encodeFixedText(fileName, "Filename", 23);
1725
- const payload = new Uint8Array(26);
1726
- payload.set([vendor, actionId], 0);
1727
- payload.set(encodedName, 2);
1728
- super(payload);
1421
+ const fileName = typeof fileNameOrSlotNumber === "string" ? fileNameOrSlotNumber : `___s_${fileNameOrSlotNumber - 1}.bin`;
1422
+ super(filePayload(vendor, actionId, fileName));
1729
1423
  }
1730
1424
  }
1731
1425
 
@@ -1733,11 +1427,7 @@ class GetFileMetadataH2DPacket extends DeviceBoundPacket {
1733
1427
  static COMMAND_ID = 86;
1734
1428
  static COMMAND_EXTENDED_ID = 25;
1735
1429
  constructor(vendor, fileName, options) {
1736
- const encodedName = encodeFixedText(fileName, "Filename", 23);
1737
- const payload = new Uint8Array(26);
1738
- payload.set([vendor, options], 0);
1739
- payload.set(encodedName, 2);
1740
- super(payload);
1430
+ super(filePayload(vendor, options, fileName));
1741
1431
  }
1742
1432
  }
1743
1433
 
@@ -1745,11 +1435,7 @@ class EraseFileH2DPacket extends DeviceBoundPacket {
1745
1435
  static COMMAND_ID = 86;
1746
1436
  static COMMAND_EXTENDED_ID = 27;
1747
1437
  constructor(vendor, fileName) {
1748
- const encodedName = encodeFixedText(fileName, "Filename", 23);
1749
- const payload = new Uint8Array(26);
1750
- payload.set([vendor, 128], 0);
1751
- payload.set(encodedName, 2);
1752
- super(payload);
1438
+ super(filePayload(vendor, 128, fileName));
1753
1439
  }
1754
1440
  }
1755
1441
 
@@ -1757,11 +1443,7 @@ class GetProgramSlotInfoH2DPacket extends DeviceBoundPacket {
1757
1443
  static COMMAND_ID = 86;
1758
1444
  static COMMAND_EXTENDED_ID = 28;
1759
1445
  constructor(vendor, fileName) {
1760
- const encodedName = encodeFixedText(fileName, "Filename", 23);
1761
- const payload = new Uint8Array(26);
1762
- payload.set([vendor, 0], 0);
1763
- payload.set(encodedName, 2);
1764
- super(payload);
1446
+ super(filePayload(vendor, 0, fileName));
1765
1447
  }
1766
1448
  }
1767
1449
 
@@ -1769,9 +1451,7 @@ class FileClearUpH2DPacket extends DeviceBoundPacket {
1769
1451
  static COMMAND_ID = 86;
1770
1452
  static COMMAND_EXTENDED_ID = 30;
1771
1453
  constructor(vendor) {
1772
- const payload = new Uint8Array(2);
1773
- payload.set([vendor, 0], 0);
1774
- super(payload);
1454
+ super(Uint8Array.of(vendor, 0));
1775
1455
  }
1776
1456
  }
1777
1457
 
@@ -1779,9 +1459,7 @@ class FileFormatH2DPacket extends DeviceBoundPacket {
1779
1459
  static COMMAND_ID = 86;
1780
1460
  static COMMAND_EXTENDED_ID = 31;
1781
1461
  constructor() {
1782
- const payload = new Uint8Array(4);
1783
- payload.set([68, 67, 66, 65], 0);
1784
- super(payload);
1462
+ super(Uint8Array.of(68, 67, 66, 65));
1785
1463
  }
1786
1464
  }
1787
1465
 
@@ -1793,33 +1471,21 @@ class GetSystemFlagsH2DPacket extends DeviceBoundPacket {
1793
1471
  class GetDeviceStatusH2DPacket extends DeviceBoundPacket {
1794
1472
  static COMMAND_ID = 86;
1795
1473
  static COMMAND_EXTENDED_ID = 33;
1796
- constructor() {
1797
- super(undefined);
1798
- }
1799
1474
  }
1800
1475
 
1801
1476
  class GetSystemStatusH2DPacket extends DeviceBoundPacket {
1802
1477
  static COMMAND_ID = 86;
1803
1478
  static COMMAND_EXTENDED_ID = 34;
1804
- constructor() {
1805
- super(undefined);
1806
- }
1807
1479
  }
1808
1480
 
1809
1481
  class GetFdtStatusH2DPacket extends DeviceBoundPacket {
1810
1482
  static COMMAND_ID = 86;
1811
1483
  static COMMAND_EXTENDED_ID = 35;
1812
- constructor() {
1813
- super(undefined);
1814
- }
1815
1484
  }
1816
1485
 
1817
1486
  class GetLogCountH2DPacket extends DeviceBoundPacket {
1818
1487
  static COMMAND_ID = 86;
1819
1488
  static COMMAND_EXTENDED_ID = 36;
1820
- constructor() {
1821
- super(undefined);
1822
- }
1823
1489
  }
1824
1490
 
1825
1491
  class ReadLogPageH2DPacket extends DeviceBoundPacket {
@@ -1837,18 +1503,13 @@ class ReadLogPageH2DPacket extends DeviceBoundPacket {
1837
1503
  class GetRadioStatusH2DPacket extends DeviceBoundPacket {
1838
1504
  static COMMAND_ID = 86;
1839
1505
  static COMMAND_EXTENDED_ID = 38;
1840
- constructor() {
1841
- super(undefined);
1842
- }
1843
1506
  }
1844
1507
 
1845
1508
  class ScreenCaptureH2DPacket extends DeviceBoundPacket {
1846
1509
  static COMMAND_ID = 86;
1847
1510
  static COMMAND_EXTENDED_ID = 40;
1848
1511
  constructor(e) {
1849
- const payload = new Uint8Array(1);
1850
- payload[0] = e;
1851
- super(payload);
1512
+ super(Uint8Array.of(e));
1852
1513
  }
1853
1514
  }
1854
1515
 
@@ -1869,10 +1530,7 @@ class SelectDashH2DPacket extends DeviceBoundPacket {
1869
1530
  static COMMAND_ID = 86;
1870
1531
  static COMMAND_EXTENDED_ID = 43;
1871
1532
  constructor(screen, port) {
1872
- const payload = new Uint8Array(2);
1873
- payload[0] = screen;
1874
- payload[1] = port;
1875
- super(payload);
1533
+ super(Uint8Array.of(screen, port));
1876
1534
  }
1877
1535
  }
1878
1536
 
@@ -1880,9 +1538,8 @@ class ReadKeyValueH2DPacket extends DeviceBoundPacket {
1880
1538
  static COMMAND_ID = 86;
1881
1539
  static COMMAND_EXTENDED_ID = 46;
1882
1540
  constructor(key) {
1883
- const encodedKey = encodeFixedText(key, "Key", 31);
1884
1541
  const payload = new Uint8Array(32);
1885
- payload.set(encodedKey, 0);
1542
+ payload.set(encodeFixedText(key, "Key", 31), 0);
1886
1543
  super(payload);
1887
1544
  }
1888
1545
  }
@@ -1906,17 +1563,11 @@ class WriteKeyValueH2DPacket extends DeviceBoundPacket {
1906
1563
  class GetSlot1to4InfoH2DPacket extends DeviceBoundPacket {
1907
1564
  static COMMAND_ID = 86;
1908
1565
  static COMMAND_EXTENDED_ID = 49;
1909
- constructor() {
1910
- super(undefined);
1911
- }
1912
1566
  }
1913
1567
 
1914
1568
  class GetSlot5to8InfoH2DPacket extends DeviceBoundPacket {
1915
1569
  static COMMAND_ID = 86;
1916
1570
  static COMMAND_EXTENDED_ID = 50;
1917
- constructor() {
1918
- super(undefined);
1919
- }
1920
1571
  }
1921
1572
 
1922
1573
  class FactoryStatusH2DPacket extends DeviceBoundPacket {
@@ -1928,9 +1579,7 @@ class FactoryEnableH2DPacket extends DeviceBoundPacket {
1928
1579
  static COMMAND_ID = 86;
1929
1580
  static COMMAND_EXTENDED_ID = 255;
1930
1581
  constructor() {
1931
- const payload = new Uint8Array(4);
1932
- payload.set([77, 76, 75, 74], 0);
1933
- super(payload);
1582
+ super(Uint8Array.of(77, 76, 75, 74));
1934
1583
  }
1935
1584
  }
1936
1585
 
@@ -1972,8 +1621,7 @@ class MatchModeReplyD2HPacket extends HostBoundPacket {
1972
1621
  modebit;
1973
1622
  constructor(data) {
1974
1623
  super(data);
1975
- const dataView = PacketView.fromPacket(this);
1976
- this.modebit = dataView.nextUint8();
1624
+ this.modebit = PacketView.fromPacket(this).nextUint8();
1977
1625
  }
1978
1626
  }
1979
1627
 
@@ -1999,31 +1647,27 @@ class MatchStatusReplyD2HPacket extends HostBoundPacket {
1999
1647
  rxSignalQuality;
2000
1648
  constructor(data) {
2001
1649
  super(data);
2002
- const dataView = PacketView.fromPacket(this);
1650
+ const view = PacketView.fromPacket(this);
2003
1651
  const n = this.ackIndex;
2004
- this.rssi = dataView.nextInt8();
2005
- this.systemStatusBits = dataView.nextUint16();
2006
- this.radioStatusBits = dataView.nextUint16();
2007
- this.fieldStatusBits = dataView.nextUint8();
2008
- this.matchClock = dataView.nextUint8();
2009
- this.brainBatteryPercent = dataView.nextUint8();
2010
- this.controllerBatteryPercent = dataView.nextUint8();
2011
- this.partnerControllerBatteryPercent = dataView.nextUint8();
2012
- this.pad = dataView.nextUint8();
2013
- this.buttons = dataView.nextUint16();
2014
- this.activeProgram = dataView.nextUint8();
2015
- this.radioType = dataView.nextUint8();
2016
- this.radioChannel = dataView.nextUint8();
2017
- this.radioSlot = dataView.nextUint8();
2018
- this.robotName = dataView.nextNTBS(10);
2019
- this.controllerFlags = dataView.getUint8(n + 28);
2020
- this.rxSignalQuality = dataView.getUint8(n + 29);
2021
- let rawStr = new TextDecoder("UTF-8").decode(data.slice(n + 18, n + this.payloadSize + 28));
2022
- const endIdx = rawStr.indexOf("\x00");
2023
- if (endIdx > -1) {
2024
- rawStr = rawStr.substr(0, endIdx);
2025
- }
2026
- this.robotName = rawStr;
1652
+ this.rssi = view.nextInt8();
1653
+ this.systemStatusBits = view.nextUint16();
1654
+ this.radioStatusBits = view.nextUint16();
1655
+ this.fieldStatusBits = view.nextUint8();
1656
+ this.matchClock = view.nextUint8();
1657
+ this.brainBatteryPercent = view.nextUint8();
1658
+ this.controllerBatteryPercent = view.nextUint8();
1659
+ this.partnerControllerBatteryPercent = view.nextUint8();
1660
+ this.pad = view.nextUint8();
1661
+ this.buttons = view.nextUint16();
1662
+ this.activeProgram = view.nextUint8();
1663
+ this.radioType = view.nextUint8();
1664
+ this.radioChannel = view.nextUint8();
1665
+ this.radioSlot = view.nextUint8();
1666
+ this.controllerFlags = view.getUint8(n + 28);
1667
+ this.rxSignalQuality = view.getUint8(n + 29);
1668
+ const raw = new TextDecoder("UTF-8").decode(this.data.slice(n + 18, n + this.payloadSize + 28));
1669
+ const end = raw.indexOf("\x00");
1670
+ this.robotName = end > -1 ? raw.slice(0, end) : raw;
2027
1671
  }
2028
1672
  }
2029
1673
 
@@ -2040,10 +1684,10 @@ class InitFileTransferReplyD2HPacket extends HostBoundPacket {
2040
1684
  crc32;
2041
1685
  constructor(data) {
2042
1686
  super(data);
2043
- const dataView = PacketView.fromPacket(this);
2044
- this.windowSize = dataView.nextUint16();
2045
- this.fileSize = dataView.nextUint32();
2046
- this.crc32 = dataView.nextUint32();
1687
+ const view = PacketView.fromPacket(this);
1688
+ this.windowSize = view.nextUint16();
1689
+ this.fileSize = view.nextUint32();
1690
+ this.crc32 = view.nextUint32();
2047
1691
  }
2048
1692
  }
2049
1693
 
@@ -2065,13 +1709,10 @@ class ReadFileReplyD2HPacket extends HostBoundPacket {
2065
1709
  buf;
2066
1710
  constructor(data) {
2067
1711
  super(data);
2068
- const dataView = PacketView.fromPacket(this);
2069
- this.addr = dataView.nextUint32();
1712
+ const view = PacketView.fromPacket(this);
1713
+ this.addr = view.nextUint32();
2070
1714
  this.length = this.payloadSize - 8;
2071
- this.buf = this.data.slice(dataView.position, dataView.position + this.length).buffer;
2072
- }
2073
- static isValidPacket(data, n) {
2074
- return super.isValidPacket(data, n);
1715
+ this.buf = this.data.slice(view.position, view.position + this.length).buffer;
2075
1716
  }
2076
1717
  }
2077
1718
 
@@ -2086,8 +1727,7 @@ class GetDirectoryFileCountReplyD2HPacket extends HostBoundPacket {
2086
1727
  count;
2087
1728
  constructor(data) {
2088
1729
  super(data);
2089
- const dataView = PacketView.fromPacket(this);
2090
- this.count = dataView.nextUint16();
1730
+ this.count = PacketView.fromPacket(this).nextUint16();
2091
1731
  }
2092
1732
  }
2093
1733
 
@@ -2097,19 +1737,19 @@ class GetDirectoryEntryReplyD2HPacket extends HostBoundPacket {
2097
1737
  file;
2098
1738
  constructor(data) {
2099
1739
  super(data);
2100
- const dataView = PacketView.fromPacket(this);
2101
- if (this.payloadSize > 4) {
2102
- this.file = {
2103
- index: dataView.nextUint8(),
2104
- size: dataView.nextUint32(),
2105
- loadAddress: dataView.nextUint32(),
2106
- crc32: dataView.nextUint32(),
2107
- type: dataView.nextString(4),
2108
- timestamp: dataView.nextUint32() + PacketEncoder.J2000_EPOCH,
2109
- version: dataView.nextVersion(),
2110
- filename: dataView.nextNTBS(32)
2111
- };
2112
- }
1740
+ if (this.payloadSize <= 4)
1741
+ return;
1742
+ const view = PacketView.fromPacket(this);
1743
+ this.file = {
1744
+ index: view.nextUint8(),
1745
+ size: view.nextUint32(),
1746
+ loadAddress: view.nextUint32(),
1747
+ crc32: view.nextUint32(),
1748
+ type: view.nextString(4),
1749
+ timestamp: view.nextUint32() + PacketEncoder.J2000_EPOCH,
1750
+ version: view.nextVersion(),
1751
+ filename: view.nextNTBS(32)
1752
+ };
2113
1753
  }
2114
1754
  }
2115
1755
 
@@ -2124,18 +1764,18 @@ class GetFileMetadataReplyD2HPacket extends HostBoundPacket {
2124
1764
  file;
2125
1765
  constructor(data) {
2126
1766
  super(data);
2127
- const dataView = PacketView.fromPacket(this);
2128
- dataView.nextUint8();
2129
- if (this.payloadSize > 4) {
2130
- this.file = {
2131
- size: dataView.nextUint32(),
2132
- loadAddress: dataView.nextUint32(),
2133
- crc32: dataView.nextUint32(),
2134
- type: dataView.nextString(4),
2135
- timestamp: dataView.nextUint32() + PacketEncoder.J2000_EPOCH,
2136
- version: dataView.nextVersion()
2137
- };
2138
- }
1767
+ if (this.payloadSize <= 4)
1768
+ return;
1769
+ const view = PacketView.fromPacket(this);
1770
+ view.nextUint8();
1771
+ this.file = {
1772
+ size: view.nextUint32(),
1773
+ loadAddress: view.nextUint32(),
1774
+ crc32: view.nextUint32(),
1775
+ type: view.nextString(4),
1776
+ timestamp: view.nextUint32() + PacketEncoder.J2000_EPOCH,
1777
+ version: view.nextVersion()
1778
+ };
2139
1779
  }
2140
1780
  }
2141
1781
 
@@ -2151,9 +1791,9 @@ class GetProgramSlotInfoReplyD2HPacket extends HostBoundPacket {
2151
1791
  slot;
2152
1792
  constructor(data) {
2153
1793
  super(data);
2154
- const dataView = PacketView.fromPacket(this);
2155
- this.slot = dataView.nextUint8();
2156
- this.requestedSlot = dataView.nextUint8();
1794
+ const view = PacketView.fromPacket(this);
1795
+ this.slot = view.nextUint8();
1796
+ this.requestedSlot = view.nextUint8();
2157
1797
  }
2158
1798
  }
2159
1799
 
@@ -2171,40 +1811,32 @@ class GetSystemFlagsReplyD2HPacket extends HostBoundPacket {
2171
1811
  static COMMAND_ID = 86;
2172
1812
  static COMMAND_EXTENDED_ID = 32;
2173
1813
  flags;
2174
- radioSearching;
1814
+ radioSearching = false;
2175
1815
  radioQuality;
2176
1816
  controllerBatteryPercent;
2177
1817
  partnerControllerBatteryPercent;
2178
1818
  battery;
2179
- currentProgram;
1819
+ currentProgram = 0;
2180
1820
  constructor(data) {
2181
1821
  super(data);
2182
- const dataView = PacketView.fromPacket(this);
2183
- this.radioSearching = false;
2184
- this.currentProgram = 0;
2185
- this.flags = dataView.nextUint32();
1822
+ const view = PacketView.fromPacket(this);
1823
+ this.flags = view.nextUint32();
2186
1824
  const hasPartner = (8192 & this.flags) !== 0;
2187
1825
  const hasRadio = (1536 & this.flags) === 1536;
2188
- const byte1 = dataView.nextUint8();
2189
- const byte2 = dataView.nextUint8();
1826
+ const byte1 = view.nextUint8();
1827
+ const byte2 = view.nextUint8();
2190
1828
  if (this.payloadSize === 11) {
2191
- this.battery = 8 * (byte1 & 15);
2192
- if ((this.flags & 256) !== 0 || hasRadio)
2193
- this.controllerBatteryPercent = 8 * (byte1 >> 4 & 15);
1829
+ this.battery = clamp100(8 * (byte1 & 15));
1830
+ if ((this.flags & 256) !== 0 || hasRadio) {
1831
+ this.controllerBatteryPercent = clamp100(8 * (byte1 >> 4 & 15));
1832
+ }
2194
1833
  if (hasRadio)
2195
- this.radioQuality = 8 * (byte2 & 15);
1834
+ this.radioQuality = clamp100(8 * (byte2 & 15));
2196
1835
  this.radioSearching = (this.flags & 1536) === 512;
2197
- if (hasPartner)
2198
- this.partnerControllerBatteryPercent = 8 * (byte2 >> 4 & 15);
2199
- this.currentProgram = dataView.nextUint8();
2200
- if (this.battery != null && this.battery > 100)
2201
- this.battery = 100;
2202
- if (this.controllerBatteryPercent != null && this.controllerBatteryPercent > 100)
2203
- this.controllerBatteryPercent = 100;
2204
- if (this.radioQuality != null && this.radioQuality > 100)
2205
- this.radioQuality = 100;
2206
- if (this.partnerControllerBatteryPercent != null && this.partnerControllerBatteryPercent > 100)
2207
- this.partnerControllerBatteryPercent = 100;
1836
+ if (hasPartner) {
1837
+ this.partnerControllerBatteryPercent = clamp100(8 * (byte2 >> 4 & 15));
1838
+ }
1839
+ this.currentProgram = view.nextUint8();
2208
1840
  }
2209
1841
  }
2210
1842
  }
@@ -2216,17 +1848,17 @@ class GetDeviceStatusReplyD2HPacket extends HostBoundPacket {
2216
1848
  devices;
2217
1849
  constructor(data) {
2218
1850
  super(data);
2219
- const dataView = PacketView.fromPacket(this);
2220
- this.count = dataView.nextUint8();
1851
+ const view = PacketView.fromPacket(this);
1852
+ this.count = view.nextUint8();
2221
1853
  this.devices = [];
2222
1854
  for (let i = 0;i < this.count; i++) {
2223
1855
  this.devices.push({
2224
- port: dataView.nextUint8(),
2225
- type: dataView.nextUint8(),
2226
- status: dataView.nextUint8(),
2227
- betaversion: dataView.nextUint8(),
2228
- version: dataView.nextUint16(),
2229
- bootversion: dataView.nextUint16()
1856
+ port: view.nextUint8(),
1857
+ type: view.nextUint8(),
1858
+ status: view.nextUint8(),
1859
+ betaversion: view.nextUint8(),
1860
+ version: view.nextUint16(),
1861
+ bootversion: view.nextUint16()
2230
1862
  });
2231
1863
  }
2232
1864
  }
@@ -2238,48 +1870,42 @@ class GetSystemStatusReplyD2HPacket extends HostBoundPacket {
2238
1870
  systemVersion;
2239
1871
  cpu0Version;
2240
1872
  cpu1Version;
2241
- nxpVersion;
1873
+ nxpVersion = VexFirmwareVersion.allZero();
2242
1874
  touchVersion;
2243
- uniqueId;
2244
- sysflags;
2245
- eventBrain;
2246
- romBootloaderActive;
2247
- ramBootloaderActive;
2248
- goldenVersion;
1875
+ uniqueId = 1234;
1876
+ sysflags = [0, 0, 0, 0, 0, 0, 0];
1877
+ eventBrain = false;
1878
+ romBootloaderActive = false;
1879
+ ramBootloaderActive = false;
1880
+ goldenVersion = VexFirmwareVersion.allZero();
2249
1881
  constructor(data) {
2250
1882
  super(data);
2251
- const dataView = PacketView.fromPacket(this);
2252
- dataView.nextUint8();
2253
- this.systemVersion = dataView.nextVersion();
2254
- this.cpu0Version = dataView.nextVersion();
2255
- this.cpu1Version = dataView.nextVersion();
2256
- this.touchVersion = dataView.nextVersion(true);
2257
- this.uniqueId = 1234;
2258
- this.sysflags = [0, 0, 0, 0, 0, 0, 0];
2259
- this.goldenVersion = VexFirmwareVersion.allZero();
2260
- this.nxpVersion = VexFirmwareVersion.allZero();
2261
- this.eventBrain = false;
2262
- this.romBootloaderActive = false;
2263
- this.ramBootloaderActive = false;
1883
+ const view = PacketView.fromPacket(this);
1884
+ view.nextUint8();
1885
+ this.systemVersion = view.nextVersion();
1886
+ this.cpu0Version = view.nextVersion();
1887
+ this.cpu1Version = view.nextVersion();
1888
+ this.touchVersion = view.nextVersion(true);
2264
1889
  if (this.payloadSize > 25) {
2265
- this.uniqueId = dataView.nextUint32();
1890
+ this.uniqueId = view.nextUint32();
2266
1891
  this.sysflags = [
2267
- dataView.nextUint8(),
2268
- dataView.nextUint8(),
2269
- dataView.nextUint8(),
2270
- dataView.nextUint8(),
2271
- dataView.nextUint8(),
1892
+ view.nextUint8(),
1893
+ view.nextUint8(),
1894
+ view.nextUint8(),
1895
+ view.nextUint8(),
1896
+ view.nextUint8(),
2272
1897
  0,
2273
- dataView.nextUint8()
1898
+ view.nextUint8()
2274
1899
  ];
2275
- this.eventBrain = (1 & this.sysflags[6]) !== 0;
2276
- this.romBootloaderActive = (2 & this.sysflags[6]) !== 0;
2277
- this.ramBootloaderActive = (4 & this.sysflags[6]) !== 0;
2278
- dataView.nextUint16();
2279
- this.goldenVersion = dataView.nextVersion();
1900
+ const flags6 = this.sysflags[6];
1901
+ this.eventBrain = (1 & flags6) !== 0;
1902
+ this.romBootloaderActive = (2 & flags6) !== 0;
1903
+ this.ramBootloaderActive = (4 & flags6) !== 0;
1904
+ view.nextUint16();
1905
+ this.goldenVersion = view.nextVersion();
2280
1906
  }
2281
1907
  if (this.payloadSize > 37) {
2282
- this.nxpVersion = dataView.nextVersion();
1908
+ this.nxpVersion = view.nextVersion();
2283
1909
  }
2284
1910
  }
2285
1911
  }
@@ -2291,17 +1917,17 @@ class GetFdtStatusReplyD2HPacket extends HostBoundPacket {
2291
1917
  status;
2292
1918
  constructor(data) {
2293
1919
  super(data);
2294
- const dataView = PacketView.fromPacket(this);
2295
- this.count = dataView.nextUint8();
1920
+ const view = PacketView.fromPacket(this);
1921
+ this.count = view.nextUint8();
2296
1922
  this.status = [];
2297
1923
  for (let i = 0;i < this.count; i++) {
2298
1924
  this.status.push({
2299
- index: dataView.nextUint8(),
2300
- type: dataView.nextUint8(),
2301
- status: dataView.nextUint8(),
2302
- betaversion: dataView.nextUint8(),
2303
- version: dataView.nextUint16(),
2304
- bootversion: dataView.nextUint16()
1925
+ index: view.nextUint8(),
1926
+ type: view.nextUint8(),
1927
+ status: view.nextUint8(),
1928
+ betaversion: view.nextUint8(),
1929
+ version: view.nextUint16(),
1930
+ bootversion: view.nextUint16()
2305
1931
  });
2306
1932
  }
2307
1933
  }
@@ -2313,9 +1939,9 @@ class GetLogCountReplyD2HPacket extends HostBoundPacket {
2313
1939
  count;
2314
1940
  constructor(data) {
2315
1941
  super(data);
2316
- const dataView = PacketView.fromPacket(this);
2317
- dataView.nextUint8();
2318
- this.count = dataView.nextUint32();
1942
+ const view = PacketView.fromPacket(this);
1943
+ view.nextUint8();
1944
+ this.count = view.nextUint32();
2319
1945
  }
2320
1946
  }
2321
1947
 
@@ -2327,20 +1953,19 @@ class ReadLogPageReplyD2HPacket extends HostBoundPacket {
2327
1953
  entries;
2328
1954
  constructor(data) {
2329
1955
  super(data);
2330
- const dataView = PacketView.fromPacket(this);
2331
- const n = this.ackIndex;
2332
- const size = dataView.nextUint8();
2333
- this.offset = dataView.nextUint32();
2334
- this.count = dataView.nextUint16();
1956
+ const view = PacketView.fromPacket(this);
1957
+ const size = view.nextUint8();
1958
+ this.offset = view.nextUint32();
1959
+ this.count = view.nextUint16();
2335
1960
  this.entries = [];
2336
- let j = n + 8;
1961
+ let j = this.ackIndex + 8;
2337
1962
  for (let i = 0;i < this.count; i++) {
2338
1963
  this.entries.push({
2339
- code: dataView.getUint8(j),
2340
- type: dataView.getUint8(j + 1),
2341
- desc: dataView.getUint8(j + 2),
2342
- spare: dataView.getUint8(j + 3),
2343
- time: dataView.getUint32(j + 4, true)
1964
+ code: view.getUint8(j),
1965
+ type: view.getUint8(j + 1),
1966
+ desc: view.getUint8(j + 2),
1967
+ spare: view.getUint8(j + 3),
1968
+ time: view.getUint32(j + 4, true)
2344
1969
  });
2345
1970
  j += size;
2346
1971
  }
@@ -2357,13 +1982,12 @@ class GetRadioStatusReplyD2HPacket extends HostBoundPacket {
2357
1982
  timeslot;
2358
1983
  constructor(data) {
2359
1984
  super(data);
2360
- const dataView = PacketView.fromPacket(this);
2361
- const n = this.ackIndex;
2362
- this.device = dataView.nextUint8();
2363
- this.quality = dataView.nextUint16();
2364
- this.strength = dataView.nextInt16();
2365
- this.channel = this.data[n + 6];
2366
- this.timeslot = this.data[n + 7];
1985
+ const view = PacketView.fromPacket(this);
1986
+ this.device = view.nextUint8();
1987
+ this.quality = view.nextUint16();
1988
+ this.strength = view.nextInt16();
1989
+ this.channel = this.data[this.ackIndex + 6];
1990
+ this.timeslot = this.data[this.ackIndex + 7];
2367
1991
  }
2368
1992
  }
2369
1993
 
@@ -2388,8 +2012,7 @@ class ReadKeyValueReplyD2HPacket extends HostBoundPacket {
2388
2012
  value;
2389
2013
  constructor(data) {
2390
2014
  super(data);
2391
- const dataView = PacketView.fromPacket(this);
2392
- this.value = dataView.nextVarNTBS(255);
2015
+ this.value = PacketView.fromPacket(this).nextVarNTBS(255);
2393
2016
  }
2394
2017
  }
2395
2018
 
@@ -2405,20 +2028,18 @@ class GetSlot1to4InfoReplyD2HPacket extends HostBoundPacket {
2405
2028
  slots;
2406
2029
  constructor(data, start = 1) {
2407
2030
  super(data);
2408
- const dataView = PacketView.fromPacket(this);
2409
- this.slotFlags = dataView.nextUint8();
2031
+ const view = PacketView.fromPacket(this);
2032
+ this.slotFlags = view.nextUint8();
2410
2033
  this.slots = [];
2411
2034
  for (let i = 0;i < 4; i++) {
2412
- const hasData = (this.slotFlags & 2 ** (start - 1 + i)) !== 0;
2413
- if (!hasData)
2035
+ if ((this.slotFlags & 1 << start - 1 + i) === 0)
2414
2036
  continue;
2415
- const iconNum = dataView.nextUint16();
2416
- const nameLen = dataView.nextUint8();
2417
- const name = dataView.nextString(nameLen);
2037
+ const icon = view.nextUint16();
2038
+ const nameLen = view.nextUint8();
2418
2039
  this.slots.push({
2419
2040
  slot: start + i,
2420
- icon: iconNum,
2421
- name
2041
+ icon,
2042
+ name: view.nextString(nameLen)
2422
2043
  });
2423
2044
  }
2424
2045
  }
@@ -2440,9 +2061,9 @@ class FactoryStatusReplyD2HPacket extends HostBoundPacket {
2440
2061
  percent;
2441
2062
  constructor(data) {
2442
2063
  super(data);
2443
- const dataView = PacketView.fromPacket(this);
2444
- this.status = dataView.nextUint8();
2445
- this.percent = dataView.nextUint8();
2064
+ const view = PacketView.fromPacket(this);
2065
+ this.status = view.nextUint8();
2066
+ this.percent = view.nextUint8();
2446
2067
  }
2447
2068
  }
2448
2069
 
@@ -2453,6 +2074,7 @@ class FactoryEnableReplyD2HPacket extends HostBoundPacket {
2453
2074
 
2454
2075
  // src/VexPacketEncoder.ts
2455
2076
  var textEncoder2 = new TextEncoder;
2077
+ var HEADER_TO_DEVICE = Uint8Array.of(201, 54, 184, 71);
2456
2078
  function encodeFixedText(value, field, maxBytes) {
2457
2079
  const encoded = textEncoder2.encode(value);
2458
2080
  if (encoded.byteLength > maxBytes) {
@@ -2466,92 +2088,96 @@ class PacketEncoder {
2466
2088
  static HEADER_TO_DEVICE = [201, 54, 184, 71];
2467
2089
  static HEADER_TO_HOST = [170, 85];
2468
2090
  static J2000_EPOCH = 946684800;
2469
- vexVersion;
2470
- crcgen;
2471
- allPacketsTable = {};
2091
+ vexVersion = 0;
2092
+ crcgen = new CrcGenerator;
2093
+ allPacketsTable = new Map;
2472
2094
  static getInstance() {
2473
- if (Packet.ENCODER === undefined) {
2474
- Packet.ENCODER = new PacketEncoder;
2475
- }
2095
+ Packet.ENCODER ??= new PacketEncoder;
2476
2096
  return Packet.ENCODER;
2477
2097
  }
2478
2098
  constructor() {
2479
- this.vexVersion = 0;
2480
- this.crcgen = new CrcGenerator;
2481
- Object.values(exports_VexPacketModels).forEach((packet) => {
2099
+ for (const packet of Object.values(exports_VexPacketModels)) {
2482
2100
  if (typeof packet === "function" && packet.prototype instanceof HostBoundPacket) {
2483
- const packetType = packet;
2484
- this.allPacketsTable[packetType.COMMAND_ID + " " + packetType.COMMAND_EXTENDED_ID] = packetType;
2101
+ const type = packet;
2102
+ let byExtendedId = this.allPacketsTable.get(type.COMMAND_ID);
2103
+ if (byExtendedId === undefined) {
2104
+ byExtendedId = new Map;
2105
+ this.allPacketsTable.set(type.COMMAND_ID, byExtendedId);
2106
+ }
2107
+ byExtendedId.set(type.COMMAND_EXTENDED_ID, type);
2485
2108
  }
2486
- });
2109
+ }
2110
+ }
2111
+ getPacketType(commandId, commandExtendedId) {
2112
+ if (commandId === undefined)
2113
+ return;
2114
+ return this.allPacketsTable.get(commandId)?.get(commandExtendedId);
2487
2115
  }
2488
2116
  createHeader(buf) {
2489
2117
  if (buf === undefined || buf.byteLength < PacketEncoder.HEADERS_LENGTH) {
2490
2118
  buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH);
2491
2119
  }
2492
2120
  const h = new Uint8Array(buf);
2493
- h.set(PacketEncoder.HEADER_TO_DEVICE);
2121
+ h.set(HEADER_TO_DEVICE);
2494
2122
  return h;
2495
2123
  }
2496
2124
  cdcCommand(cmd) {
2497
- const buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH + 1);
2498
- const h = this.createHeader(buf);
2499
- h.set([cmd], PacketEncoder.HEADERS_LENGTH);
2125
+ const h = new Uint8Array(5);
2126
+ h.set(HEADER_TO_DEVICE);
2127
+ h[4] = cmd;
2500
2128
  return h;
2501
2129
  }
2502
2130
  cdcCommandWithData(cmd, data) {
2503
- const buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH + 2 + data.length);
2504
- const h = this.createHeader(buf);
2505
- h.set([cmd, data.length], PacketEncoder.HEADERS_LENGTH);
2506
- h.set(data, PacketEncoder.HEADERS_LENGTH + 2);
2131
+ const h = new Uint8Array(6 + data.length);
2132
+ h.set(HEADER_TO_DEVICE);
2133
+ h[4] = cmd;
2134
+ h[5] = data.length;
2135
+ h.set(data, 6);
2507
2136
  return h;
2508
2137
  }
2509
2138
  cdc2Command(cmd, ext) {
2510
- const buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH + 5);
2511
- const h = this.createHeader(buf);
2512
- h.set([cmd, ext, 0], PacketEncoder.HEADERS_LENGTH);
2513
- const crc = this.crcgen.crc16(h.subarray(0, buf.byteLength - 2), 0) >>> 0;
2514
- h.set([crc >>> 8, crc & 255], buf.byteLength - 2);
2139
+ const h = new Uint8Array(9);
2140
+ h.set(HEADER_TO_DEVICE);
2141
+ h[4] = cmd;
2142
+ h[5] = ext;
2143
+ h[6] = 0;
2144
+ this.appendCrc16(h);
2515
2145
  return h;
2516
2146
  }
2517
2147
  cdc2CommandBufferLength(data) {
2518
- let length = PacketEncoder.HEADERS_LENGTH + data.length + 3 + 2;
2519
- if (data.length > 127)
2520
- length += 1;
2521
- return length;
2148
+ return PacketEncoder.HEADERS_LENGTH + data.length + 5 + (data.length > 127 ? 1 : 0);
2522
2149
  }
2523
2150
  cdc2CommandWithData(cmd, ext, data) {
2524
- const buf = new ArrayBuffer(this.cdc2CommandBufferLength(data));
2525
- const h = this.createHeader(buf);
2151
+ const h = new Uint8Array(this.cdc2CommandBufferLength(data));
2152
+ h.set(HEADER_TO_DEVICE);
2153
+ h[4] = cmd;
2154
+ h[5] = ext;
2526
2155
  if (data.length < 128) {
2527
- h.set([cmd, ext, data.length], PacketEncoder.HEADERS_LENGTH);
2528
- h.set(data, PacketEncoder.HEADERS_LENGTH + 3);
2156
+ h[6] = data.length;
2157
+ h.set(data, 7);
2529
2158
  } else {
2530
- const lengthMsb = (data.length >>> 8 | 128) >>> 0;
2531
- const lengthLsb = (data.length & 255) >>> 0;
2532
- h.set([cmd, ext, lengthMsb, lengthLsb], PacketEncoder.HEADERS_LENGTH);
2533
- h.set(data, PacketEncoder.HEADERS_LENGTH + 4);
2159
+ h[6] = data.length >>> 8 | 128;
2160
+ h[7] = data.length & 255;
2161
+ h.set(data, 8);
2534
2162
  }
2535
- const crc = this.crcgen.crc16(h.subarray(0, buf.byteLength - 2), 0);
2536
- h.set([crc >>> 8, crc & 255], buf.byteLength - 2);
2163
+ this.appendCrc16(h);
2537
2164
  return h;
2538
2165
  }
2166
+ appendCrc16(h) {
2167
+ const crc = this.crcgen.crc16(h.subarray(0, h.length - 2), 0);
2168
+ h[h.length - 2] = crc >>> 8;
2169
+ h[h.length - 1] = crc & 255;
2170
+ }
2539
2171
  validateHeader(data) {
2540
- return !(data[0] !== PacketEncoder.HEADER_TO_HOST[0] || data[1] !== PacketEncoder.HEADER_TO_HOST[1]);
2172
+ return data[0] === PacketEncoder.HEADER_TO_HOST[0] && data[1] === PacketEncoder.HEADER_TO_HOST[1];
2541
2173
  }
2542
2174
  validateMessageCdc(data) {
2543
- const message = data.subarray(0, data.byteLength - 2);
2544
- const lastTwoBytes = (data[data.byteLength - 2] << 8) + data[data.byteLength - 1];
2545
- return this.crcgen.crc16(message, 0) === lastTwoBytes;
2175
+ const crc = (data[data.byteLength - 2] << 8) + data[data.byteLength - 1];
2176
+ return this.crcgen.crc16(data.subarray(0, data.byteLength - 2), 0) === crc;
2546
2177
  }
2547
2178
  getPayloadSize(data) {
2548
- let t = 0;
2549
- let a = data[3];
2550
- if ((128 & a) !== 0) {
2551
- t = 127 & a;
2552
- a = data[4];
2553
- }
2554
- return (t << 8) + a;
2179
+ const a = data[3];
2180
+ return (a & 128) === 0 ? a : ((a & 127) << 8) + data[4];
2555
2181
  }
2556
2182
  getHostHeaderLength(data) {
2557
2183
  return (data[3] & 128) === 0 ? 4 : 5;
@@ -2588,6 +2214,9 @@ class VexSerialConnection extends VexEventTarget {
2588
2214
  super();
2589
2215
  this.serial = serial;
2590
2216
  }
2217
+ reportWarning(message, details) {
2218
+ this.emit("warning", { message, details });
2219
+ }
2591
2220
  async close() {
2592
2221
  if (this._closePromise)
2593
2222
  return this._closePromise;
@@ -2650,7 +2279,7 @@ class VexSerialConnection extends VexEventTarget {
2650
2279
  try {
2651
2280
  await port.close();
2652
2281
  } catch (e) {
2653
- console.warn("Close port error.", e);
2282
+ this.reportWarning("failed to close the serial port", e);
2654
2283
  }
2655
2284
  }
2656
2285
  if (this._wasConnected) {
@@ -2659,29 +2288,28 @@ class VexSerialConnection extends VexEventTarget {
2659
2288
  }
2660
2289
  }
2661
2290
  open(use = 0, askUser = true) {
2662
- if (this.port !== undefined) {
2663
- return errAsyncVex(new VexIoError("Already connected."));
2664
- }
2665
2291
  return new import_neverthrow.ResultAsync(this._open(use, askUser));
2666
2292
  }
2667
2293
  async _open(use, askUser) {
2668
- let port;
2669
- if (use !== undefined) {
2670
- const ports = (await this.serial.getPorts()).filter((p) => {
2671
- const info = p.getInfo();
2672
- return this.filters.find((f) => (f.usbVendorId === undefined || f.usbVendorId === info.usbVendorId) && (f.usbProductId === undefined || f.usbProductId === info.usbProductId));
2673
- }).filter((candidate) => candidate.readable === null);
2674
- port = ports[use];
2294
+ if (this._closePromise !== null)
2295
+ await this._closePromise;
2296
+ if (this.port !== undefined) {
2297
+ return import_neverthrow.err(new VexIoError("Already connected."));
2675
2298
  }
2299
+ const ports = (await this.serial.getPorts()).filter((p) => {
2300
+ const info = p.getInfo();
2301
+ return this.filters.find((f) => (f.usbVendorId === undefined || f.usbVendorId === info.usbVendorId) && (f.usbProductId === undefined || f.usbProductId === info.usbProductId));
2302
+ }).filter((candidate) => candidate.readable === null);
2303
+ let port = ports[use];
2676
2304
  if (port == null && askUser) {
2677
2305
  try {
2678
2306
  port = await this.serial.requestPort({ filters: this.filters });
2679
2307
  } catch {}
2680
2308
  }
2681
2309
  if (port == null)
2682
- return import_neverthrow.ok(undefined);
2310
+ return import_neverthrow.ok("no-port");
2683
2311
  if (port.readable != null)
2684
- return import_neverthrow.ok(false);
2312
+ return import_neverthrow.ok("busy");
2685
2313
  try {
2686
2314
  this.port = port;
2687
2315
  await port.open({ baudRate: 115200 });
@@ -2694,15 +2322,12 @@ class VexSerialConnection extends VexEventTarget {
2694
2322
  this.startReader();
2695
2323
  this._wasConnected = true;
2696
2324
  this.emit("connected", undefined);
2697
- return import_neverthrow.ok(true);
2698
- } catch {
2325
+ return import_neverthrow.ok("opened");
2326
+ } catch (e) {
2699
2327
  await this.close();
2700
- return import_neverthrow.ok(false);
2328
+ return import_neverthrow.err(toVexSerialError(e, "io"));
2701
2329
  }
2702
2330
  }
2703
- writeData(rawData, resolve, timeout = 1000) {
2704
- this.writeDataAsync(rawData, timeout).then(resolve);
2705
- }
2706
2331
  async writeDataAsync(rawData, timeout = 1000) {
2707
2332
  return new Promise((resolve) => {
2708
2333
  if (this.writer === undefined) {
@@ -2733,6 +2358,14 @@ class VexSerialConnection extends VexEventTarget {
2733
2358
  });
2734
2359
  });
2735
2360
  }
2361
+ request(packet, ReplyType, timeout = 1000) {
2362
+ return new import_neverthrow.ResultAsync((async () => {
2363
+ const result = await this.writeDataAsync(packet, timeout);
2364
+ if (result instanceof ReplyType)
2365
+ return import_neverthrow.ok(result);
2366
+ return import_neverthrow.err(new VexProtocolError(expectedReplyMessage(packet, ReplyType, result), typeof result === "number" ? result : undefined));
2367
+ })());
2368
+ }
2736
2369
  async readData(cache, expectedSize) {
2737
2370
  if (this.reader == null)
2738
2371
  throw new Error("No reader");
@@ -2773,39 +2406,56 @@ class VexSerialConnection extends VexEventTarget {
2773
2406
  if (!thePacketEncoder.validateMessageCdc(cache))
2774
2407
  throw new Error("Invalid message CDC");
2775
2408
  }
2776
- let callbackInfo;
2777
- let wantedCmdId;
2778
- let wantedCmdExId;
2779
- let tryIdx = 0;
2780
- while ((callbackInfo = this.callbacksQueue[tryIdx++]) !== undefined) {
2781
- wantedCmdId = callbackInfo?.wantedCommandId;
2782
- wantedCmdExId = callbackInfo?.wantedCommandExId;
2783
- if (wantedCmdId !== undefined && wantedCmdId !== cmdId || wantedCmdExId !== undefined && wantedCmdExId !== cmdExId) {
2409
+ let matchIdx = -1;
2410
+ let untypedIdx = -1;
2411
+ for (let i = 0;i < this.callbacksQueue.length; i++) {
2412
+ const candidate = this.callbacksQueue[i];
2413
+ if (candidate.wantedCommandId === undefined && candidate.wantedCommandExId === undefined) {
2414
+ if (untypedIdx === -1)
2415
+ untypedIdx = i;
2784
2416
  continue;
2785
2417
  }
2786
- break;
2418
+ if ((candidate.wantedCommandId === undefined || candidate.wantedCommandId === cmdId) && (candidate.wantedCommandExId === undefined || candidate.wantedCommandExId === cmdExId)) {
2419
+ matchIdx = i;
2420
+ break;
2421
+ }
2787
2422
  }
2788
- if (callbackInfo === undefined) {
2789
- console.warn("Unexpected command", cmdId, cmdExId, ack);
2423
+ if (matchIdx === -1)
2424
+ matchIdx = untypedIdx;
2425
+ if (matchIdx === -1) {
2426
+ this.reportWarning("received a reply with no matching request", {
2427
+ commandId: cmdId,
2428
+ commandExtendedId: cmdExId,
2429
+ ack
2430
+ });
2790
2431
  continue;
2791
2432
  }
2433
+ const callbackInfo = this.callbacksQueue[matchIdx];
2434
+ const wantedCmdId = callbackInfo.wantedCommandId;
2435
+ const wantedCmdExId = callbackInfo.wantedCommandExId;
2792
2436
  const data = cache.slice(0, sliceIdx);
2793
- const PackageType = thePacketEncoder.allPacketsTable[wantedCmdId + " " + wantedCmdExId];
2794
- if (wantedCmdId === undefined && wantedCmdExId === undefined || PackageType === undefined) {
2437
+ const PackageType = thePacketEncoder.getPacketType(wantedCmdId, wantedCmdExId);
2438
+ if (wantedCmdId === undefined || PackageType === undefined) {
2439
+ if (wantedCmdId !== undefined) {
2440
+ this.reportWarning("no packet class is registered for the wanted command", { commandId: wantedCmdId, commandExtendedId: wantedCmdExId });
2441
+ }
2795
2442
  callbackInfo.callback(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));
2796
2443
  } else {
2797
2444
  if (!hasExtId || PackageType.isValidPacket(data, n)) {
2798
2445
  callbackInfo.callback(new PackageType(data));
2799
2446
  } else {
2800
- console.warn("ack", ack);
2447
+ this.reportWarning("reply failed packet validation; delivering its ack instead", { commandId: cmdId, commandExtendedId: cmdExId, ack });
2801
2448
  callbackInfo.callback(ack);
2802
2449
  }
2803
2450
  }
2804
2451
  clearTimeout(callbackInfo.timeout);
2805
- this.callbacksQueue.splice(tryIdx - 1, 1);
2452
+ this.callbacksQueue.splice(matchIdx, 1);
2806
2453
  } catch (e) {
2807
2454
  if (!(e instanceof Error && e.message === "No data")) {
2808
- console.warn("Read error.", e, cache);
2455
+ this.reportWarning("reader loop stopped by a read error", {
2456
+ error: e,
2457
+ pendingBytes: cache
2458
+ });
2809
2459
  }
2810
2460
  await this.close();
2811
2461
  break;
@@ -2814,19 +2464,10 @@ class VexSerialConnection extends VexEventTarget {
2814
2464
  }
2815
2465
  }
2816
2466
  query1() {
2817
- return new import_neverthrow.ResultAsync((async () => {
2818
- const result = await this.writeDataAsync(new Query1H2DPacket, 100);
2819
- return result instanceof Query1ReplyD2HPacket ? import_neverthrow.ok(result) : import_neverthrow.err(new VexProtocolError("query1 was not acknowledged"));
2820
- })());
2467
+ return this.request(new Query1H2DPacket, Query1ReplyD2HPacket, 100);
2821
2468
  }
2822
2469
  getSystemVersion() {
2823
- return new import_neverthrow.ResultAsync((async () => {
2824
- const result = await this.writeDataAsync(new SystemVersionH2DPacket);
2825
- if (result instanceof SystemVersionReplyD2HPacket) {
2826
- return import_neverthrow.ok(result.version);
2827
- }
2828
- return import_neverthrow.err(new VexProtocolError("system version was not acknowledged"));
2829
- })());
2470
+ return this.request(new SystemVersionH2DPacket, SystemVersionReplyD2HPacket).map((result) => result.version);
2830
2471
  }
2831
2472
  }
2832
2473
 
@@ -2853,34 +2494,19 @@ class V5SerialConnection extends VexSerialConnection {
2853
2494
  }
2854
2495
  }
2855
2496
  getDeviceStatus() {
2856
- return new import_neverthrow.ResultAsync((async () => {
2857
- const result = await this.writeDataAsync(new GetDeviceStatusH2DPacket);
2858
- return result instanceof GetDeviceStatusReplyD2HPacket ? import_neverthrow.ok(result) : import_neverthrow.err(new VexProtocolError("device status was not acknowledged"));
2859
- })());
2497
+ return this.request(new GetDeviceStatusH2DPacket, GetDeviceStatusReplyD2HPacket);
2860
2498
  }
2861
2499
  getRadioStatus() {
2862
- return new import_neverthrow.ResultAsync((async () => {
2863
- const result = await this.writeDataAsync(new GetRadioStatusH2DPacket);
2864
- return result instanceof GetRadioStatusReplyD2HPacket ? import_neverthrow.ok(result) : import_neverthrow.err(new VexProtocolError("radio status was not acknowledged"));
2865
- })());
2500
+ return this.request(new GetRadioStatusH2DPacket, GetRadioStatusReplyD2HPacket);
2866
2501
  }
2867
2502
  getSystemFlags() {
2868
- return new import_neverthrow.ResultAsync((async () => {
2869
- const result = await this.writeDataAsync(new GetSystemFlagsH2DPacket);
2870
- return result instanceof GetSystemFlagsReplyD2HPacket ? import_neverthrow.ok(result) : import_neverthrow.err(new VexProtocolError("system flags were not acknowledged"));
2871
- })());
2503
+ return this.request(new GetSystemFlagsH2DPacket, GetSystemFlagsReplyD2HPacket);
2872
2504
  }
2873
2505
  getSystemStatus(timeout = 1000) {
2874
- return new import_neverthrow.ResultAsync((async () => {
2875
- const result = await this.writeDataAsync(new GetSystemStatusH2DPacket, timeout);
2876
- return result instanceof GetSystemStatusReplyD2HPacket ? import_neverthrow.ok(result) : import_neverthrow.err(new VexProtocolError("system status was not acknowledged"));
2877
- })());
2506
+ return this.request(new GetSystemStatusH2DPacket, GetSystemStatusReplyD2HPacket, timeout);
2878
2507
  }
2879
2508
  getMatchStatus() {
2880
- return new import_neverthrow.ResultAsync((async () => {
2881
- const result = await this.writeDataAsync(new GetMatchStatusH2DPacket);
2882
- return result instanceof MatchStatusReplyD2HPacket ? import_neverthrow.ok(result) : import_neverthrow.err(new VexProtocolError("match status was not acknowledged"));
2883
- })());
2509
+ return this.request(new GetMatchStatusH2DPacket, MatchStatusReplyD2HPacket);
2884
2510
  }
2885
2511
  uploadProgramToDevice(iniConfig, binFileBuf, coldFileBuf, progressCallback) {
2886
2512
  return wrapTransfer(this, () => this._uploadProgramToDevice(iniConfig, binFileBuf, coldFileBuf, progressCallback));
@@ -2941,23 +2567,23 @@ class V5SerialConnection extends VexSerialConnection {
2941
2567
  async _downloadFileToHostUnlocked(request, downloadTarget, progressCallback) {
2942
2568
  const { filename, vendor, loadAddress, size } = request;
2943
2569
  let nextAddress = loadAddress ?? USER_FLASH_USR_CODE_START;
2944
- const p1 = await this.writeDataAsync(new InitFileTransferH2DPacket(2 /* READ */, downloadTarget, vendor, 0 /* NONE */, new Uint8Array, nextAddress, filename, ""));
2945
- if (!(p1 instanceof InitFileTransferReplyD2HPacket)) {
2946
- return import_neverthrow.err(new VexTransferError("InitFileTransferH2DPacket failed"));
2947
- }
2570
+ const p1Result = await this.request(new InitFileTransferH2DPacket(2 /* READ */, downloadTarget, vendor, 0 /* NONE */, new Uint8Array, nextAddress, filename, ""), InitFileTransferReplyD2HPacket);
2571
+ if (p1Result.isErr())
2572
+ return import_neverthrow.err(p1Result.error);
2948
2573
  let transferFailed = true;
2949
2574
  let result = import_neverthrow.ok(new Uint8Array);
2950
2575
  try {
2576
+ const p1 = p1Result.value;
2951
2577
  const fileSize = size ?? p1.fileSize;
2952
2578
  const bufferChunkSize = getTransferChunkSize(p1.windowSize);
2953
2579
  let bufferOffset = 0;
2954
2580
  const fileBuf = new Uint8Array(fileSize);
2955
2581
  while (bufferOffset < fileSize) {
2956
2582
  const requestedSize = Math.min(bufferChunkSize, fileSize - bufferOffset);
2957
- const p2 = await this.writeDataAsync(new ReadFileH2DPacket(nextAddress, requestedSize), 3000);
2958
- if (!(p2 instanceof ReadFileReplyD2HPacket)) {
2959
- throw new VexTransferError("ReadFileReplyD2HPacket failed");
2960
- }
2583
+ const p2Result = await this.request(new ReadFileH2DPacket(nextAddress, requestedSize), ReadFileReplyD2HPacket, 3000);
2584
+ if (p2Result.isErr())
2585
+ throw p2Result.error;
2586
+ const p2 = p2Result.value;
2961
2587
  if (p2.addr !== nextAddress) {
2962
2588
  throw new VexTransferError(`ReadFileReplyD2HPacket returned address ${p2.addr}, expected ${nextAddress}`);
2963
2589
  }
@@ -2975,11 +2601,12 @@ class V5SerialConnection extends VexSerialConnection {
2975
2601
  result = import_neverthrow.err(e instanceof VexSerialError ? e : toVexSerialError(e, "transfer"));
2976
2602
  } finally {
2977
2603
  try {
2978
- await this.writeDataAsync(new ExitFileTransferH2DPacket(3 /* EXIT_HALT */), 30000);
2979
- } catch (cleanupError) {
2980
- if (!transferFailed) {
2981
- result = import_neverthrow.err(toVexSerialError(cleanupError, "io"));
2982
- }
2604
+ const exitResult = await this.request(new ExitFileTransferH2DPacket(3 /* EXIT_HALT */), ExitFileTransferReplyD2HPacket, 30000);
2605
+ if (!transferFailed && exitResult.isErr())
2606
+ result = import_neverthrow.err(exitResult.error);
2607
+ } catch (e) {
2608
+ if (!transferFailed)
2609
+ result = import_neverthrow.err(toVexSerialError(e, "io"));
2983
2610
  }
2984
2611
  }
2985
2612
  return result;
@@ -3004,22 +2631,20 @@ class V5SerialConnection extends VexSerialConnection {
3004
2631
  downloadTarget = downloadTarget ?? 1 /* FILE_TARGET_QSPI */;
3005
2632
  vendor = vendor ?? 1 /* USER */;
3006
2633
  let nextAddress = loadAddress ?? USER_FLASH_USR_CODE_START;
3007
- const p1 = await this.writeDataAsync(new InitFileTransferH2DPacket(1 /* WRITE */, downloadTarget, vendor, 1 /* OVERWRITE */, buf, nextAddress, filename, exttype));
3008
- if (!(p1 instanceof InitFileTransferReplyD2HPacket)) {
3009
- return import_neverthrow.err(new VexTransferError("InitFileTransferH2DPacket failed"));
3010
- }
2634
+ const p1Result = await this.request(new InitFileTransferH2DPacket(1 /* WRITE */, downloadTarget, vendor, 1 /* OVERWRITE */, buf, nextAddress, filename, exttype), InitFileTransferReplyD2HPacket);
2635
+ if (p1Result.isErr())
2636
+ return import_neverthrow.err(p1Result.error);
2637
+ const p1 = p1Result.value;
3011
2638
  const bufferChunkSize = getTransferChunkSize(p1.windowSize);
3012
2639
  let bufferOffset = 0;
3013
2640
  let lastBlock = false;
3014
2641
  let transferFailed = true;
3015
- let exitReply;
3016
2642
  let result = import_neverthrow.ok(false);
3017
2643
  try {
3018
2644
  if (linkedFile !== undefined) {
3019
- const p3 = await this.writeDataAsync(new LinkFileH2DPacket(linkedFile.vendor ?? 1 /* USER */, linkedFile.filename, 0), 1e4);
3020
- if (!(p3 instanceof LinkFileReplyD2HPacket)) {
3021
- throw new VexTransferError("LinkFileH2DPacket failed");
3022
- }
2645
+ const p3Result = await this.request(new LinkFileH2DPacket(linkedFile.vendor ?? 1 /* USER */, linkedFile.filename, 0), LinkFileReplyD2HPacket, 1e4);
2646
+ if (p3Result.isErr())
2647
+ throw p3Result.error;
3023
2648
  }
3024
2649
  while (!lastBlock) {
3025
2650
  let tmpbuf;
@@ -3031,23 +2656,21 @@ class V5SerialConnection extends VexSerialConnection {
3031
2656
  tmpbuf.set(buf.subarray(bufferOffset, buf.byteLength));
3032
2657
  lastBlock = true;
3033
2658
  }
3034
- const p2 = await this.writeDataAsync(new WriteFileH2DPacket(nextAddress, tmpbuf), 3000);
3035
- if (!(p2 instanceof WriteFileReplyD2HPacket))
3036
- throw new VexTransferError("WriteFileReplyD2DPacket failed");
3037
- if (progressCallback != null)
3038
- progressCallback(bufferOffset, buf.byteLength);
2659
+ const p2Result = await this.request(new WriteFileH2DPacket(nextAddress, tmpbuf), WriteFileReplyD2HPacket, 3000);
2660
+ if (p2Result.isErr())
2661
+ throw p2Result.error;
3039
2662
  bufferOffset += bufferChunkSize;
3040
2663
  nextAddress += bufferChunkSize;
2664
+ progressCallback?.(Math.min(bufferOffset, buf.byteLength), buf.byteLength);
3041
2665
  }
3042
- progressCallback?.(buf.byteLength, buf.byteLength);
3043
2666
  transferFailed = false;
3044
2667
  } catch (e) {
3045
2668
  result = import_neverthrow.err(e instanceof VexSerialError ? e : toVexSerialError(e, "transfer"));
3046
2669
  } finally {
3047
2670
  try {
3048
- exitReply = await this.writeDataAsync(new ExitFileTransferH2DPacket(transferFailed ? 3 /* EXIT_HALT */ : autoRun ? 1 /* EXIT_RUN */ : 3 /* EXIT_HALT */), 30000);
2671
+ const exitResult = await this.request(new ExitFileTransferH2DPacket(transferFailed ? 3 /* EXIT_HALT */ : autoRun ? 1 /* EXIT_RUN */ : 3 /* EXIT_HALT */), ExitFileTransferReplyD2HPacket, 30000);
3049
2672
  if (!transferFailed) {
3050
- result = import_neverthrow.ok(exitReply !== undefined && exitReply instanceof ExitFileTransferReplyD2HPacket);
2673
+ result = exitResult.map(() => true);
3051
2674
  }
3052
2675
  } catch (cleanupError) {
3053
2676
  if (!transferFailed) {
@@ -3069,14 +2692,20 @@ class V5SerialConnection extends VexSerialConnection {
3069
2692
  }
3070
2693
  let result;
3071
2694
  try {
3072
- const ack = await this.writeDataAsync(new EraseFileH2DPacket(vendor, filename));
3073
- result = ack instanceof EraseFileReplyD2HPacket ? import_neverthrow.ok(undefined) : import_neverthrow.err(new VexProtocolError("removeFile was not acknowledged"));
2695
+ const eraseResult = await this.request(new EraseFileH2DPacket(vendor, filename), EraseFileReplyD2HPacket);
2696
+ result = eraseResult.map(() => {
2697
+ return;
2698
+ });
3074
2699
  } catch (e) {
3075
2700
  result = import_neverthrow.err(toVexSerialError(e, "io"));
3076
- } finally {
3077
- try {
3078
- await this.writeDataAsync(new ExitFileTransferH2DPacket(3 /* EXIT_HALT */));
3079
- } catch {}
2701
+ }
2702
+ try {
2703
+ const exitResult = await this.request(new ExitFileTransferH2DPacket(3 /* EXIT_HALT */), ExitFileTransferReplyD2HPacket, 30000);
2704
+ if (result.isOk() && exitResult.isErr())
2705
+ result = import_neverthrow.err(exitResult.error);
2706
+ } catch (e) {
2707
+ if (result.isOk())
2708
+ result = import_neverthrow.err(toVexSerialError(e, "io"));
3080
2709
  }
3081
2710
  return result;
3082
2711
  }));
@@ -3085,23 +2714,26 @@ class V5SerialConnection extends VexSerialConnection {
3085
2714
  return new import_neverthrow.ResultAsync(this.withFileTransfer(async () => {
3086
2715
  let result;
3087
2716
  try {
3088
- const ack = await this.writeDataAsync(new FileClearUpH2DPacket(1 /* USER */), 30000);
3089
- result = ack instanceof FileClearUpReplyD2HPacket ? import_neverthrow.ok(undefined) : import_neverthrow.err(new VexProtocolError("removeAllFiles was not acknowledged"));
2717
+ const clearResult = await this.request(new FileClearUpH2DPacket(1 /* USER */), FileClearUpReplyD2HPacket, 30000);
2718
+ result = clearResult.map(() => {
2719
+ return;
2720
+ });
3090
2721
  } catch (e) {
3091
2722
  result = import_neverthrow.err(toVexSerialError(e, "io"));
3092
- } finally {
3093
- try {
3094
- await this.writeDataAsync(new ExitFileTransferH2DPacket(3 /* EXIT_HALT */));
3095
- } catch {}
2723
+ }
2724
+ try {
2725
+ const exitResult = await this.request(new ExitFileTransferH2DPacket(3 /* EXIT_HALT */), ExitFileTransferReplyD2HPacket, 30000);
2726
+ if (result.isOk() && exitResult.isErr())
2727
+ result = import_neverthrow.err(exitResult.error);
2728
+ } catch (e) {
2729
+ if (result.isOk())
2730
+ result = import_neverthrow.err(toVexSerialError(e, "io"));
3096
2731
  }
3097
2732
  return result;
3098
2733
  }));
3099
2734
  }
3100
2735
  captureScreenSetup() {
3101
- return new import_neverthrow.ResultAsync((async () => {
3102
- const result = await this.writeDataAsync(new ScreenCaptureH2DPacket(0));
3103
- return result instanceof ScreenCaptureReplyD2HPacket ? import_neverthrow.ok(result) : import_neverthrow.err(new VexProtocolError("screen capture was rejected"));
3104
- })());
2736
+ return this.request(new ScreenCaptureH2DPacket(0), ScreenCaptureReplyD2HPacket);
3105
2737
  }
3106
2738
  captureScreen(progressCallback) {
3107
2739
  return wrapTransfer(this, () => this._captureScreen(progressCallback));
@@ -3122,37 +2754,22 @@ class V5SerialConnection extends VexSerialConnection {
3122
2754
  return import_neverthrow.ok(convertScreenCapture(framebuffer.value));
3123
2755
  }
3124
2756
  setMatchMode(mode) {
3125
- return new import_neverthrow.ResultAsync((async () => {
3126
- const result = await this.writeDataAsync(new UpdateMatchModeH2DPacket(mode, 0));
3127
- return result instanceof MatchModeReplyD2HPacket ? import_neverthrow.ok(result) : import_neverthrow.err(new VexProtocolError("setMatchMode was not acknowledged"));
3128
- })());
2757
+ return this.request(new UpdateMatchModeH2DPacket(mode, 0), MatchModeReplyD2HPacket);
3129
2758
  }
3130
2759
  runProgram(value) {
3131
2760
  return this.loadProgram(value);
3132
2761
  }
3133
2762
  loadProgram(value) {
3134
- return new import_neverthrow.ResultAsync((async () => {
3135
- const result = await this.writeDataAsync(new LoadFileActionH2DPacket(1 /* USER */, 0 /* RUN */, value));
3136
- return result instanceof LoadFileActionReplyD2HPacket ? import_neverthrow.ok(result) : import_neverthrow.err(new VexProtocolError("loadProgram was not acknowledged"));
3137
- })());
2763
+ return this.request(new LoadFileActionH2DPacket(1 /* USER */, 0 /* RUN */, value), LoadFileActionReplyD2HPacket);
3138
2764
  }
3139
2765
  stopProgram() {
3140
- return new import_neverthrow.ResultAsync((async () => {
3141
- const result = await this.writeDataAsync(new LoadFileActionH2DPacket(1 /* USER */, 128 /* STOP */, ""));
3142
- return result instanceof LoadFileActionReplyD2HPacket ? import_neverthrow.ok(result) : import_neverthrow.err(new VexProtocolError("stopProgram was not acknowledged"));
3143
- })());
2766
+ return this.request(new LoadFileActionH2DPacket(1 /* USER */, 128 /* STOP */, ""), LoadFileActionReplyD2HPacket);
3144
2767
  }
3145
2768
  mockTouch(x, y, press) {
3146
- return new import_neverthrow.ResultAsync((async () => {
3147
- const result = await this.writeDataAsync(new SendDashTouchH2DPacket(x, y, press));
3148
- return result instanceof SendDashTouchReplyD2HPacket ? import_neverthrow.ok(result) : import_neverthrow.err(new VexProtocolError("mockTouch was not acknowledged"));
3149
- })());
2769
+ return this.request(new SendDashTouchH2DPacket(x, y, press), SendDashTouchReplyD2HPacket);
3150
2770
  }
3151
2771
  openScreen(screen, port) {
3152
- return new import_neverthrow.ResultAsync((async () => {
3153
- const result = await this.writeDataAsync(new SelectDashH2DPacket(screen, port));
3154
- return result instanceof SelectDashReplyD2HPacket ? import_neverthrow.ok(result) : import_neverthrow.err(new VexProtocolError("openScreen was not acknowledged"));
3155
- })());
2772
+ return this.request(new SelectDashH2DPacket(screen, port), SelectDashReplyD2HPacket);
3156
2773
  }
3157
2774
  }
3158
2775
  function binaryArrayJoin(left, right) {
@@ -3194,8 +2811,16 @@ function wrapTransfer(conn, operation) {
3194
2811
  }
3195
2812
  }));
3196
2813
  }
3197
- function errAsyncVex(error) {
3198
- return new import_neverthrow.ResultAsync(Promise.resolve(import_neverthrow.err(error)));
2814
+ function expectedReplyMessage(packet, ReplyType, reply) {
2815
+ const expected = `expected ${ReplyType.name} for ${packet.constructor.name}`;
2816
+ if (typeof reply === "number")
2817
+ return `${expected}; received ${ackTypeName(reply)}`;
2818
+ if (reply instanceof ArrayBuffer)
2819
+ return `${expected}; received raw ArrayBuffer`;
2820
+ return `${expected}; received ${reply.constructor.name}`;
2821
+ }
2822
+ function ackTypeName(ackType) {
2823
+ return `AckType.${AckType[ackType] ?? "UNKNOWN"} (${ackType})`;
3199
2824
  }
3200
2825
  // src/VexDeviceState.ts
3201
2826
  var import_neverthrow4 = __toESM(require_index_cjs(), 1);
@@ -3206,9 +2831,6 @@ var MAX_CATALOG_BYTES = 4 * 1024;
3206
2831
  var MAX_VEXOS_BYTES = 64 * 1024 * 1024;
3207
2832
  var MAX_FIRMWARE_IMAGE_BYTES = 32 * 1024 * 1024;
3208
2833
  var MAX_AGGREGATE_IMAGE_BYTES = 48 * 1024 * 1024;
3209
- function fromAsyncFn(fn) {
3210
- return new import_neverthrow2.ResultAsync(fn());
3211
- }
3212
2834
  function downloadFileFromInternet(link, options = {}) {
3213
2835
  const { maxBytes = Number.POSITIVE_INFINITY, timeout = 30000 } = options;
3214
2836
  if (maxBytes <= 0) {
@@ -3217,7 +2839,7 @@ function downloadFileFromInternet(link, options = {}) {
3217
2839
  if (timeout < 0) {
3218
2840
  return import_neverthrow2.errAsync(new VexInvalidArgumentError("timeout must be non-negative"));
3219
2841
  }
3220
- return fromAsyncFn(() => runDownload(link, maxBytes, timeout));
2842
+ return new import_neverthrow2.ResultAsync(runDownload(link, maxBytes, timeout));
3221
2843
  }
3222
2844
  async function runDownload(link, maxBytes, timeout) {
3223
2845
  const controller = new AbortController;
@@ -3284,7 +2906,7 @@ function sleepUntilAsync(f, timeout, interval = 20) {
3284
2906
  if (interval <= 0) {
3285
2907
  return import_neverthrow2.errAsync(new VexInvalidArgumentError("interval must be positive"));
3286
2908
  }
3287
- return fromAsyncFn(() => runSleepUntilAsync(f, timeout, interval));
2909
+ return new import_neverthrow2.ResultAsync(runSleepUntilAsync(f, timeout, interval));
3288
2910
  }
3289
2911
  async function runSleepUntilAsync(f, timeout, interval) {
3290
2912
  const deadline = Date.now() + timeout;
@@ -3309,7 +2931,7 @@ function sleepUntil(f, timeout, interval = 20) {
3309
2931
  if (interval <= 0) {
3310
2932
  return import_neverthrow2.errAsync(new VexInvalidArgumentError("interval must be positive"));
3311
2933
  }
3312
- return fromAsyncFn(() => runSleepUntil(f, timeout, interval));
2934
+ return new import_neverthrow2.ResultAsync(runSleepUntil(f, timeout, interval));
3313
2935
  }
3314
2936
  async function runSleepUntil(f, timeout, interval) {
3315
2937
  const deadline = Date.now() + timeout;
@@ -3336,6 +2958,59 @@ function sleep(ms) {
3336
2958
  async function sleepInner(ms) {
3337
2959
  return new Promise((resolve) => setTimeout(resolve, ms));
3338
2960
  }
2961
+ async function flashFactoryImage(conn, options, pcb) {
2962
+ const { image, label, downloadTarget } = options;
2963
+ pcb(`FACTORY ENB ${label}`, 0, 0);
2964
+ const enableReply = await conn.request(new FactoryEnableH2DPacket, FactoryEnableReplyD2HPacket);
2965
+ if (enableReply.isErr())
2966
+ return import_neverthrow2.err(enableReply.error);
2967
+ const writeRequest = {
2968
+ filename: "null.bin",
2969
+ vendor: 1 /* USER */,
2970
+ loadAddress: USER_FLASH_USR_CODE_START,
2971
+ buf: image.buf,
2972
+ downloadTarget,
2973
+ exttype: "bin",
2974
+ autoRun: true,
2975
+ linkedFile: undefined
2976
+ };
2977
+ const upload = await conn.uploadFileToDevice(writeRequest, (c, t) => {
2978
+ pcb(`UPLOAD ${label}`, c, t);
2979
+ });
2980
+ if (upload.isErr())
2981
+ return import_neverthrow2.err(upload.error);
2982
+ if (!upload.value) {
2983
+ return import_neverthrow2.err(new VexFirmwareError(`${label} upload was rejected by device`));
2984
+ }
2985
+ const deadline = Date.now() + 120000;
2986
+ while (Date.now() < deadline) {
2987
+ const statusReply = await conn.request(new FactoryStatusH2DPacket, FactoryStatusReplyD2HPacket, 1e4);
2988
+ if (statusReply.isErr())
2989
+ return import_neverthrow2.err(statusReply.error);
2990
+ reportFactoryStatus(label, statusReply.value, pcb);
2991
+ if (statusReply.value.status === 0 && statusReply.value.percent === 100) {
2992
+ return import_neverthrow2.ok(undefined);
2993
+ }
2994
+ await sleepInner(500);
2995
+ }
2996
+ return import_neverthrow2.err(new VexFirmwareError(`${label} factory status timed out`));
2997
+ }
2998
+ function reportFactoryStatus(label, reply, pcb) {
2999
+ switch (reply.status) {
3000
+ case 2:
3001
+ pcb(`ERASE ${label}`, reply.percent, 100);
3002
+ break;
3003
+ case 3:
3004
+ pcb(`WRITE ${label}`, reply.percent, 100);
3005
+ break;
3006
+ case 4:
3007
+ pcb(`VERIFY ${label}`, reply.percent, 100);
3008
+ break;
3009
+ case 8:
3010
+ pcb(`FINISHING ${label}`, reply.percent, 100);
3011
+ break;
3012
+ }
3013
+ }
3339
3014
  async function extractFirmwareImages(usingVersion, vexos) {
3340
3015
  const { unzip } = await import("unzipit");
3341
3016
  const { entries } = await unzip(vexos);
@@ -3383,7 +3058,7 @@ async function extractFirmwareImages(usingVersion, vexos) {
3383
3058
  return ordered;
3384
3059
  }
3385
3060
  function uploadFirmware(state, publicUrl = "https://content.vexrobotics.com/vexos/public/V5/", usingVersion, progressCallback) {
3386
- return fromAsyncFn(() => runUploadFirmware(state, publicUrl, usingVersion, progressCallback));
3061
+ return new import_neverthrow2.ResultAsync(runUploadFirmware(state, publicUrl, usingVersion, progressCallback));
3387
3062
  }
3388
3063
  async function runUploadFirmware(state, publicUrl, usingVersion, progressCallback) {
3389
3064
  const device = state._instance;
@@ -3425,12 +3100,7 @@ async function runUploadFirmware(state, publicUrl, usingVersion, progressCallbac
3425
3100
  return import_neverthrow2.err(toVexSerialError(e, "firmware"));
3426
3101
  }
3427
3102
  pcb("UNZIP VEXOS", 1, 1);
3428
- return state.withFileTransfer(async () => {
3429
- pcb("FACTORY ENB BOOT", 0, 0);
3430
- const result = await conn.writeDataAsync(new FactoryEnableH2DPacket);
3431
- if (!(result instanceof FactoryEnableReplyD2HPacket)) {
3432
- return import_neverthrow2.err(new VexProtocolError("FactoryEnableH2DPacket failed"));
3433
- }
3103
+ return state.withRefreshPaused(async () => {
3434
3104
  const boot = images.find((image) => image.name.endsWith("BOOT.bin"));
3435
3105
  if (boot === undefined) {
3436
3106
  return import_neverthrow2.err(new VexFirmwareError("VEXos archive is missing BOOT.bin"));
@@ -3439,105 +3109,20 @@ async function runUploadFirmware(state, publicUrl, usingVersion, progressCallbac
3439
3109
  if (assertImage === undefined) {
3440
3110
  return import_neverthrow2.err(new VexFirmwareError("VEXos archive is missing assets.bin"));
3441
3111
  }
3442
- const bootWriteRequest = {
3443
- filename: "null.bin",
3444
- vendor: 1 /* USER */,
3445
- loadAddress: USER_FLASH_USR_CODE_START,
3446
- buf: boot.buf,
3447
- downloadTarget: 14 /* FILE_TARGET_B1 */,
3448
- exttype: "bin",
3449
- autoRun: true,
3450
- linkedFile: undefined
3451
- };
3452
- const bootUpload = await conn.uploadFileToDevice(bootWriteRequest, (c, t) => {
3453
- pcb("UPLOAD BOOT", c, t);
3454
- });
3455
- if (bootUpload.isErr())
3456
- return import_neverthrow2.err(bootUpload.error);
3457
- if (!bootUpload.value)
3458
- return import_neverthrow2.ok(false);
3459
- const bootDeadline = Date.now() + 120000;
3460
- let bootComplete = false;
3461
- while (Date.now() < bootDeadline) {
3462
- const result3 = await conn.writeDataAsync(new FactoryStatusH2DPacket, 1e4);
3463
- if (result3 instanceof FactoryStatusReplyD2HPacket) {
3464
- switch (result3.status) {
3465
- case 2:
3466
- pcb("ERASE BOOT", result3.percent, 100);
3467
- break;
3468
- case 3:
3469
- pcb("WRITE BOOT", result3.percent, 100);
3470
- break;
3471
- case 4:
3472
- pcb("VERIFY BOOT", result3.percent, 100);
3473
- break;
3474
- case 8:
3475
- pcb("FINISHING BOOT", result3.percent, 100);
3476
- break;
3477
- }
3478
- if (result3.status === 0 && result3.percent === 100) {
3479
- bootComplete = true;
3480
- break;
3481
- }
3482
- } else {
3483
- return import_neverthrow2.ok(false);
3484
- }
3485
- await sleepInner(500);
3486
- }
3487
- if (!bootComplete)
3488
- return import_neverthrow2.ok(false);
3489
- pcb("FACTORY ENB ASSERT", 0, 0);
3490
- const result5 = await conn.writeDataAsync(new FactoryEnableH2DPacket);
3491
- if (!(result5 instanceof FactoryEnableReplyD2HPacket)) {
3492
- return import_neverthrow2.err(new VexProtocolError("FactoryEnableH2DPacket failed"));
3493
- }
3494
- const assertWriteRequest = {
3495
- filename: "null.bin",
3496
- vendor: 1 /* USER */,
3497
- loadAddress: USER_FLASH_USR_CODE_START,
3498
- buf: assertImage.buf,
3499
- downloadTarget: 13 /* FILE_TARGET_A1 */,
3500
- exttype: "bin",
3501
- autoRun: true,
3502
- linkedFile: undefined
3503
- };
3504
- const assertUpload = await conn.uploadFileToDevice(assertWriteRequest, (c, t) => {
3505
- pcb("UPLOAD ASSERT", c, t);
3506
- });
3507
- if (assertUpload.isErr())
3508
- return import_neverthrow2.err(assertUpload.error);
3509
- if (!assertUpload.value)
3510
- return import_neverthrow2.ok(false);
3511
- const assertDeadline = Date.now() + 120000;
3512
- let assertComplete = false;
3513
- while (Date.now() < assertDeadline) {
3514
- const result7 = await conn.writeDataAsync(new FactoryStatusH2DPacket, 1e4);
3515
- if (result7 instanceof FactoryStatusReplyD2HPacket) {
3516
- switch (result7.status) {
3517
- case 2:
3518
- pcb("ERASE ASSERT", result7.percent, 100);
3519
- break;
3520
- case 3:
3521
- pcb("WRITE ASSERT", result7.percent, 100);
3522
- break;
3523
- case 4:
3524
- pcb("VERIFY ASSERT", result7.percent, 100);
3525
- break;
3526
- case 8:
3527
- pcb("FINISHING ASSERT", result7.percent, 100);
3528
- break;
3529
- }
3530
- if (result7.status === 0 && result7.percent === 100) {
3531
- assertComplete = true;
3532
- break;
3533
- }
3534
- } else {
3535
- return import_neverthrow2.ok(false);
3536
- }
3537
- await sleepInner(500);
3538
- }
3539
- if (!assertComplete)
3540
- return import_neverthrow2.ok(false);
3112
+ const bootFlash = await flashFactoryImage(conn, {
3113
+ image: boot,
3114
+ label: "BOOT",
3115
+ downloadTarget: 14 /* FILE_TARGET_B1 */
3116
+ }, pcb);
3117
+ if (bootFlash.isErr())
3118
+ return import_neverthrow2.err(bootFlash.error);
3119
+ const assetsFlash = await flashFactoryImage(conn, {
3120
+ image: assertImage,
3121
+ label: "ASSETS",
3122
+ downloadTarget: 13 /* FILE_TARGET_A1 */
3123
+ }, pcb);
3124
+ if (assetsFlash.isErr())
3125
+ return import_neverthrow2.err(assetsFlash.error);
3541
3126
  return import_neverthrow2.ok(true);
3542
3127
  });
3543
3128
  }
@@ -3550,8 +3135,7 @@ function getValue(state, key) {
3550
3135
  if (conn == null || !conn.isConnected) {
3551
3136
  return import_neverthrow3.err(new VexNotConnectedError);
3552
3137
  }
3553
- const result = await conn.writeDataAsync(new ReadKeyValueH2DPacket(key));
3554
- return result instanceof ReadKeyValueReplyD2HPacket ? import_neverthrow3.ok(result.value) : import_neverthrow3.err(new VexProtocolError("getValue was not acknowledged"));
3138
+ return conn.request(new ReadKeyValueH2DPacket(key), ReadKeyValueReplyD2HPacket).map((result) => result.value);
3555
3139
  })());
3556
3140
  }
3557
3141
  function setValue(state, key, value) {
@@ -3560,8 +3144,9 @@ function setValue(state, key, value) {
3560
3144
  if (conn == null || !conn.isConnected) {
3561
3145
  return import_neverthrow3.err(new VexNotConnectedError);
3562
3146
  }
3563
- const result = await conn.writeDataAsync(new WriteKeyValueH2DPacket(key, value));
3564
- return result instanceof WriteKeyValueReplyD2HPacket ? import_neverthrow3.ok(undefined) : import_neverthrow3.err(new VexProtocolError("setValue was not acknowledged"));
3147
+ return conn.request(new WriteKeyValueH2DPacket(key, value), WriteKeyValueReplyD2HPacket).map(() => {
3148
+ return;
3149
+ });
3565
3150
  })());
3566
3151
  }
3567
3152
  function listFiles(state, vendor = 1 /* USER */) {
@@ -3570,26 +3155,24 @@ function listFiles(state, vendor = 1 /* USER */) {
3570
3155
  if (conn == null || !conn.isConnected) {
3571
3156
  return import_neverthrow3.err(new VexNotConnectedError);
3572
3157
  }
3573
- const result = await conn.writeDataAsync(new GetDirectoryFileCountH2DPacket(vendor));
3574
- if (!(result instanceof GetDirectoryFileCountReplyD2HPacket)) {
3575
- return import_neverthrow3.err(new VexProtocolError("directory file count was not acknowledged"));
3576
- }
3158
+ const countResult = await conn.request(new GetDirectoryFileCountH2DPacket(vendor), GetDirectoryFileCountReplyD2HPacket);
3159
+ if (countResult.isErr())
3160
+ return import_neverthrow3.err(countResult.error);
3577
3161
  const files = [];
3578
- for (let i = 0;i < result.count; i++) {
3579
- const result2 = await conn.writeDataAsync(new GetDirectoryEntryH2DPacket(i));
3580
- if (!(result2 instanceof GetDirectoryEntryReplyD2HPacket)) {
3581
- return import_neverthrow3.err(new VexProtocolError("directory entry was not acknowledged"));
3582
- }
3583
- if (result2.file != null) {
3162
+ for (let i = 0;i < countResult.value.count; i++) {
3163
+ const entryResult = await conn.request(new GetDirectoryEntryH2DPacket(i), GetDirectoryEntryReplyD2HPacket);
3164
+ if (entryResult.isErr())
3165
+ return import_neverthrow3.err(entryResult.error);
3166
+ if (entryResult.value.file != null) {
3584
3167
  files.push({
3585
- filename: result2.file.filename,
3168
+ filename: entryResult.value.file.filename,
3586
3169
  vendor,
3587
- loadAddress: result2.file.loadAddress,
3588
- size: result2.file.size,
3589
- crc32: result2.file.crc32,
3590
- type: result2.file.type,
3591
- timestamp: result2.file.timestamp,
3592
- version: result2.file.version
3170
+ loadAddress: entryResult.value.file.loadAddress,
3171
+ size: entryResult.value.file.size,
3172
+ crc32: entryResult.value.file.crc32,
3173
+ type: entryResult.value.file.type,
3174
+ timestamp: entryResult.value.file.timestamp,
3175
+ version: entryResult.value.file.version
3593
3176
  });
3594
3177
  }
3595
3178
  }
@@ -3625,10 +3208,10 @@ function listProgram(state) {
3625
3208
  time: n,
3626
3209
  requestedSlot: -1
3627
3210
  };
3628
- const result2 = await conn.writeDataAsync(new GetProgramSlotInfoH2DPacket(1 /* USER */, program.binfile));
3629
- if (result2 instanceof GetProgramSlotInfoReplyD2HPacket) {
3630
- program.slot = result2.slot;
3631
- program.requestedSlot = result2.requestedSlot;
3211
+ const slotInfo = await conn.request(new GetProgramSlotInfoH2DPacket(1 /* USER */, program.binfile), GetProgramSlotInfoReplyD2HPacket);
3212
+ if (slotInfo.isOk()) {
3213
+ program.slot = slotInfo.value.slot;
3214
+ program.requestedSlot = slotInfo.value.requestedSlot;
3632
3215
  }
3633
3216
  programList.push(program);
3634
3217
  }
@@ -3647,7 +3230,7 @@ function readFile(state, request, downloadTarget = 1 /* FILE_TARGET_QSPI */, pro
3647
3230
  } else {
3648
3231
  handle = request;
3649
3232
  }
3650
- return state.withFileTransfer(() => conn.downloadFileToHost(handle, downloadTarget, progressCallback));
3233
+ return state.withRefreshPaused(() => conn.downloadFileToHost(handle, downloadTarget, progressCallback));
3651
3234
  })());
3652
3235
  }
3653
3236
  function removeFile(state, request) {
@@ -3656,7 +3239,7 @@ function removeFile(state, request) {
3656
3239
  if (conn == null || !conn.isConnected) {
3657
3240
  return import_neverthrow3.err(new VexNotConnectedError);
3658
3241
  }
3659
- return state.withFileTransfer(() => conn.removeFile(request));
3242
+ return state.withRefreshPaused(() => conn.removeFile(request));
3660
3243
  })());
3661
3244
  }
3662
3245
  function removeAllFiles(state) {
@@ -3665,7 +3248,7 @@ function removeAllFiles(state) {
3665
3248
  if (conn == null || !conn.isConnected) {
3666
3249
  return import_neverthrow3.err(new VexNotConnectedError);
3667
3250
  }
3668
- return state.withFileTransfer(() => conn.removeAllFiles());
3251
+ return state.withRefreshPaused(() => conn.removeAllFiles());
3669
3252
  })());
3670
3253
  }
3671
3254
  function uploadProgram(state, iniConfig, binFileBuf, coldFileBuf, progressCallback) {
@@ -3678,7 +3261,7 @@ async function runUploadProgram(state, iniConfig, binFileBuf, coldFileBuf, progr
3678
3261
  return import_neverthrow3.err(new VexNotConnectedError);
3679
3262
  }
3680
3263
  let switchedToDownload = false;
3681
- return state.withFileTransfer(async () => {
3264
+ return state.withRefreshPaused(async () => {
3682
3265
  try {
3683
3266
  if (device.isV5Controller) {
3684
3267
  await sleep(250);
@@ -3737,7 +3320,7 @@ function writeFile(state, request, progressCallback) {
3737
3320
  if (conn == null || !conn.isConnected) {
3738
3321
  return import_neverthrow3.err(new VexNotConnectedError);
3739
3322
  }
3740
- return state.withFileTransfer(() => conn.uploadFileToDevice(request, progressCallback));
3323
+ return state.withRefreshPaused(() => conn.uploadFileToDevice(request, progressCallback));
3741
3324
  })());
3742
3325
  }
3743
3326
  function captureScreen(state, progressCallback) {
@@ -3746,7 +3329,7 @@ function captureScreen(state, progressCallback) {
3746
3329
  if (conn == null || !conn.isConnected) {
3747
3330
  return import_neverthrow3.err(new VexNotConnectedError);
3748
3331
  }
3749
- return state.withFileTransfer(() => conn.captureScreen(progressCallback));
3332
+ return state.withRefreshPaused(() => conn.captureScreen(progressCallback));
3750
3333
  })());
3751
3334
  }
3752
3335
 
@@ -3769,10 +3352,13 @@ class VexSerialDevice extends VexEventTarget {
3769
3352
  class V5SerialDeviceState {
3770
3353
  _instance;
3771
3354
  refreshPauseDepth = 0;
3772
- get isFileTransferring() {
3355
+ get isRefreshPaused() {
3773
3356
  return this.refreshPauseDepth > 0;
3774
3357
  }
3775
- async withFileTransfer(operation) {
3358
+ get isFileTransferring() {
3359
+ return this.isRefreshPaused;
3360
+ }
3361
+ async withRefreshPaused(operation) {
3776
3362
  this.refreshPauseDepth++;
3777
3363
  try {
3778
3364
  return await operation();
@@ -3780,6 +3366,9 @@ class V5SerialDeviceState {
3780
3366
  this.refreshPauseDepth--;
3781
3367
  }
3782
3368
  }
3369
+ async withFileTransfer(operation) {
3370
+ return this.withRefreshPaused(operation);
3371
+ }
3783
3372
  brain = {
3784
3373
  activeProgram: 0,
3785
3374
  battery: {
@@ -3809,7 +3398,8 @@ class V5SerialDeviceState {
3809
3398
  },
3810
3399
  {
3811
3400
  battery: 0,
3812
- isAvailable: false
3401
+ isAvailable: false,
3402
+ isCharging: false
3813
3403
  }
3814
3404
  ];
3815
3405
  devices = [];
@@ -3832,8 +3422,14 @@ class V5SerialDeviceState {
3832
3422
 
3833
3423
  class V5Brain {
3834
3424
  state;
3425
+ batteryFacade;
3426
+ buttonFacade;
3427
+ settingsFacade;
3835
3428
  constructor(state) {
3836
3429
  this.state = state;
3430
+ this.batteryFacade = new V5Battery(state);
3431
+ this.buttonFacade = new V5BrainButton(state);
3432
+ this.settingsFacade = new V5BrainSettings(state);
3837
3433
  }
3838
3434
  get isRunningProgram() {
3839
3435
  return this.activeProgram !== 0;
@@ -3866,9 +3462,8 @@ class V5Brain {
3866
3462
  const reply = await conn.runProgram(slot);
3867
3463
  if (reply.isErr())
3868
3464
  return import_neverthrow4.err(reply.error);
3869
- const slotNumber = typeof slot === "string" ? Number.parseInt(slot, 10) : slot;
3870
- if (Number.isFinite(slotNumber))
3871
- this.state.brain.activeProgram = slotNumber;
3465
+ if (typeof slot === "number")
3466
+ this.state.brain.activeProgram = slot;
3872
3467
  return import_neverthrow4.ok(undefined);
3873
3468
  })());
3874
3469
  }
@@ -3885,10 +3480,10 @@ class V5Brain {
3885
3480
  })());
3886
3481
  }
3887
3482
  get battery() {
3888
- return new V5Battery(this.state);
3483
+ return this.batteryFacade;
3889
3484
  }
3890
3485
  get button() {
3891
- return new V5BrainButton(this.state);
3486
+ return this.buttonFacade;
3892
3487
  }
3893
3488
  get cpu0Version() {
3894
3489
  return this.state.brain.cpu0Version;
@@ -3900,7 +3495,7 @@ class V5Brain {
3900
3495
  return this.state.brain.isAvailable;
3901
3496
  }
3902
3497
  get settings() {
3903
- return new V5BrainSettings(this.state);
3498
+ return this.settingsFacade;
3904
3499
  }
3905
3500
  get systemVersion() {
3906
3501
  return this.state.brain.systemVersion;
@@ -4055,18 +3650,29 @@ class V5Radio {
4055
3650
  }
4056
3651
  changeChannel(channel) {
4057
3652
  return new import_neverthrow4.ResultAsync((async () => {
4058
- const result = await this.state._instance.connection?.writeDataAsync(new FileControlH2DPacket(1, channel));
4059
- return result instanceof FileControlReplyD2HPacket ? import_neverthrow4.ok(undefined) : import_neverthrow4.err(new VexProtocolError("changeChannel was not acknowledged"));
3653
+ const conn = this.state._instance.connection;
3654
+ if (conn == null || !conn.isConnected) {
3655
+ return import_neverthrow4.err(new VexNotConnectedError);
3656
+ }
3657
+ return conn.request(new FileControlH2DPacket(1, channel), FileControlReplyD2HPacket).map(() => {
3658
+ return;
3659
+ });
4060
3660
  })());
4061
3661
  }
4062
3662
  }
4063
3663
 
4064
3664
  // src/VexDevice.ts
4065
3665
  var import_neverthrow5 = __toESM(require_index_cjs(), 1);
3666
+ function unrefTimerIfPossible(timer) {
3667
+ if (typeof timer !== "object" || timer === null || !("unref" in timer))
3668
+ return;
3669
+ const unref = timer.unref;
3670
+ if (typeof unref === "function")
3671
+ unref.call(timer);
3672
+ }
4066
3673
 
4067
3674
  class V5SerialDevice extends VexSerialDevice {
4068
3675
  autoReconnect = true;
4069
- autoRefresh = true;
4070
3676
  pauseRefreshOnFileTransfer = true;
4071
3677
  _isReconnecting = false;
4072
3678
  _isDisconnecting = false;
@@ -4074,19 +3680,45 @@ class V5SerialDevice extends VexSerialDevice {
4074
3680
  state = new V5SerialDeviceState(this);
4075
3681
  _disposed = false;
4076
3682
  _refreshGeneration = 0;
4077
- constructor(defaultSerial) {
3683
+ _autoRefresh = false;
3684
+ _isLastRefreshComplete = true;
3685
+ _brain = new V5Brain(this.state);
3686
+ _controllers = [
3687
+ new V5Controller(this.state, 0),
3688
+ new V5Controller(this.state, 1)
3689
+ ];
3690
+ _radio = new V5Radio(this.state);
3691
+ _deviceFacades = [];
3692
+ constructor(defaultSerial, autoRefresh = false) {
4078
3693
  super(defaultSerial);
4079
- let isLastRefreshComplete = true;
3694
+ this.autoRefresh = autoRefresh;
3695
+ }
3696
+ get autoRefresh() {
3697
+ return this._autoRefresh;
3698
+ }
3699
+ set autoRefresh(value) {
3700
+ if (this._autoRefresh === value)
3701
+ return;
3702
+ this._autoRefresh = value;
3703
+ if (value) {
3704
+ this._startRefreshInterval();
3705
+ } else {
3706
+ this._stopRefreshInterval();
3707
+ }
3708
+ }
3709
+ _startRefreshInterval() {
3710
+ if (this._refreshInterval !== undefined || this._disposed)
3711
+ return;
4080
3712
  this._refreshInterval = setInterval(() => {
4081
3713
  if (this._disposed)
4082
3714
  return;
4083
- if (this.autoRefresh && isLastRefreshComplete) {
3715
+ if (this._autoRefresh && this._isLastRefreshComplete) {
4084
3716
  if (!this.isConnected) {
4085
3717
  this.state.brain.isAvailable = false;
4086
3718
  return;
4087
3719
  }
4088
- if (!this.pauseRefreshOnFileTransfer || !this.state.isFileTransferring) {
4089
- isLastRefreshComplete = false;
3720
+ if (!this.pauseRefreshOnFileTransfer || !this.state.isRefreshPaused) {
3721
+ this._isLastRefreshComplete = false;
4090
3722
  (async () => {
4091
3723
  try {
4092
3724
  const r = await this.refresh();
@@ -4095,27 +3727,37 @@ class V5SerialDevice extends VexSerialDevice {
4095
3727
  } catch (error) {
4096
3728
  this.emit("error", error);
4097
3729
  } finally {
4098
- isLastRefreshComplete = true;
3730
+ this._isLastRefreshComplete = true;
4099
3731
  }
4100
3732
  })();
4101
3733
  }
4102
3734
  }
4103
3735
  }, 200);
3736
+ unrefTimerIfPossible(this._refreshInterval);
3737
+ }
3738
+ _stopRefreshInterval() {
3739
+ if (this._refreshInterval === undefined)
3740
+ return;
3741
+ clearInterval(this._refreshInterval);
3742
+ this._refreshInterval = undefined;
4104
3743
  }
4105
3744
  get isV5Controller() {
4106
3745
  return this.deviceType === 1283 /* V5_CONTROLLER */;
4107
3746
  }
4108
3747
  get brain() {
4109
- return new V5Brain(this.state);
3748
+ return this._brain;
4110
3749
  }
4111
3750
  get controllers() {
4112
- return [new V5Controller(this.state, 0), new V5Controller(this.state, 1)];
3751
+ return this._controllers;
4113
3752
  }
4114
3753
  get devices() {
4115
3754
  const rtn = [];
4116
- for (let i = 1;i <= this.state.devices.length; i++) {
4117
- if (this.state.devices[i] != null)
4118
- rtn.push(new V5SmartDevice(this.state, i));
3755
+ for (let i = 1;i < this.state.devices.length; i++) {
3756
+ if (this.state.devices[i] != null) {
3757
+ const facade = this._deviceFacades[i] ?? new V5SmartDevice(this.state, i);
3758
+ this._deviceFacades[i] = facade;
3759
+ rtn.push(facade);
3760
+ }
4119
3761
  }
4120
3762
  return rtn;
4121
3763
  }
@@ -4140,7 +3782,7 @@ class V5SerialDevice extends VexSerialDevice {
4140
3782
  })());
4141
3783
  }
4142
3784
  get radio() {
4143
- return new V5Radio(this.state);
3785
+ return this._radio;
4144
3786
  }
4145
3787
  mockTouch(x, y, press) {
4146
3788
  return new import_neverthrow5.ResultAsync((async () => {
@@ -4161,7 +3803,7 @@ class V5SerialDevice extends VexSerialDevice {
4161
3803
  if (conn != null) {
4162
3804
  if (!conn.isConnected) {
4163
3805
  const opened = await conn.open();
4164
- if (opened.isErr() || opened.value !== true) {
3806
+ if (opened.isErr() || opened.value !== "opened") {
4165
3807
  return import_neverthrow5.err(new VexIoError("failed to open the supplied connection"));
4166
3808
  }
4167
3809
  }
@@ -4180,10 +3822,10 @@ class V5SerialDevice extends VexSerialDevice {
4180
3822
  await c.close();
4181
3823
  return import_neverthrow5.err(result.error);
4182
3824
  }
4183
- if (result.value === undefined) {
3825
+ if (result.value === "no-port") {
4184
3826
  return import_neverthrow5.err(new VexNotConnectedError("no V5 device was found"));
4185
3827
  }
4186
- if (!result.value) {
3828
+ if (result.value === "busy") {
4187
3829
  await c.close();
4188
3830
  continue;
4189
3831
  }
@@ -4215,10 +3857,6 @@ class V5SerialDevice extends VexSerialDevice {
4215
3857
  this.autoReconnect = false;
4216
3858
  this.autoRefresh = false;
4217
3859
  this._disposed = true;
4218
- if (this._refreshInterval !== undefined) {
4219
- clearInterval(this._refreshInterval);
4220
- this._refreshInterval = undefined;
4221
- }
4222
3860
  await this.disconnect();
4223
3861
  }
4224
3862
  reconnect(timeout = 0) {
@@ -4254,9 +3892,9 @@ class V5SerialDevice extends VexSerialDevice {
4254
3892
  await c.close();
4255
3893
  return import_neverthrow5.err(result.error);
4256
3894
  }
4257
- if (result.value === undefined)
3895
+ if (result.value === "no-port")
4258
3896
  break;
4259
- if (!result.value) {
3897
+ if (result.value === "busy") {
4260
3898
  await c.close();
4261
3899
  continue;
4262
3900
  }
@@ -4299,7 +3937,10 @@ class V5SerialDevice extends VexSerialDevice {
4299
3937
  if (this.connection == null)
4300
3938
  return;
4301
3939
  this.connection.on("disconnected", (_data) => {
4302
- if (this.autoReconnect && !this._isDisconnecting) {
3940
+ if (this._isDisconnecting)
3941
+ return;
3942
+ this.emit("disconnected", undefined);
3943
+ if (this.autoReconnect) {
4303
3944
  this.reconnect().mapErr((e) => this.emit("error", e));
4304
3945
  }
4305
3946
  });
@@ -4397,7 +4038,8 @@ class V5SerialDevice extends VexSerialDevice {
4397
4038
  },
4398
4039
  {
4399
4040
  battery: controller1Battery,
4400
- isAvailable: controller1Available
4041
+ isAvailable: controller1Available,
4042
+ isCharging: (flags2 & 128) !== 0
4401
4043
  }
4402
4044
  ],
4403
4045
  radio: {
@@ -4464,23 +4106,22 @@ class IniSectionBuilder extends BaseIniBuilder {
4464
4106
  this.keyTransform = keyTransform;
4465
4107
  }
4466
4108
  addSingleObjProperty(key, maxValueLength) {
4467
- if (this.object[key] == null || this.object[key].toString().length === 0)
4109
+ const value = this.object[key];
4110
+ if (value == null || value.toString().length === 0)
4468
4111
  return;
4469
4112
  const formattedKey = this.keyTransform(key).padEnd(12).slice(0, 12);
4470
- const trimmedVal = this.object[key].toString().slice(0, maxValueLength);
4113
+ const trimmedVal = value.toString().slice(0, maxValueLength);
4471
4114
  const escapedVal = trimmedVal.replace(/["\\\u0000-\u001f\u007f]/g, (character) => `\\x${character.charCodeAt(0).toString(16).padStart(2, "0")}`);
4472
4115
  this.addLine(`${formattedKey} = "${escapedVal}"`);
4473
4116
  }
4474
4117
  addObjProperty(key, maxValueLength) {
4475
- const keys = Array.isArray(key) ? key : [key];
4476
- for (const k of keys) {
4118
+ for (const k of Array.isArray(key) ? key : [key]) {
4477
4119
  this.addSingleObjProperty(k, maxValueLength);
4478
4120
  }
4479
4121
  return this;
4480
4122
  }
4481
4123
  addAllObjProps(maxValueLength) {
4482
- const keys = Object.keys(this.object);
4483
- for (const k of keys) {
4124
+ for (const k of Object.keys(this.object)) {
4484
4125
  this.addSingleObjProperty(k, maxValueLength);
4485
4126
  }
4486
4127
  return this;
@@ -4509,21 +4150,15 @@ class ProgramIniConfig {
4509
4150
  date: "",
4510
4151
  timezone: "0"
4511
4152
  };
4512
- config = {};
4153
+ config = { 22: "adi" };
4513
4154
  controller1 = {};
4514
4155
  controller2 = {};
4515
- constructor() {
4516
- this.config = {
4517
- 22: "adi"
4518
- };
4519
- }
4520
4156
  setProgramDate(date) {
4521
- const d = date;
4522
- this.program.date = d.toISOString();
4523
- const tzo = Math.abs(d.getTimezoneOffset());
4524
- const tzh = tzo / 60 >>> 0;
4525
- const tzm = tzo - tzh * 60;
4526
- this.program.timezone = (d.getTimezoneOffset() > 0 ? "-" : "+") + this.dec2(tzh) + ":" + this.dec2(tzm);
4157
+ this.program.date = date.toISOString();
4158
+ const offset = Math.abs(date.getTimezoneOffset());
4159
+ const hours = offset / 60 >>> 0;
4160
+ const minutes = offset - hours * 60;
4161
+ this.program.timezone = (date.getTimezoneOffset() > 0 ? "-" : "+") + this.dec2(hours) + ":" + this.dec2(minutes);
4527
4162
  }
4528
4163
  createIni() {
4529
4164
  if (this.program.date.length === 0) {
@@ -4532,10 +4167,9 @@ class ProgramIniConfig {
4532
4167
  return new IniFileBuilder().addComment("").addComment("VEX program ini file").addComment("Generated by Vex V5 Serial Protocol Library").addComment("").addSection(new IniSectionBuilder("project", this.project).addObjProperty("ide", 16)).addComment("").addSection(new IniSectionBuilder("program", this.program).addObjProperty("name", 32).addObjProperty("description", 256).addObjProperty("icon", 16).addObjProperty("iconalt", 16).addObjProperty("slot", 16)).addComment("").addSection(new IniSectionBuilder("config", this.config, (k) => "port_" + this.dec2(k)).addAllObjProps()).addComment("").addSection(new IniSectionBuilder("controller_1", this.controller1).addAllObjProps()).addComment("").addSection(new IniSectionBuilder("controller_2", this.controller2).addAllObjProps()).getContent();
4533
4168
  }
4534
4169
  dec2(value) {
4535
- const str = ("00" + value.toString(10)).substr(-2, 2);
4536
- return str.toUpperCase();
4170
+ return (value % 100).toString(10).padStart(2, "0").toUpperCase();
4537
4171
  }
4538
4172
  }
4539
4173
 
4540
- //# debugId=AF2D48855258B72064756E2164756E21
4174
+ //# debugId=6C653363AF816C0D64756E2164756E21
4541
4175
  //# sourceMappingURL=index.cjs.map