@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.js CHANGED
@@ -200,6 +200,7 @@ var SelectDashScreen;
200
200
  // src/VexError.ts
201
201
  class VexSerialError extends Error {
202
202
  kind;
203
+ ackType = undefined;
203
204
  constructor(kind, message) {
204
205
  super(message);
205
206
  this.name = "VexSerialError";
@@ -222,9 +223,11 @@ class VexInvalidArgumentError extends VexSerialError {
222
223
  }
223
224
 
224
225
  class VexProtocolError extends VexSerialError {
225
- constructor(message) {
226
+ ackType;
227
+ constructor(message, ackType) {
226
228
  super("protocol", message);
227
229
  this.name = "VexProtocolError";
230
+ this.ackType = ackType;
228
231
  }
229
232
  }
230
233
 
@@ -284,9 +287,19 @@ class VexEventEmitter {
284
287
  this.handlerMap.set(eventName, listeners);
285
288
  }
286
289
  emit(eventName, data) {
287
- (this.handlerMap.get(eventName) ?? []).forEach((callback) => {
288
- callback(data);
289
- });
290
+ const errors = [];
291
+ for (const callback of [...this.handlerMap.get(eventName) ?? []]) {
292
+ try {
293
+ callback(data);
294
+ } catch (error) {
295
+ errors.push(error);
296
+ }
297
+ }
298
+ if (errors.length === 1)
299
+ throw errors[0];
300
+ if (errors.length > 1) {
301
+ throw new AggregateError(errors, `listeners for ${String(eventName)} failed`);
302
+ }
290
303
  }
291
304
  clearListeners() {
292
305
  this.handlerMap.clear();
@@ -299,17 +312,20 @@ class VexEventTarget {
299
312
  this.emitter = new VexEventEmitter;
300
313
  }
301
314
  emit(eventName, data) {
302
- this.emitter.emit(String(eventName), data);
315
+ this.emitter.emit(this.normalizeEventName(eventName), data);
303
316
  }
304
317
  on(eventName, listener) {
305
- this.emitter.on(String(eventName), listener);
318
+ this.emitter.on(this.normalizeEventName(eventName), listener);
306
319
  }
307
320
  remove(eventName, listener) {
308
- this.emitter.remove(String(eventName), listener);
321
+ this.emitter.remove(this.normalizeEventName(eventName), listener);
309
322
  }
310
323
  clearListeners() {
311
324
  this.emitter.clearListeners();
312
325
  }
326
+ normalizeEventName(eventName) {
327
+ return String(eventName);
328
+ }
313
329
  }
314
330
 
315
331
  // ../../node_modules/.bun/neverthrow@8.2.0/node_modules/neverthrow/dist/index.es.js
@@ -775,42 +791,32 @@ class Packet {
775
791
  }
776
792
 
777
793
  class DeviceBoundPacket extends Packet {
794
+ static COMMAND_ID;
795
+ static COMMAND_EXTENDED_ID;
778
796
  get commandId() {
779
797
  return this.constructor.COMMAND_ID;
780
798
  }
781
799
  get commandExtendedId() {
782
800
  return this.constructor.COMMAND_EXTENDED_ID;
783
801
  }
784
- static COMMAND_ID;
785
- static COMMAND_EXTENDED_ID;
786
802
  constructor(payload) {
787
- super(new Uint8Array);
788
- const me = this.constructor;
789
- if (me.COMMAND_EXTENDED_ID === undefined) {
790
- if (payload === undefined) {
791
- this.data = Packet.ENCODER.cdcCommand(me.COMMAND_ID);
792
- } else {
793
- this.data = Packet.ENCODER.cdcCommandWithData(me.COMMAND_ID, payload);
794
- }
795
- } else {
796
- if (payload === undefined) {
797
- this.data = Packet.ENCODER.cdc2Command(me.COMMAND_ID, me.COMMAND_EXTENDED_ID);
798
- } else {
799
- this.data = Packet.ENCODER.cdc2CommandWithData(me.COMMAND_ID, me.COMMAND_EXTENDED_ID, payload);
800
- }
801
- }
803
+ const { COMMAND_ID: cmd, COMMAND_EXTENDED_ID: ext } = new.target;
804
+ const encoder = Packet.ENCODER;
805
+ super(ext === undefined ? payload === undefined ? encoder.cdcCommand(cmd) : encoder.cdcCommandWithData(cmd, payload) : payload === undefined ? encoder.cdc2Command(cmd, ext) : encoder.cdc2CommandWithData(cmd, ext, payload));
802
806
  }
803
807
  }
804
808
 
805
809
  class HostBoundPacket extends Packet {
806
- ack = 255 /* CDC2_NACK */;
810
+ static COMMAND_ID;
811
+ static COMMAND_EXTENDED_ID;
812
+ ack;
807
813
  payloadSize;
808
814
  ackIndex;
809
815
  constructor(data) {
810
816
  super(data);
811
817
  this.payloadSize = Packet.ENCODER.getPayloadSize(this.data);
812
- const n = Packet.ENCODER.getHostHeaderLength(this.data);
813
- this.ack = this.data[this.ackIndex = n + 1];
818
+ this.ackIndex = Packet.ENCODER.getHostHeaderLength(this.data) + 1;
819
+ this.ack = this.data[this.ackIndex];
814
820
  }
815
821
  static isValidPacket(data, n) {
816
822
  const ack = data[n + 1];
@@ -819,309 +825,50 @@ class HostBoundPacket extends Packet {
819
825
  }
820
826
 
821
827
  // src/VexCRC.ts
822
- var CRC16TABLE = [
823
- 0,
824
- 4129,
825
- 8258,
826
- 12387,
827
- 16516,
828
- 20645,
829
- 24774,
830
- 28903,
831
- 33032,
832
- 37161,
833
- 41290,
834
- 45419,
835
- 49548,
836
- 53677,
837
- 57806,
838
- 61935,
839
- 4657,
840
- 528,
841
- 12915,
842
- 8786,
843
- 21173,
844
- 17044,
845
- 29431,
846
- 25302,
847
- 37689,
848
- 33560,
849
- 45947,
850
- 41818,
851
- 54205,
852
- 50076,
853
- 62463,
854
- 58334,
855
- 9314,
856
- 13379,
857
- 1056,
858
- 5121,
859
- 25830,
860
- 29895,
861
- 17572,
862
- 21637,
863
- 42346,
864
- 46411,
865
- 34088,
866
- 38153,
867
- 58862,
868
- 62927,
869
- 50604,
870
- 54669,
871
- 13907,
872
- 9842,
873
- 5649,
874
- 1584,
875
- 30423,
876
- 26358,
877
- 22165,
878
- 18100,
879
- 46939,
880
- 42874,
881
- 38681,
882
- 34616,
883
- 63455,
884
- 59390,
885
- 55197,
886
- 51132,
887
- 18628,
888
- 22757,
889
- 26758,
890
- 30887,
891
- 2112,
892
- 6241,
893
- 10242,
894
- 14371,
895
- 51660,
896
- 55789,
897
- 59790,
898
- 63919,
899
- 35144,
900
- 39273,
901
- 43274,
902
- 47403,
903
- 23285,
904
- 19156,
905
- 31415,
906
- 27286,
907
- 6769,
908
- 2640,
909
- 14899,
910
- 10770,
911
- 56317,
912
- 52188,
913
- 64447,
914
- 60318,
915
- 39801,
916
- 35672,
917
- 47931,
918
- 43802,
919
- 27814,
920
- 31879,
921
- 19684,
922
- 23749,
923
- 11298,
924
- 15363,
925
- 3168,
926
- 7233,
927
- 60846,
928
- 64911,
929
- 52716,
930
- 56781,
931
- 44330,
932
- 48395,
933
- 36200,
934
- 40265,
935
- 32407,
936
- 28342,
937
- 24277,
938
- 20212,
939
- 15891,
940
- 11826,
941
- 7761,
942
- 3696,
943
- 65439,
944
- 61374,
945
- 57309,
946
- 53244,
947
- 48923,
948
- 44858,
949
- 40793,
950
- 36728,
951
- 37256,
952
- 33193,
953
- 45514,
954
- 41451,
955
- 53516,
956
- 49453,
957
- 61774,
958
- 57711,
959
- 4224,
960
- 161,
961
- 12482,
962
- 8419,
963
- 20484,
964
- 16421,
965
- 28742,
966
- 24679,
967
- 33721,
968
- 37784,
969
- 41979,
970
- 46042,
971
- 49981,
972
- 54044,
973
- 58239,
974
- 62302,
975
- 689,
976
- 4752,
977
- 8947,
978
- 13010,
979
- 16949,
980
- 21012,
981
- 25207,
982
- 29270,
983
- 46570,
984
- 42443,
985
- 38312,
986
- 34185,
987
- 62830,
988
- 58703,
989
- 54572,
990
- 50445,
991
- 13538,
992
- 9411,
993
- 5280,
994
- 1153,
995
- 29798,
996
- 25671,
997
- 21540,
998
- 17413,
999
- 42971,
1000
- 47098,
1001
- 34713,
1002
- 38840,
1003
- 59231,
1004
- 63358,
1005
- 50973,
1006
- 55100,
1007
- 9939,
1008
- 14066,
1009
- 1681,
1010
- 5808,
1011
- 26199,
1012
- 30326,
1013
- 17941,
1014
- 22068,
1015
- 55628,
1016
- 51565,
1017
- 63758,
1018
- 59695,
1019
- 39368,
1020
- 35305,
1021
- 47498,
1022
- 43435,
1023
- 22596,
1024
- 18533,
1025
- 30726,
1026
- 26663,
1027
- 6336,
1028
- 2273,
1029
- 14466,
1030
- 10403,
1031
- 52093,
1032
- 56156,
1033
- 60223,
1034
- 64286,
1035
- 35833,
1036
- 39896,
1037
- 43963,
1038
- 48026,
1039
- 19061,
1040
- 23124,
1041
- 27191,
1042
- 31254,
1043
- 2801,
1044
- 6864,
1045
- 10931,
1046
- 14994,
1047
- 64814,
1048
- 60687,
1049
- 56684,
1050
- 52557,
1051
- 48554,
1052
- 44427,
1053
- 40424,
1054
- 36297,
1055
- 31782,
1056
- 27655,
1057
- 23652,
1058
- 19525,
1059
- 15522,
1060
- 11395,
1061
- 7392,
1062
- 3265,
1063
- 61215,
1064
- 65342,
1065
- 53085,
1066
- 57212,
1067
- 44955,
1068
- 49082,
1069
- 36825,
1070
- 40952,
1071
- 28183,
1072
- 32310,
1073
- 20053,
1074
- 24180,
1075
- 11923,
1076
- 16050,
1077
- 3793,
1078
- 7920
1079
- ];
828
+ var POLYNOMIAL_CRC32 = 79764919;
829
+ var POLYNOMIAL_CRC16 = 4129;
830
+ function genTable16() {
831
+ const table = new Uint16Array(256);
832
+ for (let i = 0;i < 256; i++) {
833
+ let acc = i << 8;
834
+ for (let j = 0;j < 8; j++) {
835
+ acc = (acc & 32768) !== 0 ? acc << 1 ^ POLYNOMIAL_CRC16 : acc << 1;
836
+ }
837
+ table[i] = acc & 65535;
838
+ }
839
+ return table;
840
+ }
841
+ function genTable32() {
842
+ const table = new Uint32Array(256);
843
+ for (let i = 0;i < 256; i++) {
844
+ let acc = i << 24;
845
+ for (let j = 0;j < 8; j++) {
846
+ acc = (acc & 2147483648) !== 0 ? acc << 1 ^ POLYNOMIAL_CRC32 : acc << 1;
847
+ }
848
+ table[i] = acc;
849
+ }
850
+ return table;
851
+ }
852
+ var CRC16_TABLE = genTable16();
853
+ var CRC32_TABLE = genTable32();
1080
854
 
1081
855
  class CrcGenerator {
1082
- crc32Table;
1083
- static POLYNOMIAL_CRC32 = 79764919;
1084
- static POLYNOMIAL_CRC16 = 4129;
1085
- constructor() {
1086
- this.crc32Table = new Uint32Array(256);
1087
- this.crc32GenTable();
1088
- }
856
+ crc32Table = CRC32_TABLE;
857
+ static POLYNOMIAL_CRC32 = POLYNOMIAL_CRC32;
858
+ static POLYNOMIAL_CRC16 = POLYNOMIAL_CRC16;
1089
859
  crc16(buf, initValue) {
1090
- const numberOfBytes = buf.byteLength;
1091
- let accumulator = initValue;
1092
- let i;
1093
- let j;
1094
- for (j = 0;j < numberOfBytes; j++) {
1095
- i = (accumulator >>> 8 ^ buf[j]) & 255;
1096
- accumulator = (accumulator << 8 ^ CRC16TABLE[i]) >>> 0;
1097
- }
1098
- return (accumulator & 65535) >>> 0;
1099
- }
1100
- crc32GenTable() {
1101
- let i;
1102
- let j;
1103
- let crcAccumulator;
1104
- for (i = 0;i < 256; i++) {
1105
- crcAccumulator = i << 24;
1106
- for (j = 0;j < 8; j++) {
1107
- if ((crcAccumulator & 2147483648) !== 0)
1108
- crcAccumulator = crcAccumulator << 1 ^ CrcGenerator.POLYNOMIAL_CRC32;
1109
- else
1110
- crcAccumulator = crcAccumulator << 1;
1111
- }
1112
- this.crc32Table[i] = crcAccumulator;
860
+ let acc = initValue;
861
+ for (let j = 0;j < buf.length; j++) {
862
+ acc = (acc << 8 ^ CRC16_TABLE[(acc >>> 8 ^ buf[j]) & 255]) >>> 0;
1113
863
  }
864
+ return acc & 65535;
1114
865
  }
1115
866
  crc32(buf, initValue) {
1116
- const numberOfBytes = buf.byteLength;
1117
- let crcAccumulator = initValue;
1118
- let i;
1119
- let j;
1120
- for (j = 0;j < numberOfBytes; j++) {
1121
- i = (crcAccumulator >>> 24 ^ buf[j]) & 255;
1122
- crcAccumulator = (crcAccumulator << 8 ^ this.crc32Table[i]) >>> 0;
867
+ let acc = initValue;
868
+ for (let j = 0;j < buf.length; j++) {
869
+ acc = (acc << 8 ^ CRC32_TABLE[(acc >>> 24 ^ buf[j]) & 255]) >>> 0;
1123
870
  }
1124
- return (crcAccumulator & 4294967295) >>> 0;
871
+ return acc >>> 0;
1125
872
  }
1126
873
  }
1127
874
 
@@ -1213,9 +960,8 @@ class VexFirmwareVersion {
1213
960
  }
1214
961
  static fromString(version) {
1215
962
  const parts = version.toLowerCase().replace(/b/g, "").split(".").map((x) => parseInt(x, 10));
1216
- while (parts.length < 4) {
963
+ while (parts.length < 4)
1217
964
  parts.push(0);
1218
- }
1219
965
  return new VexFirmwareVersion(parts[0], parts[1], parts[2], parts[3]);
1220
966
  }
1221
967
  static fromUint8Array(data, offset = 0, reverse = false) {
@@ -1245,24 +991,23 @@ class VexFirmwareVersion {
1245
991
  return `${this.toUserString()}.b${this.beta}`;
1246
992
  }
1247
993
  compare(that) {
1248
- const majorComp = this.major - that.major;
1249
- const minorComp = this.minor - that.minor;
1250
- const buildComp = this.build - that.build;
1251
- const betaComp = this.beta - that.beta;
1252
- if (majorComp !== 0) {
1253
- return majorComp;
1254
- } else if (minorComp !== 0) {
1255
- return minorComp;
1256
- } else if (buildComp !== 0) {
1257
- return buildComp;
1258
- } else if (betaComp !== 0) {
1259
- return betaComp;
994
+ for (const [a, b] of [
995
+ [this.major, that.major],
996
+ [this.minor, that.minor],
997
+ [this.build, that.build],
998
+ [this.beta, that.beta]
999
+ ]) {
1000
+ const delta = a - b;
1001
+ if (delta !== 0)
1002
+ return delta;
1260
1003
  }
1261
1004
  return 0;
1262
1005
  }
1263
1006
  }
1264
1007
 
1265
1008
  // src/VexPacketView.ts
1009
+ var textDecoder = new TextDecoder("UTF-8");
1010
+
1266
1011
  class PacketView extends DataView {
1267
1012
  position = 0;
1268
1013
  littleEndianDefault = true;
@@ -1275,14 +1020,10 @@ class PacketView extends DataView {
1275
1020
  return view;
1276
1021
  }
1277
1022
  nextInt8() {
1278
- const result = this.getInt8(this.position);
1279
- this.position += 1;
1280
- return result;
1023
+ return this.getInt8(this.position++);
1281
1024
  }
1282
1025
  nextUint8() {
1283
- const result = this.getUint8(this.position);
1284
- this.position += 1;
1285
- return result;
1026
+ return this.getUint8(this.position++);
1286
1027
  }
1287
1028
  nextInt16(littleEndian = this.littleEndianDefault) {
1288
1029
  const result = this.getInt16(this.position, littleEndian);
@@ -1305,37 +1046,28 @@ class PacketView extends DataView {
1305
1046
  return result;
1306
1047
  }
1307
1048
  nextString(length) {
1308
- let result = "";
1309
- for (let i = 0;i < length; i++) {
1310
- result += String.fromCharCode(this.nextUint8());
1311
- }
1049
+ const result = textDecoder.decode(new Uint8Array(this.buffer, this.byteOffset + this.position, length));
1050
+ this.position += length;
1312
1051
  return result;
1313
1052
  }
1314
1053
  nextNTBS(length) {
1315
- let result = "";
1316
- const lastPosition = this.position;
1317
- for (let i = 0;i < length; i++) {
1318
- if (this.byteLength <= this.position)
1319
- break;
1320
- const g = this.nextUint8();
1321
- if (g === 0)
1322
- break;
1323
- result += String.fromCharCode(g);
1324
- }
1325
- this.position = lastPosition + length;
1054
+ const start = this.position;
1055
+ const result = this.nextVarNTBS(length);
1056
+ this.position = start + length;
1326
1057
  return result;
1327
1058
  }
1328
1059
  nextVarNTBS(length) {
1329
- let result = "";
1060
+ const start = this.position;
1061
+ let byteLength = 0;
1330
1062
  for (let i = 0;i < length; i++) {
1331
1063
  if (this.byteLength <= this.position)
1332
1064
  break;
1333
1065
  const g = this.nextUint8();
1334
1066
  if (g === 0)
1335
1067
  break;
1336
- result += String.fromCharCode(g);
1068
+ byteLength++;
1337
1069
  }
1338
- return result;
1070
+ return textDecoder.decode(new Uint8Array(this.buffer, this.byteOffset + start, byteLength));
1339
1071
  }
1340
1072
  nextVersion(reverse = false) {
1341
1073
  const result = VexFirmwareVersion.fromUint8Array(new Uint8Array(this.buffer, this.byteOffset, this.byteLength), this.position, reverse);
@@ -1346,42 +1078,33 @@ class PacketView extends DataView {
1346
1078
 
1347
1079
  // src/VexPacketModels.ts
1348
1080
  var textEncoder = new TextEncoder;
1081
+ function filePayload(a, b, fileName) {
1082
+ const payload = new Uint8Array(26);
1083
+ payload[0] = a;
1084
+ payload[1] = b;
1085
+ payload.set(encodeFixedText(fileName, "Filename", 23), 2);
1086
+ return payload;
1087
+ }
1088
+ var clamp100 = (value) => value !== undefined && value > 100 ? 100 : value;
1349
1089
 
1350
1090
  class Query1H2DPacket extends DeviceBoundPacket {
1351
1091
  static COMMAND_ID = 33;
1352
1092
  static COMMAND_EXTENDED_ID = undefined;
1353
- constructor() {
1354
- super(undefined);
1355
- }
1356
1093
  }
1357
1094
 
1358
1095
  class SystemVersionH2DPacket extends DeviceBoundPacket {
1359
1096
  static COMMAND_ID = 164;
1360
1097
  static COMMAND_EXTENDED_ID = undefined;
1361
- constructor() {
1362
- super(undefined);
1363
- }
1364
1098
  }
1365
1099
 
1366
1100
  class UpdateMatchModeH2DPacket extends DeviceBoundPacket {
1367
1101
  static COMMAND_ID = 88;
1368
1102
  static COMMAND_EXTENDED_ID = 193;
1369
1103
  constructor(mode, matchClock) {
1370
- let bit1;
1371
- switch (mode) {
1372
- case "autonomous":
1373
- bit1 = 10;
1374
- break;
1375
- case "driver":
1376
- bit1 = 8;
1377
- break;
1378
- case "disabled":
1379
- bit1 = 11;
1380
- }
1104
+ const bit1 = mode === "autonomous" ? 10 : mode === "driver" ? 8 : 11;
1381
1105
  const payload = new Uint8Array(5);
1382
- const view = new DataView(payload.buffer);
1383
- payload[0] = (15 & bit1) >>> 0;
1384
- view.setUint32(1, matchClock, true);
1106
+ payload[0] = bit1 & 15;
1107
+ new DataView(payload.buffer).setUint32(1, matchClock, true);
1385
1108
  super(payload);
1386
1109
  }
1387
1110
  }
@@ -1389,18 +1112,13 @@ class UpdateMatchModeH2DPacket extends DeviceBoundPacket {
1389
1112
  class GetMatchStatusH2DPacket extends DeviceBoundPacket {
1390
1113
  static COMMAND_ID = 88;
1391
1114
  static COMMAND_EXTENDED_ID = 194;
1392
- constructor() {
1393
- super(undefined);
1394
- }
1395
1115
  }
1396
1116
 
1397
1117
  class GetRadioModeH2DPacket extends DeviceBoundPacket {
1398
1118
  static COMMAND_ID = 88;
1399
1119
  static COMMAND_EXTENDED_ID = 65;
1400
1120
  constructor(mode) {
1401
- const payload = new Uint8Array(1);
1402
- payload[0] = mode;
1403
- super(payload);
1121
+ super(Uint8Array.of(mode));
1404
1122
  }
1405
1123
  }
1406
1124
 
@@ -1408,9 +1126,7 @@ class FileControlH2DPacket extends DeviceBoundPacket {
1408
1126
  static COMMAND_ID = 86;
1409
1127
  static COMMAND_EXTENDED_ID = 16;
1410
1128
  constructor(a, b) {
1411
- const payload = new Uint8Array(2);
1412
- payload.set([a, b], 0);
1413
- super(payload);
1129
+ super(Uint8Array.of(a, b));
1414
1130
  }
1415
1131
  }
1416
1132
 
@@ -1420,25 +1136,21 @@ class InitFileTransferH2DPacket extends DeviceBoundPacket {
1420
1136
  constructor(operation, target, vendor, options, binary, addr, name, type, version = new VexFirmwareVersion(1, 0, 0, 0)) {
1421
1137
  const payload = new Uint8Array(52);
1422
1138
  const view = new DataView(payload.buffer);
1423
- view.setUint8(0, operation);
1424
- view.setUint8(1, target);
1425
- view.setUint8(2, vendor);
1426
- view.setUint8(3, options);
1139
+ payload[0] = operation;
1140
+ payload[1] = target;
1141
+ payload[2] = vendor;
1142
+ payload[3] = options;
1427
1143
  view.setUint32(4, binary.length, true);
1428
1144
  view.setUint32(8, addr, true);
1429
1145
  view.setUint32(12, operation === 1 /* WRITE */ ? Packet.ENCODER.crcgen.crc32(binary, 0) : 0, true);
1430
- const re = /(?:\.([^.]+))?$/;
1431
- const reResult = re.exec(name);
1432
- let ext = reResult != null ? reResult[1] : undefined;
1433
- ext ??= "";
1434
- ext = ext === "gz" ? "bin" : ext;
1146
+ let ext = /(?:\.([^.]+))?$/.exec(name)?.[1] ?? "";
1147
+ if (ext === "gz")
1148
+ ext = "bin";
1435
1149
  payload.set(encodeFixedText(type ?? ext, "File type", 4), 16);
1436
1150
  const timestamp = (Date.now() / 1000 >>> 0) - PacketEncoder.J2000_EPOCH;
1437
1151
  view.setUint32(20, timestamp, true);
1438
1152
  payload.set(version.toUint8Array(), 24);
1439
- const nameEncoded = encodeFixedText(name, "Filename", 23);
1440
- payload.set(nameEncoded, 28);
1441
- view.setUint8(51, 0);
1153
+ payload.set(encodeFixedText(name, "Filename", 23), 28);
1442
1154
  super(payload);
1443
1155
  }
1444
1156
  }
@@ -1447,9 +1159,7 @@ class ExitFileTransferH2DPacket extends DeviceBoundPacket {
1447
1159
  static COMMAND_ID = 86;
1448
1160
  static COMMAND_EXTENDED_ID = 18;
1449
1161
  constructor(action) {
1450
- const payload = new Uint8Array(1);
1451
- payload[0] = action;
1452
- super(payload);
1162
+ super(Uint8Array.of(action));
1453
1163
  }
1454
1164
  }
1455
1165
 
@@ -1458,8 +1168,7 @@ class WriteFileH2DPacket extends DeviceBoundPacket {
1458
1168
  static COMMAND_EXTENDED_ID = 19;
1459
1169
  constructor(addr, buf) {
1460
1170
  const payload = new Uint8Array(4 + buf.length);
1461
- const view = new DataView(payload.buffer);
1462
- view.setUint32(0, addr, true);
1171
+ new DataView(payload.buffer).setUint32(0, addr, true);
1463
1172
  payload.set(buf, 4);
1464
1173
  super(payload);
1465
1174
  }
@@ -1481,11 +1190,7 @@ class LinkFileH2DPacket extends DeviceBoundPacket {
1481
1190
  static COMMAND_ID = 86;
1482
1191
  static COMMAND_EXTENDED_ID = 21;
1483
1192
  constructor(vendor, fileName, options) {
1484
- const str = encodeFixedText(fileName, "Filename", 23);
1485
- const payload = new Uint8Array(26);
1486
- payload.set([vendor, options], 0);
1487
- payload.set(str, 2);
1488
- super(payload);
1193
+ super(filePayload(vendor, options, fileName));
1489
1194
  }
1490
1195
  }
1491
1196
 
@@ -1493,9 +1198,7 @@ class GetDirectoryFileCountH2DPacket extends DeviceBoundPacket {
1493
1198
  static COMMAND_ID = 86;
1494
1199
  static COMMAND_EXTENDED_ID = 22;
1495
1200
  constructor(vendor) {
1496
- const payload = new Uint8Array(2);
1497
- payload.set([vendor, 0], 0);
1498
- super(payload);
1201
+ super(Uint8Array.of(vendor, 0));
1499
1202
  }
1500
1203
  }
1501
1204
 
@@ -1503,9 +1206,7 @@ class GetDirectoryEntryH2DPacket extends DeviceBoundPacket {
1503
1206
  static COMMAND_ID = 86;
1504
1207
  static COMMAND_EXTENDED_ID = 23;
1505
1208
  constructor(index) {
1506
- const payload = new Uint8Array(2);
1507
- payload.set([index, 0], 0);
1508
- super(payload);
1209
+ super(Uint8Array.of(index, 0));
1509
1210
  }
1510
1211
  }
1511
1212
 
@@ -1513,17 +1214,8 @@ class LoadFileActionH2DPacket extends DeviceBoundPacket {
1513
1214
  static COMMAND_ID = 86;
1514
1215
  static COMMAND_EXTENDED_ID = 24;
1515
1216
  constructor(vendor, actionId, fileNameOrSlotNumber) {
1516
- let fileName;
1517
- if (typeof fileNameOrSlotNumber === "string") {
1518
- fileName = fileNameOrSlotNumber;
1519
- } else {
1520
- fileName = "___s_" + (fileNameOrSlotNumber - 1) + ".bin";
1521
- }
1522
- const encodedName = encodeFixedText(fileName, "Filename", 23);
1523
- const payload = new Uint8Array(26);
1524
- payload.set([vendor, actionId], 0);
1525
- payload.set(encodedName, 2);
1526
- super(payload);
1217
+ const fileName = typeof fileNameOrSlotNumber === "string" ? fileNameOrSlotNumber : `___s_${fileNameOrSlotNumber - 1}.bin`;
1218
+ super(filePayload(vendor, actionId, fileName));
1527
1219
  }
1528
1220
  }
1529
1221
 
@@ -1531,11 +1223,7 @@ class GetFileMetadataH2DPacket extends DeviceBoundPacket {
1531
1223
  static COMMAND_ID = 86;
1532
1224
  static COMMAND_EXTENDED_ID = 25;
1533
1225
  constructor(vendor, fileName, options) {
1534
- const encodedName = encodeFixedText(fileName, "Filename", 23);
1535
- const payload = new Uint8Array(26);
1536
- payload.set([vendor, options], 0);
1537
- payload.set(encodedName, 2);
1538
- super(payload);
1226
+ super(filePayload(vendor, options, fileName));
1539
1227
  }
1540
1228
  }
1541
1229
 
@@ -1543,11 +1231,7 @@ class EraseFileH2DPacket extends DeviceBoundPacket {
1543
1231
  static COMMAND_ID = 86;
1544
1232
  static COMMAND_EXTENDED_ID = 27;
1545
1233
  constructor(vendor, fileName) {
1546
- const encodedName = encodeFixedText(fileName, "Filename", 23);
1547
- const payload = new Uint8Array(26);
1548
- payload.set([vendor, 128], 0);
1549
- payload.set(encodedName, 2);
1550
- super(payload);
1234
+ super(filePayload(vendor, 128, fileName));
1551
1235
  }
1552
1236
  }
1553
1237
 
@@ -1555,11 +1239,7 @@ class GetProgramSlotInfoH2DPacket extends DeviceBoundPacket {
1555
1239
  static COMMAND_ID = 86;
1556
1240
  static COMMAND_EXTENDED_ID = 28;
1557
1241
  constructor(vendor, fileName) {
1558
- const encodedName = encodeFixedText(fileName, "Filename", 23);
1559
- const payload = new Uint8Array(26);
1560
- payload.set([vendor, 0], 0);
1561
- payload.set(encodedName, 2);
1562
- super(payload);
1242
+ super(filePayload(vendor, 0, fileName));
1563
1243
  }
1564
1244
  }
1565
1245
 
@@ -1567,9 +1247,7 @@ class FileClearUpH2DPacket extends DeviceBoundPacket {
1567
1247
  static COMMAND_ID = 86;
1568
1248
  static COMMAND_EXTENDED_ID = 30;
1569
1249
  constructor(vendor) {
1570
- const payload = new Uint8Array(2);
1571
- payload.set([vendor, 0], 0);
1572
- super(payload);
1250
+ super(Uint8Array.of(vendor, 0));
1573
1251
  }
1574
1252
  }
1575
1253
 
@@ -1577,9 +1255,7 @@ class FileFormatH2DPacket extends DeviceBoundPacket {
1577
1255
  static COMMAND_ID = 86;
1578
1256
  static COMMAND_EXTENDED_ID = 31;
1579
1257
  constructor() {
1580
- const payload = new Uint8Array(4);
1581
- payload.set([68, 67, 66, 65], 0);
1582
- super(payload);
1258
+ super(Uint8Array.of(68, 67, 66, 65));
1583
1259
  }
1584
1260
  }
1585
1261
 
@@ -1591,33 +1267,21 @@ class GetSystemFlagsH2DPacket extends DeviceBoundPacket {
1591
1267
  class GetDeviceStatusH2DPacket extends DeviceBoundPacket {
1592
1268
  static COMMAND_ID = 86;
1593
1269
  static COMMAND_EXTENDED_ID = 33;
1594
- constructor() {
1595
- super(undefined);
1596
- }
1597
1270
  }
1598
1271
 
1599
1272
  class GetSystemStatusH2DPacket extends DeviceBoundPacket {
1600
1273
  static COMMAND_ID = 86;
1601
1274
  static COMMAND_EXTENDED_ID = 34;
1602
- constructor() {
1603
- super(undefined);
1604
- }
1605
1275
  }
1606
1276
 
1607
1277
  class GetFdtStatusH2DPacket extends DeviceBoundPacket {
1608
1278
  static COMMAND_ID = 86;
1609
1279
  static COMMAND_EXTENDED_ID = 35;
1610
- constructor() {
1611
- super(undefined);
1612
- }
1613
1280
  }
1614
1281
 
1615
1282
  class GetLogCountH2DPacket extends DeviceBoundPacket {
1616
1283
  static COMMAND_ID = 86;
1617
1284
  static COMMAND_EXTENDED_ID = 36;
1618
- constructor() {
1619
- super(undefined);
1620
- }
1621
1285
  }
1622
1286
 
1623
1287
  class ReadLogPageH2DPacket extends DeviceBoundPacket {
@@ -1635,18 +1299,13 @@ class ReadLogPageH2DPacket extends DeviceBoundPacket {
1635
1299
  class GetRadioStatusH2DPacket extends DeviceBoundPacket {
1636
1300
  static COMMAND_ID = 86;
1637
1301
  static COMMAND_EXTENDED_ID = 38;
1638
- constructor() {
1639
- super(undefined);
1640
- }
1641
1302
  }
1642
1303
 
1643
1304
  class ScreenCaptureH2DPacket extends DeviceBoundPacket {
1644
1305
  static COMMAND_ID = 86;
1645
1306
  static COMMAND_EXTENDED_ID = 40;
1646
1307
  constructor(e) {
1647
- const payload = new Uint8Array(1);
1648
- payload[0] = e;
1649
- super(payload);
1308
+ super(Uint8Array.of(e));
1650
1309
  }
1651
1310
  }
1652
1311
 
@@ -1667,10 +1326,7 @@ class SelectDashH2DPacket extends DeviceBoundPacket {
1667
1326
  static COMMAND_ID = 86;
1668
1327
  static COMMAND_EXTENDED_ID = 43;
1669
1328
  constructor(screen, port) {
1670
- const payload = new Uint8Array(2);
1671
- payload[0] = screen;
1672
- payload[1] = port;
1673
- super(payload);
1329
+ super(Uint8Array.of(screen, port));
1674
1330
  }
1675
1331
  }
1676
1332
 
@@ -1678,9 +1334,8 @@ class ReadKeyValueH2DPacket extends DeviceBoundPacket {
1678
1334
  static COMMAND_ID = 86;
1679
1335
  static COMMAND_EXTENDED_ID = 46;
1680
1336
  constructor(key) {
1681
- const encodedKey = encodeFixedText(key, "Key", 31);
1682
1337
  const payload = new Uint8Array(32);
1683
- payload.set(encodedKey, 0);
1338
+ payload.set(encodeFixedText(key, "Key", 31), 0);
1684
1339
  super(payload);
1685
1340
  }
1686
1341
  }
@@ -1704,17 +1359,11 @@ class WriteKeyValueH2DPacket extends DeviceBoundPacket {
1704
1359
  class GetSlot1to4InfoH2DPacket extends DeviceBoundPacket {
1705
1360
  static COMMAND_ID = 86;
1706
1361
  static COMMAND_EXTENDED_ID = 49;
1707
- constructor() {
1708
- super(undefined);
1709
- }
1710
1362
  }
1711
1363
 
1712
1364
  class GetSlot5to8InfoH2DPacket extends DeviceBoundPacket {
1713
1365
  static COMMAND_ID = 86;
1714
1366
  static COMMAND_EXTENDED_ID = 50;
1715
- constructor() {
1716
- super(undefined);
1717
- }
1718
1367
  }
1719
1368
 
1720
1369
  class FactoryStatusH2DPacket extends DeviceBoundPacket {
@@ -1726,9 +1375,7 @@ class FactoryEnableH2DPacket extends DeviceBoundPacket {
1726
1375
  static COMMAND_ID = 86;
1727
1376
  static COMMAND_EXTENDED_ID = 255;
1728
1377
  constructor() {
1729
- const payload = new Uint8Array(4);
1730
- payload.set([77, 76, 75, 74], 0);
1731
- super(payload);
1378
+ super(Uint8Array.of(77, 76, 75, 74));
1732
1379
  }
1733
1380
  }
1734
1381
 
@@ -1770,8 +1417,7 @@ class MatchModeReplyD2HPacket extends HostBoundPacket {
1770
1417
  modebit;
1771
1418
  constructor(data) {
1772
1419
  super(data);
1773
- const dataView = PacketView.fromPacket(this);
1774
- this.modebit = dataView.nextUint8();
1420
+ this.modebit = PacketView.fromPacket(this).nextUint8();
1775
1421
  }
1776
1422
  }
1777
1423
 
@@ -1797,31 +1443,27 @@ class MatchStatusReplyD2HPacket extends HostBoundPacket {
1797
1443
  rxSignalQuality;
1798
1444
  constructor(data) {
1799
1445
  super(data);
1800
- const dataView = PacketView.fromPacket(this);
1446
+ const view = PacketView.fromPacket(this);
1801
1447
  const n = this.ackIndex;
1802
- this.rssi = dataView.nextInt8();
1803
- this.systemStatusBits = dataView.nextUint16();
1804
- this.radioStatusBits = dataView.nextUint16();
1805
- this.fieldStatusBits = dataView.nextUint8();
1806
- this.matchClock = dataView.nextUint8();
1807
- this.brainBatteryPercent = dataView.nextUint8();
1808
- this.controllerBatteryPercent = dataView.nextUint8();
1809
- this.partnerControllerBatteryPercent = dataView.nextUint8();
1810
- this.pad = dataView.nextUint8();
1811
- this.buttons = dataView.nextUint16();
1812
- this.activeProgram = dataView.nextUint8();
1813
- this.radioType = dataView.nextUint8();
1814
- this.radioChannel = dataView.nextUint8();
1815
- this.radioSlot = dataView.nextUint8();
1816
- this.robotName = dataView.nextNTBS(10);
1817
- this.controllerFlags = dataView.getUint8(n + 28);
1818
- this.rxSignalQuality = dataView.getUint8(n + 29);
1819
- let rawStr = new TextDecoder("UTF-8").decode(data.slice(n + 18, n + this.payloadSize + 28));
1820
- const endIdx = rawStr.indexOf("\x00");
1821
- if (endIdx > -1) {
1822
- rawStr = rawStr.substr(0, endIdx);
1823
- }
1824
- this.robotName = rawStr;
1448
+ this.rssi = view.nextInt8();
1449
+ this.systemStatusBits = view.nextUint16();
1450
+ this.radioStatusBits = view.nextUint16();
1451
+ this.fieldStatusBits = view.nextUint8();
1452
+ this.matchClock = view.nextUint8();
1453
+ this.brainBatteryPercent = view.nextUint8();
1454
+ this.controllerBatteryPercent = view.nextUint8();
1455
+ this.partnerControllerBatteryPercent = view.nextUint8();
1456
+ this.pad = view.nextUint8();
1457
+ this.buttons = view.nextUint16();
1458
+ this.activeProgram = view.nextUint8();
1459
+ this.radioType = view.nextUint8();
1460
+ this.radioChannel = view.nextUint8();
1461
+ this.radioSlot = view.nextUint8();
1462
+ this.controllerFlags = view.getUint8(n + 28);
1463
+ this.rxSignalQuality = view.getUint8(n + 29);
1464
+ const raw = new TextDecoder("UTF-8").decode(this.data.slice(n + 18, n + this.payloadSize + 28));
1465
+ const end = raw.indexOf("\x00");
1466
+ this.robotName = end > -1 ? raw.slice(0, end) : raw;
1825
1467
  }
1826
1468
  }
1827
1469
 
@@ -1838,10 +1480,10 @@ class InitFileTransferReplyD2HPacket extends HostBoundPacket {
1838
1480
  crc32;
1839
1481
  constructor(data) {
1840
1482
  super(data);
1841
- const dataView = PacketView.fromPacket(this);
1842
- this.windowSize = dataView.nextUint16();
1843
- this.fileSize = dataView.nextUint32();
1844
- this.crc32 = dataView.nextUint32();
1483
+ const view = PacketView.fromPacket(this);
1484
+ this.windowSize = view.nextUint16();
1485
+ this.fileSize = view.nextUint32();
1486
+ this.crc32 = view.nextUint32();
1845
1487
  }
1846
1488
  }
1847
1489
 
@@ -1863,13 +1505,10 @@ class ReadFileReplyD2HPacket extends HostBoundPacket {
1863
1505
  buf;
1864
1506
  constructor(data) {
1865
1507
  super(data);
1866
- const dataView = PacketView.fromPacket(this);
1867
- this.addr = dataView.nextUint32();
1508
+ const view = PacketView.fromPacket(this);
1509
+ this.addr = view.nextUint32();
1868
1510
  this.length = this.payloadSize - 8;
1869
- this.buf = this.data.slice(dataView.position, dataView.position + this.length).buffer;
1870
- }
1871
- static isValidPacket(data, n) {
1872
- return super.isValidPacket(data, n);
1511
+ this.buf = this.data.slice(view.position, view.position + this.length).buffer;
1873
1512
  }
1874
1513
  }
1875
1514
 
@@ -1884,8 +1523,7 @@ class GetDirectoryFileCountReplyD2HPacket extends HostBoundPacket {
1884
1523
  count;
1885
1524
  constructor(data) {
1886
1525
  super(data);
1887
- const dataView = PacketView.fromPacket(this);
1888
- this.count = dataView.nextUint16();
1526
+ this.count = PacketView.fromPacket(this).nextUint16();
1889
1527
  }
1890
1528
  }
1891
1529
 
@@ -1895,19 +1533,19 @@ class GetDirectoryEntryReplyD2HPacket extends HostBoundPacket {
1895
1533
  file;
1896
1534
  constructor(data) {
1897
1535
  super(data);
1898
- const dataView = PacketView.fromPacket(this);
1899
- if (this.payloadSize > 4) {
1900
- this.file = {
1901
- index: dataView.nextUint8(),
1902
- size: dataView.nextUint32(),
1903
- loadAddress: dataView.nextUint32(),
1904
- crc32: dataView.nextUint32(),
1905
- type: dataView.nextString(4),
1906
- timestamp: dataView.nextUint32() + PacketEncoder.J2000_EPOCH,
1907
- version: dataView.nextVersion(),
1908
- filename: dataView.nextNTBS(32)
1909
- };
1910
- }
1536
+ if (this.payloadSize <= 4)
1537
+ return;
1538
+ const view = PacketView.fromPacket(this);
1539
+ this.file = {
1540
+ index: view.nextUint8(),
1541
+ size: view.nextUint32(),
1542
+ loadAddress: view.nextUint32(),
1543
+ crc32: view.nextUint32(),
1544
+ type: view.nextString(4),
1545
+ timestamp: view.nextUint32() + PacketEncoder.J2000_EPOCH,
1546
+ version: view.nextVersion(),
1547
+ filename: view.nextNTBS(32)
1548
+ };
1911
1549
  }
1912
1550
  }
1913
1551
 
@@ -1922,18 +1560,18 @@ class GetFileMetadataReplyD2HPacket extends HostBoundPacket {
1922
1560
  file;
1923
1561
  constructor(data) {
1924
1562
  super(data);
1925
- const dataView = PacketView.fromPacket(this);
1926
- dataView.nextUint8();
1927
- if (this.payloadSize > 4) {
1928
- this.file = {
1929
- size: dataView.nextUint32(),
1930
- loadAddress: dataView.nextUint32(),
1931
- crc32: dataView.nextUint32(),
1932
- type: dataView.nextString(4),
1933
- timestamp: dataView.nextUint32() + PacketEncoder.J2000_EPOCH,
1934
- version: dataView.nextVersion()
1935
- };
1936
- }
1563
+ if (this.payloadSize <= 4)
1564
+ return;
1565
+ const view = PacketView.fromPacket(this);
1566
+ view.nextUint8();
1567
+ this.file = {
1568
+ size: view.nextUint32(),
1569
+ loadAddress: view.nextUint32(),
1570
+ crc32: view.nextUint32(),
1571
+ type: view.nextString(4),
1572
+ timestamp: view.nextUint32() + PacketEncoder.J2000_EPOCH,
1573
+ version: view.nextVersion()
1574
+ };
1937
1575
  }
1938
1576
  }
1939
1577
 
@@ -1949,9 +1587,9 @@ class GetProgramSlotInfoReplyD2HPacket extends HostBoundPacket {
1949
1587
  slot;
1950
1588
  constructor(data) {
1951
1589
  super(data);
1952
- const dataView = PacketView.fromPacket(this);
1953
- this.slot = dataView.nextUint8();
1954
- this.requestedSlot = dataView.nextUint8();
1590
+ const view = PacketView.fromPacket(this);
1591
+ this.slot = view.nextUint8();
1592
+ this.requestedSlot = view.nextUint8();
1955
1593
  }
1956
1594
  }
1957
1595
 
@@ -1969,40 +1607,32 @@ class GetSystemFlagsReplyD2HPacket extends HostBoundPacket {
1969
1607
  static COMMAND_ID = 86;
1970
1608
  static COMMAND_EXTENDED_ID = 32;
1971
1609
  flags;
1972
- radioSearching;
1610
+ radioSearching = false;
1973
1611
  radioQuality;
1974
1612
  controllerBatteryPercent;
1975
1613
  partnerControllerBatteryPercent;
1976
1614
  battery;
1977
- currentProgram;
1615
+ currentProgram = 0;
1978
1616
  constructor(data) {
1979
1617
  super(data);
1980
- const dataView = PacketView.fromPacket(this);
1981
- this.radioSearching = false;
1982
- this.currentProgram = 0;
1983
- this.flags = dataView.nextUint32();
1618
+ const view = PacketView.fromPacket(this);
1619
+ this.flags = view.nextUint32();
1984
1620
  const hasPartner = (8192 & this.flags) !== 0;
1985
1621
  const hasRadio = (1536 & this.flags) === 1536;
1986
- const byte1 = dataView.nextUint8();
1987
- const byte2 = dataView.nextUint8();
1622
+ const byte1 = view.nextUint8();
1623
+ const byte2 = view.nextUint8();
1988
1624
  if (this.payloadSize === 11) {
1989
- this.battery = 8 * (byte1 & 15);
1990
- if ((this.flags & 256) !== 0 || hasRadio)
1991
- this.controllerBatteryPercent = 8 * (byte1 >> 4 & 15);
1625
+ this.battery = clamp100(8 * (byte1 & 15));
1626
+ if ((this.flags & 256) !== 0 || hasRadio) {
1627
+ this.controllerBatteryPercent = clamp100(8 * (byte1 >> 4 & 15));
1628
+ }
1992
1629
  if (hasRadio)
1993
- this.radioQuality = 8 * (byte2 & 15);
1630
+ this.radioQuality = clamp100(8 * (byte2 & 15));
1994
1631
  this.radioSearching = (this.flags & 1536) === 512;
1995
- if (hasPartner)
1996
- this.partnerControllerBatteryPercent = 8 * (byte2 >> 4 & 15);
1997
- this.currentProgram = dataView.nextUint8();
1998
- if (this.battery != null && this.battery > 100)
1999
- this.battery = 100;
2000
- if (this.controllerBatteryPercent != null && this.controllerBatteryPercent > 100)
2001
- this.controllerBatteryPercent = 100;
2002
- if (this.radioQuality != null && this.radioQuality > 100)
2003
- this.radioQuality = 100;
2004
- if (this.partnerControllerBatteryPercent != null && this.partnerControllerBatteryPercent > 100)
2005
- this.partnerControllerBatteryPercent = 100;
1632
+ if (hasPartner) {
1633
+ this.partnerControllerBatteryPercent = clamp100(8 * (byte2 >> 4 & 15));
1634
+ }
1635
+ this.currentProgram = view.nextUint8();
2006
1636
  }
2007
1637
  }
2008
1638
  }
@@ -2014,17 +1644,17 @@ class GetDeviceStatusReplyD2HPacket extends HostBoundPacket {
2014
1644
  devices;
2015
1645
  constructor(data) {
2016
1646
  super(data);
2017
- const dataView = PacketView.fromPacket(this);
2018
- this.count = dataView.nextUint8();
1647
+ const view = PacketView.fromPacket(this);
1648
+ this.count = view.nextUint8();
2019
1649
  this.devices = [];
2020
1650
  for (let i = 0;i < this.count; i++) {
2021
1651
  this.devices.push({
2022
- port: dataView.nextUint8(),
2023
- type: dataView.nextUint8(),
2024
- status: dataView.nextUint8(),
2025
- betaversion: dataView.nextUint8(),
2026
- version: dataView.nextUint16(),
2027
- bootversion: dataView.nextUint16()
1652
+ port: view.nextUint8(),
1653
+ type: view.nextUint8(),
1654
+ status: view.nextUint8(),
1655
+ betaversion: view.nextUint8(),
1656
+ version: view.nextUint16(),
1657
+ bootversion: view.nextUint16()
2028
1658
  });
2029
1659
  }
2030
1660
  }
@@ -2036,48 +1666,42 @@ class GetSystemStatusReplyD2HPacket extends HostBoundPacket {
2036
1666
  systemVersion;
2037
1667
  cpu0Version;
2038
1668
  cpu1Version;
2039
- nxpVersion;
1669
+ nxpVersion = VexFirmwareVersion.allZero();
2040
1670
  touchVersion;
2041
- uniqueId;
2042
- sysflags;
2043
- eventBrain;
2044
- romBootloaderActive;
2045
- ramBootloaderActive;
2046
- goldenVersion;
1671
+ uniqueId = 1234;
1672
+ sysflags = [0, 0, 0, 0, 0, 0, 0];
1673
+ eventBrain = false;
1674
+ romBootloaderActive = false;
1675
+ ramBootloaderActive = false;
1676
+ goldenVersion = VexFirmwareVersion.allZero();
2047
1677
  constructor(data) {
2048
1678
  super(data);
2049
- const dataView = PacketView.fromPacket(this);
2050
- dataView.nextUint8();
2051
- this.systemVersion = dataView.nextVersion();
2052
- this.cpu0Version = dataView.nextVersion();
2053
- this.cpu1Version = dataView.nextVersion();
2054
- this.touchVersion = dataView.nextVersion(true);
2055
- this.uniqueId = 1234;
2056
- this.sysflags = [0, 0, 0, 0, 0, 0, 0];
2057
- this.goldenVersion = VexFirmwareVersion.allZero();
2058
- this.nxpVersion = VexFirmwareVersion.allZero();
2059
- this.eventBrain = false;
2060
- this.romBootloaderActive = false;
2061
- this.ramBootloaderActive = false;
1679
+ const view = PacketView.fromPacket(this);
1680
+ view.nextUint8();
1681
+ this.systemVersion = view.nextVersion();
1682
+ this.cpu0Version = view.nextVersion();
1683
+ this.cpu1Version = view.nextVersion();
1684
+ this.touchVersion = view.nextVersion(true);
2062
1685
  if (this.payloadSize > 25) {
2063
- this.uniqueId = dataView.nextUint32();
1686
+ this.uniqueId = view.nextUint32();
2064
1687
  this.sysflags = [
2065
- dataView.nextUint8(),
2066
- dataView.nextUint8(),
2067
- dataView.nextUint8(),
2068
- dataView.nextUint8(),
2069
- dataView.nextUint8(),
1688
+ view.nextUint8(),
1689
+ view.nextUint8(),
1690
+ view.nextUint8(),
1691
+ view.nextUint8(),
1692
+ view.nextUint8(),
2070
1693
  0,
2071
- dataView.nextUint8()
1694
+ view.nextUint8()
2072
1695
  ];
2073
- this.eventBrain = (1 & this.sysflags[6]) !== 0;
2074
- this.romBootloaderActive = (2 & this.sysflags[6]) !== 0;
2075
- this.ramBootloaderActive = (4 & this.sysflags[6]) !== 0;
2076
- dataView.nextUint16();
2077
- this.goldenVersion = dataView.nextVersion();
1696
+ const flags6 = this.sysflags[6];
1697
+ this.eventBrain = (1 & flags6) !== 0;
1698
+ this.romBootloaderActive = (2 & flags6) !== 0;
1699
+ this.ramBootloaderActive = (4 & flags6) !== 0;
1700
+ view.nextUint16();
1701
+ this.goldenVersion = view.nextVersion();
2078
1702
  }
2079
1703
  if (this.payloadSize > 37) {
2080
- this.nxpVersion = dataView.nextVersion();
1704
+ this.nxpVersion = view.nextVersion();
2081
1705
  }
2082
1706
  }
2083
1707
  }
@@ -2089,17 +1713,17 @@ class GetFdtStatusReplyD2HPacket extends HostBoundPacket {
2089
1713
  status;
2090
1714
  constructor(data) {
2091
1715
  super(data);
2092
- const dataView = PacketView.fromPacket(this);
2093
- this.count = dataView.nextUint8();
1716
+ const view = PacketView.fromPacket(this);
1717
+ this.count = view.nextUint8();
2094
1718
  this.status = [];
2095
1719
  for (let i = 0;i < this.count; i++) {
2096
1720
  this.status.push({
2097
- index: dataView.nextUint8(),
2098
- type: dataView.nextUint8(),
2099
- status: dataView.nextUint8(),
2100
- betaversion: dataView.nextUint8(),
2101
- version: dataView.nextUint16(),
2102
- bootversion: dataView.nextUint16()
1721
+ index: view.nextUint8(),
1722
+ type: view.nextUint8(),
1723
+ status: view.nextUint8(),
1724
+ betaversion: view.nextUint8(),
1725
+ version: view.nextUint16(),
1726
+ bootversion: view.nextUint16()
2103
1727
  });
2104
1728
  }
2105
1729
  }
@@ -2111,9 +1735,9 @@ class GetLogCountReplyD2HPacket extends HostBoundPacket {
2111
1735
  count;
2112
1736
  constructor(data) {
2113
1737
  super(data);
2114
- const dataView = PacketView.fromPacket(this);
2115
- dataView.nextUint8();
2116
- this.count = dataView.nextUint32();
1738
+ const view = PacketView.fromPacket(this);
1739
+ view.nextUint8();
1740
+ this.count = view.nextUint32();
2117
1741
  }
2118
1742
  }
2119
1743
 
@@ -2125,20 +1749,19 @@ class ReadLogPageReplyD2HPacket extends HostBoundPacket {
2125
1749
  entries;
2126
1750
  constructor(data) {
2127
1751
  super(data);
2128
- const dataView = PacketView.fromPacket(this);
2129
- const n = this.ackIndex;
2130
- const size = dataView.nextUint8();
2131
- this.offset = dataView.nextUint32();
2132
- this.count = dataView.nextUint16();
1752
+ const view = PacketView.fromPacket(this);
1753
+ const size = view.nextUint8();
1754
+ this.offset = view.nextUint32();
1755
+ this.count = view.nextUint16();
2133
1756
  this.entries = [];
2134
- let j = n + 8;
1757
+ let j = this.ackIndex + 8;
2135
1758
  for (let i = 0;i < this.count; i++) {
2136
1759
  this.entries.push({
2137
- code: dataView.getUint8(j),
2138
- type: dataView.getUint8(j + 1),
2139
- desc: dataView.getUint8(j + 2),
2140
- spare: dataView.getUint8(j + 3),
2141
- time: dataView.getUint32(j + 4, true)
1760
+ code: view.getUint8(j),
1761
+ type: view.getUint8(j + 1),
1762
+ desc: view.getUint8(j + 2),
1763
+ spare: view.getUint8(j + 3),
1764
+ time: view.getUint32(j + 4, true)
2142
1765
  });
2143
1766
  j += size;
2144
1767
  }
@@ -2155,13 +1778,12 @@ class GetRadioStatusReplyD2HPacket extends HostBoundPacket {
2155
1778
  timeslot;
2156
1779
  constructor(data) {
2157
1780
  super(data);
2158
- const dataView = PacketView.fromPacket(this);
2159
- const n = this.ackIndex;
2160
- this.device = dataView.nextUint8();
2161
- this.quality = dataView.nextUint16();
2162
- this.strength = dataView.nextInt16();
2163
- this.channel = this.data[n + 6];
2164
- this.timeslot = this.data[n + 7];
1781
+ const view = PacketView.fromPacket(this);
1782
+ this.device = view.nextUint8();
1783
+ this.quality = view.nextUint16();
1784
+ this.strength = view.nextInt16();
1785
+ this.channel = this.data[this.ackIndex + 6];
1786
+ this.timeslot = this.data[this.ackIndex + 7];
2165
1787
  }
2166
1788
  }
2167
1789
 
@@ -2186,8 +1808,7 @@ class ReadKeyValueReplyD2HPacket extends HostBoundPacket {
2186
1808
  value;
2187
1809
  constructor(data) {
2188
1810
  super(data);
2189
- const dataView = PacketView.fromPacket(this);
2190
- this.value = dataView.nextVarNTBS(255);
1811
+ this.value = PacketView.fromPacket(this).nextVarNTBS(255);
2191
1812
  }
2192
1813
  }
2193
1814
 
@@ -2203,20 +1824,18 @@ class GetSlot1to4InfoReplyD2HPacket extends HostBoundPacket {
2203
1824
  slots;
2204
1825
  constructor(data, start = 1) {
2205
1826
  super(data);
2206
- const dataView = PacketView.fromPacket(this);
2207
- this.slotFlags = dataView.nextUint8();
1827
+ const view = PacketView.fromPacket(this);
1828
+ this.slotFlags = view.nextUint8();
2208
1829
  this.slots = [];
2209
1830
  for (let i = 0;i < 4; i++) {
2210
- const hasData = (this.slotFlags & 2 ** (start - 1 + i)) !== 0;
2211
- if (!hasData)
1831
+ if ((this.slotFlags & 1 << start - 1 + i) === 0)
2212
1832
  continue;
2213
- const iconNum = dataView.nextUint16();
2214
- const nameLen = dataView.nextUint8();
2215
- const name = dataView.nextString(nameLen);
1833
+ const icon = view.nextUint16();
1834
+ const nameLen = view.nextUint8();
2216
1835
  this.slots.push({
2217
1836
  slot: start + i,
2218
- icon: iconNum,
2219
- name
1837
+ icon,
1838
+ name: view.nextString(nameLen)
2220
1839
  });
2221
1840
  }
2222
1841
  }
@@ -2238,9 +1857,9 @@ class FactoryStatusReplyD2HPacket extends HostBoundPacket {
2238
1857
  percent;
2239
1858
  constructor(data) {
2240
1859
  super(data);
2241
- const dataView = PacketView.fromPacket(this);
2242
- this.status = dataView.nextUint8();
2243
- this.percent = dataView.nextUint8();
1860
+ const view = PacketView.fromPacket(this);
1861
+ this.status = view.nextUint8();
1862
+ this.percent = view.nextUint8();
2244
1863
  }
2245
1864
  }
2246
1865
 
@@ -2251,6 +1870,7 @@ class FactoryEnableReplyD2HPacket extends HostBoundPacket {
2251
1870
 
2252
1871
  // src/VexPacketEncoder.ts
2253
1872
  var textEncoder2 = new TextEncoder;
1873
+ var HEADER_TO_DEVICE = Uint8Array.of(201, 54, 184, 71);
2254
1874
  function encodeFixedText(value, field, maxBytes) {
2255
1875
  const encoded = textEncoder2.encode(value);
2256
1876
  if (encoded.byteLength > maxBytes) {
@@ -2264,92 +1884,96 @@ class PacketEncoder {
2264
1884
  static HEADER_TO_DEVICE = [201, 54, 184, 71];
2265
1885
  static HEADER_TO_HOST = [170, 85];
2266
1886
  static J2000_EPOCH = 946684800;
2267
- vexVersion;
2268
- crcgen;
2269
- allPacketsTable = {};
1887
+ vexVersion = 0;
1888
+ crcgen = new CrcGenerator;
1889
+ allPacketsTable = new Map;
2270
1890
  static getInstance() {
2271
- if (Packet.ENCODER === undefined) {
2272
- Packet.ENCODER = new PacketEncoder;
2273
- }
1891
+ Packet.ENCODER ??= new PacketEncoder;
2274
1892
  return Packet.ENCODER;
2275
1893
  }
2276
1894
  constructor() {
2277
- this.vexVersion = 0;
2278
- this.crcgen = new CrcGenerator;
2279
- Object.values(exports_VexPacketModels).forEach((packet) => {
1895
+ for (const packet of Object.values(exports_VexPacketModels)) {
2280
1896
  if (typeof packet === "function" && packet.prototype instanceof HostBoundPacket) {
2281
- const packetType = packet;
2282
- this.allPacketsTable[packetType.COMMAND_ID + " " + packetType.COMMAND_EXTENDED_ID] = packetType;
1897
+ const type = packet;
1898
+ let byExtendedId = this.allPacketsTable.get(type.COMMAND_ID);
1899
+ if (byExtendedId === undefined) {
1900
+ byExtendedId = new Map;
1901
+ this.allPacketsTable.set(type.COMMAND_ID, byExtendedId);
1902
+ }
1903
+ byExtendedId.set(type.COMMAND_EXTENDED_ID, type);
2283
1904
  }
2284
- });
1905
+ }
1906
+ }
1907
+ getPacketType(commandId, commandExtendedId) {
1908
+ if (commandId === undefined)
1909
+ return;
1910
+ return this.allPacketsTable.get(commandId)?.get(commandExtendedId);
2285
1911
  }
2286
1912
  createHeader(buf) {
2287
1913
  if (buf === undefined || buf.byteLength < PacketEncoder.HEADERS_LENGTH) {
2288
1914
  buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH);
2289
1915
  }
2290
1916
  const h = new Uint8Array(buf);
2291
- h.set(PacketEncoder.HEADER_TO_DEVICE);
1917
+ h.set(HEADER_TO_DEVICE);
2292
1918
  return h;
2293
1919
  }
2294
1920
  cdcCommand(cmd) {
2295
- const buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH + 1);
2296
- const h = this.createHeader(buf);
2297
- h.set([cmd], PacketEncoder.HEADERS_LENGTH);
1921
+ const h = new Uint8Array(5);
1922
+ h.set(HEADER_TO_DEVICE);
1923
+ h[4] = cmd;
2298
1924
  return h;
2299
1925
  }
2300
1926
  cdcCommandWithData(cmd, data) {
2301
- const buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH + 2 + data.length);
2302
- const h = this.createHeader(buf);
2303
- h.set([cmd, data.length], PacketEncoder.HEADERS_LENGTH);
2304
- h.set(data, PacketEncoder.HEADERS_LENGTH + 2);
1927
+ const h = new Uint8Array(6 + data.length);
1928
+ h.set(HEADER_TO_DEVICE);
1929
+ h[4] = cmd;
1930
+ h[5] = data.length;
1931
+ h.set(data, 6);
2305
1932
  return h;
2306
1933
  }
2307
1934
  cdc2Command(cmd, ext) {
2308
- const buf = new ArrayBuffer(PacketEncoder.HEADERS_LENGTH + 5);
2309
- const h = this.createHeader(buf);
2310
- h.set([cmd, ext, 0], PacketEncoder.HEADERS_LENGTH);
2311
- const crc = this.crcgen.crc16(h.subarray(0, buf.byteLength - 2), 0) >>> 0;
2312
- h.set([crc >>> 8, crc & 255], buf.byteLength - 2);
1935
+ const h = new Uint8Array(9);
1936
+ h.set(HEADER_TO_DEVICE);
1937
+ h[4] = cmd;
1938
+ h[5] = ext;
1939
+ h[6] = 0;
1940
+ this.appendCrc16(h);
2313
1941
  return h;
2314
1942
  }
2315
1943
  cdc2CommandBufferLength(data) {
2316
- let length = PacketEncoder.HEADERS_LENGTH + data.length + 3 + 2;
2317
- if (data.length > 127)
2318
- length += 1;
2319
- return length;
1944
+ return PacketEncoder.HEADERS_LENGTH + data.length + 5 + (data.length > 127 ? 1 : 0);
2320
1945
  }
2321
1946
  cdc2CommandWithData(cmd, ext, data) {
2322
- const buf = new ArrayBuffer(this.cdc2CommandBufferLength(data));
2323
- const h = this.createHeader(buf);
1947
+ const h = new Uint8Array(this.cdc2CommandBufferLength(data));
1948
+ h.set(HEADER_TO_DEVICE);
1949
+ h[4] = cmd;
1950
+ h[5] = ext;
2324
1951
  if (data.length < 128) {
2325
- h.set([cmd, ext, data.length], PacketEncoder.HEADERS_LENGTH);
2326
- h.set(data, PacketEncoder.HEADERS_LENGTH + 3);
1952
+ h[6] = data.length;
1953
+ h.set(data, 7);
2327
1954
  } else {
2328
- const lengthMsb = (data.length >>> 8 | 128) >>> 0;
2329
- const lengthLsb = (data.length & 255) >>> 0;
2330
- h.set([cmd, ext, lengthMsb, lengthLsb], PacketEncoder.HEADERS_LENGTH);
2331
- h.set(data, PacketEncoder.HEADERS_LENGTH + 4);
1955
+ h[6] = data.length >>> 8 | 128;
1956
+ h[7] = data.length & 255;
1957
+ h.set(data, 8);
2332
1958
  }
2333
- const crc = this.crcgen.crc16(h.subarray(0, buf.byteLength - 2), 0);
2334
- h.set([crc >>> 8, crc & 255], buf.byteLength - 2);
1959
+ this.appendCrc16(h);
2335
1960
  return h;
2336
1961
  }
1962
+ appendCrc16(h) {
1963
+ const crc = this.crcgen.crc16(h.subarray(0, h.length - 2), 0);
1964
+ h[h.length - 2] = crc >>> 8;
1965
+ h[h.length - 1] = crc & 255;
1966
+ }
2337
1967
  validateHeader(data) {
2338
- return !(data[0] !== PacketEncoder.HEADER_TO_HOST[0] || data[1] !== PacketEncoder.HEADER_TO_HOST[1]);
1968
+ return data[0] === PacketEncoder.HEADER_TO_HOST[0] && data[1] === PacketEncoder.HEADER_TO_HOST[1];
2339
1969
  }
2340
1970
  validateMessageCdc(data) {
2341
- const message = data.subarray(0, data.byteLength - 2);
2342
- const lastTwoBytes = (data[data.byteLength - 2] << 8) + data[data.byteLength - 1];
2343
- return this.crcgen.crc16(message, 0) === lastTwoBytes;
1971
+ const crc = (data[data.byteLength - 2] << 8) + data[data.byteLength - 1];
1972
+ return this.crcgen.crc16(data.subarray(0, data.byteLength - 2), 0) === crc;
2344
1973
  }
2345
1974
  getPayloadSize(data) {
2346
- let t = 0;
2347
- let a = data[3];
2348
- if ((128 & a) !== 0) {
2349
- t = 127 & a;
2350
- a = data[4];
2351
- }
2352
- return (t << 8) + a;
1975
+ const a = data[3];
1976
+ return (a & 128) === 0 ? a : ((a & 127) << 8) + data[4];
2353
1977
  }
2354
1978
  getHostHeaderLength(data) {
2355
1979
  return (data[3] & 128) === 0 ? 4 : 5;
@@ -2386,6 +2010,9 @@ class VexSerialConnection extends VexEventTarget {
2386
2010
  super();
2387
2011
  this.serial = serial;
2388
2012
  }
2013
+ reportWarning(message, details) {
2014
+ this.emit("warning", { message, details });
2015
+ }
2389
2016
  async close() {
2390
2017
  if (this._closePromise)
2391
2018
  return this._closePromise;
@@ -2448,7 +2075,7 @@ class VexSerialConnection extends VexEventTarget {
2448
2075
  try {
2449
2076
  await port.close();
2450
2077
  } catch (e) {
2451
- console.warn("Close port error.", e);
2078
+ this.reportWarning("failed to close the serial port", e);
2452
2079
  }
2453
2080
  }
2454
2081
  if (this._wasConnected) {
@@ -2457,29 +2084,28 @@ class VexSerialConnection extends VexEventTarget {
2457
2084
  }
2458
2085
  }
2459
2086
  open(use = 0, askUser = true) {
2460
- if (this.port !== undefined) {
2461
- return errAsyncVex(new VexIoError("Already connected."));
2462
- }
2463
2087
  return new ResultAsync(this._open(use, askUser));
2464
2088
  }
2465
2089
  async _open(use, askUser) {
2466
- let port;
2467
- if (use !== undefined) {
2468
- const ports = (await this.serial.getPorts()).filter((p) => {
2469
- const info = p.getInfo();
2470
- return this.filters.find((f) => (f.usbVendorId === undefined || f.usbVendorId === info.usbVendorId) && (f.usbProductId === undefined || f.usbProductId === info.usbProductId));
2471
- }).filter((candidate) => candidate.readable === null);
2472
- port = ports[use];
2090
+ if (this._closePromise !== null)
2091
+ await this._closePromise;
2092
+ if (this.port !== undefined) {
2093
+ return err(new VexIoError("Already connected."));
2473
2094
  }
2095
+ const ports = (await this.serial.getPorts()).filter((p) => {
2096
+ const info = p.getInfo();
2097
+ return this.filters.find((f) => (f.usbVendorId === undefined || f.usbVendorId === info.usbVendorId) && (f.usbProductId === undefined || f.usbProductId === info.usbProductId));
2098
+ }).filter((candidate) => candidate.readable === null);
2099
+ let port = ports[use];
2474
2100
  if (port == null && askUser) {
2475
2101
  try {
2476
2102
  port = await this.serial.requestPort({ filters: this.filters });
2477
2103
  } catch {}
2478
2104
  }
2479
2105
  if (port == null)
2480
- return ok(undefined);
2106
+ return ok("no-port");
2481
2107
  if (port.readable != null)
2482
- return ok(false);
2108
+ return ok("busy");
2483
2109
  try {
2484
2110
  this.port = port;
2485
2111
  await port.open({ baudRate: 115200 });
@@ -2492,15 +2118,12 @@ class VexSerialConnection extends VexEventTarget {
2492
2118
  this.startReader();
2493
2119
  this._wasConnected = true;
2494
2120
  this.emit("connected", undefined);
2495
- return ok(true);
2496
- } catch {
2121
+ return ok("opened");
2122
+ } catch (e) {
2497
2123
  await this.close();
2498
- return ok(false);
2124
+ return err(toVexSerialError(e, "io"));
2499
2125
  }
2500
2126
  }
2501
- writeData(rawData, resolve, timeout = 1000) {
2502
- this.writeDataAsync(rawData, timeout).then(resolve);
2503
- }
2504
2127
  async writeDataAsync(rawData, timeout = 1000) {
2505
2128
  return new Promise((resolve) => {
2506
2129
  if (this.writer === undefined) {
@@ -2531,6 +2154,14 @@ class VexSerialConnection extends VexEventTarget {
2531
2154
  });
2532
2155
  });
2533
2156
  }
2157
+ request(packet, ReplyType, timeout = 1000) {
2158
+ return new ResultAsync((async () => {
2159
+ const result = await this.writeDataAsync(packet, timeout);
2160
+ if (result instanceof ReplyType)
2161
+ return ok(result);
2162
+ return err(new VexProtocolError(expectedReplyMessage(packet, ReplyType, result), typeof result === "number" ? result : undefined));
2163
+ })());
2164
+ }
2534
2165
  async readData(cache, expectedSize) {
2535
2166
  if (this.reader == null)
2536
2167
  throw new Error("No reader");
@@ -2571,39 +2202,56 @@ class VexSerialConnection extends VexEventTarget {
2571
2202
  if (!thePacketEncoder.validateMessageCdc(cache))
2572
2203
  throw new Error("Invalid message CDC");
2573
2204
  }
2574
- let callbackInfo;
2575
- let wantedCmdId;
2576
- let wantedCmdExId;
2577
- let tryIdx = 0;
2578
- while ((callbackInfo = this.callbacksQueue[tryIdx++]) !== undefined) {
2579
- wantedCmdId = callbackInfo?.wantedCommandId;
2580
- wantedCmdExId = callbackInfo?.wantedCommandExId;
2581
- if (wantedCmdId !== undefined && wantedCmdId !== cmdId || wantedCmdExId !== undefined && wantedCmdExId !== cmdExId) {
2205
+ let matchIdx = -1;
2206
+ let untypedIdx = -1;
2207
+ for (let i = 0;i < this.callbacksQueue.length; i++) {
2208
+ const candidate = this.callbacksQueue[i];
2209
+ if (candidate.wantedCommandId === undefined && candidate.wantedCommandExId === undefined) {
2210
+ if (untypedIdx === -1)
2211
+ untypedIdx = i;
2582
2212
  continue;
2583
2213
  }
2584
- break;
2214
+ if ((candidate.wantedCommandId === undefined || candidate.wantedCommandId === cmdId) && (candidate.wantedCommandExId === undefined || candidate.wantedCommandExId === cmdExId)) {
2215
+ matchIdx = i;
2216
+ break;
2217
+ }
2585
2218
  }
2586
- if (callbackInfo === undefined) {
2587
- console.warn("Unexpected command", cmdId, cmdExId, ack);
2219
+ if (matchIdx === -1)
2220
+ matchIdx = untypedIdx;
2221
+ if (matchIdx === -1) {
2222
+ this.reportWarning("received a reply with no matching request", {
2223
+ commandId: cmdId,
2224
+ commandExtendedId: cmdExId,
2225
+ ack
2226
+ });
2588
2227
  continue;
2589
2228
  }
2229
+ const callbackInfo = this.callbacksQueue[matchIdx];
2230
+ const wantedCmdId = callbackInfo.wantedCommandId;
2231
+ const wantedCmdExId = callbackInfo.wantedCommandExId;
2590
2232
  const data = cache.slice(0, sliceIdx);
2591
- const PackageType = thePacketEncoder.allPacketsTable[wantedCmdId + " " + wantedCmdExId];
2592
- if (wantedCmdId === undefined && wantedCmdExId === undefined || PackageType === undefined) {
2233
+ const PackageType = thePacketEncoder.getPacketType(wantedCmdId, wantedCmdExId);
2234
+ if (wantedCmdId === undefined || PackageType === undefined) {
2235
+ if (wantedCmdId !== undefined) {
2236
+ this.reportWarning("no packet class is registered for the wanted command", { commandId: wantedCmdId, commandExtendedId: wantedCmdExId });
2237
+ }
2593
2238
  callbackInfo.callback(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));
2594
2239
  } else {
2595
2240
  if (!hasExtId || PackageType.isValidPacket(data, n)) {
2596
2241
  callbackInfo.callback(new PackageType(data));
2597
2242
  } else {
2598
- console.warn("ack", ack);
2243
+ this.reportWarning("reply failed packet validation; delivering its ack instead", { commandId: cmdId, commandExtendedId: cmdExId, ack });
2599
2244
  callbackInfo.callback(ack);
2600
2245
  }
2601
2246
  }
2602
2247
  clearTimeout(callbackInfo.timeout);
2603
- this.callbacksQueue.splice(tryIdx - 1, 1);
2248
+ this.callbacksQueue.splice(matchIdx, 1);
2604
2249
  } catch (e) {
2605
2250
  if (!(e instanceof Error && e.message === "No data")) {
2606
- console.warn("Read error.", e, cache);
2251
+ this.reportWarning("reader loop stopped by a read error", {
2252
+ error: e,
2253
+ pendingBytes: cache
2254
+ });
2607
2255
  }
2608
2256
  await this.close();
2609
2257
  break;
@@ -2612,19 +2260,10 @@ class VexSerialConnection extends VexEventTarget {
2612
2260
  }
2613
2261
  }
2614
2262
  query1() {
2615
- return new ResultAsync((async () => {
2616
- const result = await this.writeDataAsync(new Query1H2DPacket, 100);
2617
- return result instanceof Query1ReplyD2HPacket ? ok(result) : err(new VexProtocolError("query1 was not acknowledged"));
2618
- })());
2263
+ return this.request(new Query1H2DPacket, Query1ReplyD2HPacket, 100);
2619
2264
  }
2620
2265
  getSystemVersion() {
2621
- return new ResultAsync((async () => {
2622
- const result = await this.writeDataAsync(new SystemVersionH2DPacket);
2623
- if (result instanceof SystemVersionReplyD2HPacket) {
2624
- return ok(result.version);
2625
- }
2626
- return err(new VexProtocolError("system version was not acknowledged"));
2627
- })());
2266
+ return this.request(new SystemVersionH2DPacket, SystemVersionReplyD2HPacket).map((result) => result.version);
2628
2267
  }
2629
2268
  }
2630
2269
 
@@ -2651,34 +2290,19 @@ class V5SerialConnection extends VexSerialConnection {
2651
2290
  }
2652
2291
  }
2653
2292
  getDeviceStatus() {
2654
- return new ResultAsync((async () => {
2655
- const result = await this.writeDataAsync(new GetDeviceStatusH2DPacket);
2656
- return result instanceof GetDeviceStatusReplyD2HPacket ? ok(result) : err(new VexProtocolError("device status was not acknowledged"));
2657
- })());
2293
+ return this.request(new GetDeviceStatusH2DPacket, GetDeviceStatusReplyD2HPacket);
2658
2294
  }
2659
2295
  getRadioStatus() {
2660
- return new ResultAsync((async () => {
2661
- const result = await this.writeDataAsync(new GetRadioStatusH2DPacket);
2662
- return result instanceof GetRadioStatusReplyD2HPacket ? ok(result) : err(new VexProtocolError("radio status was not acknowledged"));
2663
- })());
2296
+ return this.request(new GetRadioStatusH2DPacket, GetRadioStatusReplyD2HPacket);
2664
2297
  }
2665
2298
  getSystemFlags() {
2666
- return new ResultAsync((async () => {
2667
- const result = await this.writeDataAsync(new GetSystemFlagsH2DPacket);
2668
- return result instanceof GetSystemFlagsReplyD2HPacket ? ok(result) : err(new VexProtocolError("system flags were not acknowledged"));
2669
- })());
2299
+ return this.request(new GetSystemFlagsH2DPacket, GetSystemFlagsReplyD2HPacket);
2670
2300
  }
2671
2301
  getSystemStatus(timeout = 1000) {
2672
- return new ResultAsync((async () => {
2673
- const result = await this.writeDataAsync(new GetSystemStatusH2DPacket, timeout);
2674
- return result instanceof GetSystemStatusReplyD2HPacket ? ok(result) : err(new VexProtocolError("system status was not acknowledged"));
2675
- })());
2302
+ return this.request(new GetSystemStatusH2DPacket, GetSystemStatusReplyD2HPacket, timeout);
2676
2303
  }
2677
2304
  getMatchStatus() {
2678
- return new ResultAsync((async () => {
2679
- const result = await this.writeDataAsync(new GetMatchStatusH2DPacket);
2680
- return result instanceof MatchStatusReplyD2HPacket ? ok(result) : err(new VexProtocolError("match status was not acknowledged"));
2681
- })());
2305
+ return this.request(new GetMatchStatusH2DPacket, MatchStatusReplyD2HPacket);
2682
2306
  }
2683
2307
  uploadProgramToDevice(iniConfig, binFileBuf, coldFileBuf, progressCallback) {
2684
2308
  return wrapTransfer(this, () => this._uploadProgramToDevice(iniConfig, binFileBuf, coldFileBuf, progressCallback));
@@ -2739,23 +2363,23 @@ class V5SerialConnection extends VexSerialConnection {
2739
2363
  async _downloadFileToHostUnlocked(request, downloadTarget, progressCallback) {
2740
2364
  const { filename, vendor, loadAddress, size } = request;
2741
2365
  let nextAddress = loadAddress ?? USER_FLASH_USR_CODE_START;
2742
- const p1 = await this.writeDataAsync(new InitFileTransferH2DPacket(2 /* READ */, downloadTarget, vendor, 0 /* NONE */, new Uint8Array, nextAddress, filename, ""));
2743
- if (!(p1 instanceof InitFileTransferReplyD2HPacket)) {
2744
- return err(new VexTransferError("InitFileTransferH2DPacket failed"));
2745
- }
2366
+ const p1Result = await this.request(new InitFileTransferH2DPacket(2 /* READ */, downloadTarget, vendor, 0 /* NONE */, new Uint8Array, nextAddress, filename, ""), InitFileTransferReplyD2HPacket);
2367
+ if (p1Result.isErr())
2368
+ return err(p1Result.error);
2746
2369
  let transferFailed = true;
2747
2370
  let result = ok(new Uint8Array);
2748
2371
  try {
2372
+ const p1 = p1Result.value;
2749
2373
  const fileSize = size ?? p1.fileSize;
2750
2374
  const bufferChunkSize = getTransferChunkSize(p1.windowSize);
2751
2375
  let bufferOffset = 0;
2752
2376
  const fileBuf = new Uint8Array(fileSize);
2753
2377
  while (bufferOffset < fileSize) {
2754
2378
  const requestedSize = Math.min(bufferChunkSize, fileSize - bufferOffset);
2755
- const p2 = await this.writeDataAsync(new ReadFileH2DPacket(nextAddress, requestedSize), 3000);
2756
- if (!(p2 instanceof ReadFileReplyD2HPacket)) {
2757
- throw new VexTransferError("ReadFileReplyD2HPacket failed");
2758
- }
2379
+ const p2Result = await this.request(new ReadFileH2DPacket(nextAddress, requestedSize), ReadFileReplyD2HPacket, 3000);
2380
+ if (p2Result.isErr())
2381
+ throw p2Result.error;
2382
+ const p2 = p2Result.value;
2759
2383
  if (p2.addr !== nextAddress) {
2760
2384
  throw new VexTransferError(`ReadFileReplyD2HPacket returned address ${p2.addr}, expected ${nextAddress}`);
2761
2385
  }
@@ -2773,11 +2397,12 @@ class V5SerialConnection extends VexSerialConnection {
2773
2397
  result = err(e instanceof VexSerialError ? e : toVexSerialError(e, "transfer"));
2774
2398
  } finally {
2775
2399
  try {
2776
- await this.writeDataAsync(new ExitFileTransferH2DPacket(3 /* EXIT_HALT */), 30000);
2777
- } catch (cleanupError) {
2778
- if (!transferFailed) {
2779
- result = err(toVexSerialError(cleanupError, "io"));
2780
- }
2400
+ const exitResult = await this.request(new ExitFileTransferH2DPacket(3 /* EXIT_HALT */), ExitFileTransferReplyD2HPacket, 30000);
2401
+ if (!transferFailed && exitResult.isErr())
2402
+ result = err(exitResult.error);
2403
+ } catch (e) {
2404
+ if (!transferFailed)
2405
+ result = err(toVexSerialError(e, "io"));
2781
2406
  }
2782
2407
  }
2783
2408
  return result;
@@ -2802,22 +2427,20 @@ class V5SerialConnection extends VexSerialConnection {
2802
2427
  downloadTarget = downloadTarget ?? 1 /* FILE_TARGET_QSPI */;
2803
2428
  vendor = vendor ?? 1 /* USER */;
2804
2429
  let nextAddress = loadAddress ?? USER_FLASH_USR_CODE_START;
2805
- const p1 = await this.writeDataAsync(new InitFileTransferH2DPacket(1 /* WRITE */, downloadTarget, vendor, 1 /* OVERWRITE */, buf, nextAddress, filename, exttype));
2806
- if (!(p1 instanceof InitFileTransferReplyD2HPacket)) {
2807
- return err(new VexTransferError("InitFileTransferH2DPacket failed"));
2808
- }
2430
+ const p1Result = await this.request(new InitFileTransferH2DPacket(1 /* WRITE */, downloadTarget, vendor, 1 /* OVERWRITE */, buf, nextAddress, filename, exttype), InitFileTransferReplyD2HPacket);
2431
+ if (p1Result.isErr())
2432
+ return err(p1Result.error);
2433
+ const p1 = p1Result.value;
2809
2434
  const bufferChunkSize = getTransferChunkSize(p1.windowSize);
2810
2435
  let bufferOffset = 0;
2811
2436
  let lastBlock = false;
2812
2437
  let transferFailed = true;
2813
- let exitReply;
2814
2438
  let result = ok(false);
2815
2439
  try {
2816
2440
  if (linkedFile !== undefined) {
2817
- const p3 = await this.writeDataAsync(new LinkFileH2DPacket(linkedFile.vendor ?? 1 /* USER */, linkedFile.filename, 0), 1e4);
2818
- if (!(p3 instanceof LinkFileReplyD2HPacket)) {
2819
- throw new VexTransferError("LinkFileH2DPacket failed");
2820
- }
2441
+ const p3Result = await this.request(new LinkFileH2DPacket(linkedFile.vendor ?? 1 /* USER */, linkedFile.filename, 0), LinkFileReplyD2HPacket, 1e4);
2442
+ if (p3Result.isErr())
2443
+ throw p3Result.error;
2821
2444
  }
2822
2445
  while (!lastBlock) {
2823
2446
  let tmpbuf;
@@ -2829,23 +2452,21 @@ class V5SerialConnection extends VexSerialConnection {
2829
2452
  tmpbuf.set(buf.subarray(bufferOffset, buf.byteLength));
2830
2453
  lastBlock = true;
2831
2454
  }
2832
- const p2 = await this.writeDataAsync(new WriteFileH2DPacket(nextAddress, tmpbuf), 3000);
2833
- if (!(p2 instanceof WriteFileReplyD2HPacket))
2834
- throw new VexTransferError("WriteFileReplyD2DPacket failed");
2835
- if (progressCallback != null)
2836
- progressCallback(bufferOffset, buf.byteLength);
2455
+ const p2Result = await this.request(new WriteFileH2DPacket(nextAddress, tmpbuf), WriteFileReplyD2HPacket, 3000);
2456
+ if (p2Result.isErr())
2457
+ throw p2Result.error;
2837
2458
  bufferOffset += bufferChunkSize;
2838
2459
  nextAddress += bufferChunkSize;
2460
+ progressCallback?.(Math.min(bufferOffset, buf.byteLength), buf.byteLength);
2839
2461
  }
2840
- progressCallback?.(buf.byteLength, buf.byteLength);
2841
2462
  transferFailed = false;
2842
2463
  } catch (e) {
2843
2464
  result = err(e instanceof VexSerialError ? e : toVexSerialError(e, "transfer"));
2844
2465
  } finally {
2845
2466
  try {
2846
- exitReply = await this.writeDataAsync(new ExitFileTransferH2DPacket(transferFailed ? 3 /* EXIT_HALT */ : autoRun ? 1 /* EXIT_RUN */ : 3 /* EXIT_HALT */), 30000);
2467
+ const exitResult = await this.request(new ExitFileTransferH2DPacket(transferFailed ? 3 /* EXIT_HALT */ : autoRun ? 1 /* EXIT_RUN */ : 3 /* EXIT_HALT */), ExitFileTransferReplyD2HPacket, 30000);
2847
2468
  if (!transferFailed) {
2848
- result = ok(exitReply !== undefined && exitReply instanceof ExitFileTransferReplyD2HPacket);
2469
+ result = exitResult.map(() => true);
2849
2470
  }
2850
2471
  } catch (cleanupError) {
2851
2472
  if (!transferFailed) {
@@ -2867,14 +2488,20 @@ class V5SerialConnection extends VexSerialConnection {
2867
2488
  }
2868
2489
  let result;
2869
2490
  try {
2870
- const ack = await this.writeDataAsync(new EraseFileH2DPacket(vendor, filename));
2871
- result = ack instanceof EraseFileReplyD2HPacket ? ok(undefined) : err(new VexProtocolError("removeFile was not acknowledged"));
2491
+ const eraseResult = await this.request(new EraseFileH2DPacket(vendor, filename), EraseFileReplyD2HPacket);
2492
+ result = eraseResult.map(() => {
2493
+ return;
2494
+ });
2872
2495
  } catch (e) {
2873
2496
  result = err(toVexSerialError(e, "io"));
2874
- } finally {
2875
- try {
2876
- await this.writeDataAsync(new ExitFileTransferH2DPacket(3 /* EXIT_HALT */));
2877
- } catch {}
2497
+ }
2498
+ try {
2499
+ const exitResult = await this.request(new ExitFileTransferH2DPacket(3 /* EXIT_HALT */), ExitFileTransferReplyD2HPacket, 30000);
2500
+ if (result.isOk() && exitResult.isErr())
2501
+ result = err(exitResult.error);
2502
+ } catch (e) {
2503
+ if (result.isOk())
2504
+ result = err(toVexSerialError(e, "io"));
2878
2505
  }
2879
2506
  return result;
2880
2507
  }));
@@ -2883,23 +2510,26 @@ class V5SerialConnection extends VexSerialConnection {
2883
2510
  return new ResultAsync(this.withFileTransfer(async () => {
2884
2511
  let result;
2885
2512
  try {
2886
- const ack = await this.writeDataAsync(new FileClearUpH2DPacket(1 /* USER */), 30000);
2887
- result = ack instanceof FileClearUpReplyD2HPacket ? ok(undefined) : err(new VexProtocolError("removeAllFiles was not acknowledged"));
2513
+ const clearResult = await this.request(new FileClearUpH2DPacket(1 /* USER */), FileClearUpReplyD2HPacket, 30000);
2514
+ result = clearResult.map(() => {
2515
+ return;
2516
+ });
2888
2517
  } catch (e) {
2889
2518
  result = err(toVexSerialError(e, "io"));
2890
- } finally {
2891
- try {
2892
- await this.writeDataAsync(new ExitFileTransferH2DPacket(3 /* EXIT_HALT */));
2893
- } catch {}
2519
+ }
2520
+ try {
2521
+ const exitResult = await this.request(new ExitFileTransferH2DPacket(3 /* EXIT_HALT */), ExitFileTransferReplyD2HPacket, 30000);
2522
+ if (result.isOk() && exitResult.isErr())
2523
+ result = err(exitResult.error);
2524
+ } catch (e) {
2525
+ if (result.isOk())
2526
+ result = err(toVexSerialError(e, "io"));
2894
2527
  }
2895
2528
  return result;
2896
2529
  }));
2897
2530
  }
2898
2531
  captureScreenSetup() {
2899
- return new ResultAsync((async () => {
2900
- const result = await this.writeDataAsync(new ScreenCaptureH2DPacket(0));
2901
- return result instanceof ScreenCaptureReplyD2HPacket ? ok(result) : err(new VexProtocolError("screen capture was rejected"));
2902
- })());
2532
+ return this.request(new ScreenCaptureH2DPacket(0), ScreenCaptureReplyD2HPacket);
2903
2533
  }
2904
2534
  captureScreen(progressCallback) {
2905
2535
  return wrapTransfer(this, () => this._captureScreen(progressCallback));
@@ -2920,37 +2550,22 @@ class V5SerialConnection extends VexSerialConnection {
2920
2550
  return ok(convertScreenCapture(framebuffer.value));
2921
2551
  }
2922
2552
  setMatchMode(mode) {
2923
- return new ResultAsync((async () => {
2924
- const result = await this.writeDataAsync(new UpdateMatchModeH2DPacket(mode, 0));
2925
- return result instanceof MatchModeReplyD2HPacket ? ok(result) : err(new VexProtocolError("setMatchMode was not acknowledged"));
2926
- })());
2553
+ return this.request(new UpdateMatchModeH2DPacket(mode, 0), MatchModeReplyD2HPacket);
2927
2554
  }
2928
2555
  runProgram(value) {
2929
2556
  return this.loadProgram(value);
2930
2557
  }
2931
2558
  loadProgram(value) {
2932
- return new ResultAsync((async () => {
2933
- const result = await this.writeDataAsync(new LoadFileActionH2DPacket(1 /* USER */, 0 /* RUN */, value));
2934
- return result instanceof LoadFileActionReplyD2HPacket ? ok(result) : err(new VexProtocolError("loadProgram was not acknowledged"));
2935
- })());
2559
+ return this.request(new LoadFileActionH2DPacket(1 /* USER */, 0 /* RUN */, value), LoadFileActionReplyD2HPacket);
2936
2560
  }
2937
2561
  stopProgram() {
2938
- return new ResultAsync((async () => {
2939
- const result = await this.writeDataAsync(new LoadFileActionH2DPacket(1 /* USER */, 128 /* STOP */, ""));
2940
- return result instanceof LoadFileActionReplyD2HPacket ? ok(result) : err(new VexProtocolError("stopProgram was not acknowledged"));
2941
- })());
2562
+ return this.request(new LoadFileActionH2DPacket(1 /* USER */, 128 /* STOP */, ""), LoadFileActionReplyD2HPacket);
2942
2563
  }
2943
2564
  mockTouch(x, y, press) {
2944
- return new ResultAsync((async () => {
2945
- const result = await this.writeDataAsync(new SendDashTouchH2DPacket(x, y, press));
2946
- return result instanceof SendDashTouchReplyD2HPacket ? ok(result) : err(new VexProtocolError("mockTouch was not acknowledged"));
2947
- })());
2565
+ return this.request(new SendDashTouchH2DPacket(x, y, press), SendDashTouchReplyD2HPacket);
2948
2566
  }
2949
2567
  openScreen(screen, port) {
2950
- return new ResultAsync((async () => {
2951
- const result = await this.writeDataAsync(new SelectDashH2DPacket(screen, port));
2952
- return result instanceof SelectDashReplyD2HPacket ? ok(result) : err(new VexProtocolError("openScreen was not acknowledged"));
2953
- })());
2568
+ return this.request(new SelectDashH2DPacket(screen, port), SelectDashReplyD2HPacket);
2954
2569
  }
2955
2570
  }
2956
2571
  function binaryArrayJoin(left, right) {
@@ -2992,17 +2607,22 @@ function wrapTransfer(conn, operation) {
2992
2607
  }
2993
2608
  }));
2994
2609
  }
2995
- function errAsyncVex(error) {
2996
- return new ResultAsync(Promise.resolve(err(error)));
2610
+ function expectedReplyMessage(packet, ReplyType, reply) {
2611
+ const expected = `expected ${ReplyType.name} for ${packet.constructor.name}`;
2612
+ if (typeof reply === "number")
2613
+ return `${expected}; received ${ackTypeName(reply)}`;
2614
+ if (reply instanceof ArrayBuffer)
2615
+ return `${expected}; received raw ArrayBuffer`;
2616
+ return `${expected}; received ${reply.constructor.name}`;
2617
+ }
2618
+ function ackTypeName(ackType) {
2619
+ return `AckType.${AckType[ackType] ?? "UNKNOWN"} (${ackType})`;
2997
2620
  }
2998
2621
  // src/VexFirmware.ts
2999
2622
  var MAX_CATALOG_BYTES = 4 * 1024;
3000
2623
  var MAX_VEXOS_BYTES = 64 * 1024 * 1024;
3001
2624
  var MAX_FIRMWARE_IMAGE_BYTES = 32 * 1024 * 1024;
3002
2625
  var MAX_AGGREGATE_IMAGE_BYTES = 48 * 1024 * 1024;
3003
- function fromAsyncFn(fn) {
3004
- return new ResultAsync(fn());
3005
- }
3006
2626
  function downloadFileFromInternet(link, options = {}) {
3007
2627
  const { maxBytes = Number.POSITIVE_INFINITY, timeout = 30000 } = options;
3008
2628
  if (maxBytes <= 0) {
@@ -3011,7 +2631,7 @@ function downloadFileFromInternet(link, options = {}) {
3011
2631
  if (timeout < 0) {
3012
2632
  return errAsync(new VexInvalidArgumentError("timeout must be non-negative"));
3013
2633
  }
3014
- return fromAsyncFn(() => runDownload(link, maxBytes, timeout));
2634
+ return new ResultAsync(runDownload(link, maxBytes, timeout));
3015
2635
  }
3016
2636
  async function runDownload(link, maxBytes, timeout) {
3017
2637
  const controller = new AbortController;
@@ -3078,7 +2698,7 @@ function sleepUntilAsync(f, timeout, interval = 20) {
3078
2698
  if (interval <= 0) {
3079
2699
  return errAsync(new VexInvalidArgumentError("interval must be positive"));
3080
2700
  }
3081
- return fromAsyncFn(() => runSleepUntilAsync(f, timeout, interval));
2701
+ return new ResultAsync(runSleepUntilAsync(f, timeout, interval));
3082
2702
  }
3083
2703
  async function runSleepUntilAsync(f, timeout, interval) {
3084
2704
  const deadline = Date.now() + timeout;
@@ -3103,7 +2723,7 @@ function sleepUntil(f, timeout, interval = 20) {
3103
2723
  if (interval <= 0) {
3104
2724
  return errAsync(new VexInvalidArgumentError("interval must be positive"));
3105
2725
  }
3106
- return fromAsyncFn(() => runSleepUntil(f, timeout, interval));
2726
+ return new ResultAsync(runSleepUntil(f, timeout, interval));
3107
2727
  }
3108
2728
  async function runSleepUntil(f, timeout, interval) {
3109
2729
  const deadline = Date.now() + timeout;
@@ -3130,6 +2750,59 @@ function sleep(ms) {
3130
2750
  async function sleepInner(ms) {
3131
2751
  return new Promise((resolve) => setTimeout(resolve, ms));
3132
2752
  }
2753
+ async function flashFactoryImage(conn, options, pcb) {
2754
+ const { image, label, downloadTarget } = options;
2755
+ pcb(`FACTORY ENB ${label}`, 0, 0);
2756
+ const enableReply = await conn.request(new FactoryEnableH2DPacket, FactoryEnableReplyD2HPacket);
2757
+ if (enableReply.isErr())
2758
+ return err(enableReply.error);
2759
+ const writeRequest = {
2760
+ filename: "null.bin",
2761
+ vendor: 1 /* USER */,
2762
+ loadAddress: USER_FLASH_USR_CODE_START,
2763
+ buf: image.buf,
2764
+ downloadTarget,
2765
+ exttype: "bin",
2766
+ autoRun: true,
2767
+ linkedFile: undefined
2768
+ };
2769
+ const upload = await conn.uploadFileToDevice(writeRequest, (c, t) => {
2770
+ pcb(`UPLOAD ${label}`, c, t);
2771
+ });
2772
+ if (upload.isErr())
2773
+ return err(upload.error);
2774
+ if (!upload.value) {
2775
+ return err(new VexFirmwareError(`${label} upload was rejected by device`));
2776
+ }
2777
+ const deadline = Date.now() + 120000;
2778
+ while (Date.now() < deadline) {
2779
+ const statusReply = await conn.request(new FactoryStatusH2DPacket, FactoryStatusReplyD2HPacket, 1e4);
2780
+ if (statusReply.isErr())
2781
+ return err(statusReply.error);
2782
+ reportFactoryStatus(label, statusReply.value, pcb);
2783
+ if (statusReply.value.status === 0 && statusReply.value.percent === 100) {
2784
+ return ok(undefined);
2785
+ }
2786
+ await sleepInner(500);
2787
+ }
2788
+ return err(new VexFirmwareError(`${label} factory status timed out`));
2789
+ }
2790
+ function reportFactoryStatus(label, reply, pcb) {
2791
+ switch (reply.status) {
2792
+ case 2:
2793
+ pcb(`ERASE ${label}`, reply.percent, 100);
2794
+ break;
2795
+ case 3:
2796
+ pcb(`WRITE ${label}`, reply.percent, 100);
2797
+ break;
2798
+ case 4:
2799
+ pcb(`VERIFY ${label}`, reply.percent, 100);
2800
+ break;
2801
+ case 8:
2802
+ pcb(`FINISHING ${label}`, reply.percent, 100);
2803
+ break;
2804
+ }
2805
+ }
3133
2806
  async function extractFirmwareImages(usingVersion, vexos) {
3134
2807
  const { unzip } = await import("unzipit");
3135
2808
  const { entries } = await unzip(vexos);
@@ -3177,7 +2850,7 @@ async function extractFirmwareImages(usingVersion, vexos) {
3177
2850
  return ordered;
3178
2851
  }
3179
2852
  function uploadFirmware(state, publicUrl = "https://content.vexrobotics.com/vexos/public/V5/", usingVersion, progressCallback) {
3180
- return fromAsyncFn(() => runUploadFirmware(state, publicUrl, usingVersion, progressCallback));
2853
+ return new ResultAsync(runUploadFirmware(state, publicUrl, usingVersion, progressCallback));
3181
2854
  }
3182
2855
  async function runUploadFirmware(state, publicUrl, usingVersion, progressCallback) {
3183
2856
  const device = state._instance;
@@ -3219,12 +2892,7 @@ async function runUploadFirmware(state, publicUrl, usingVersion, progressCallbac
3219
2892
  return err(toVexSerialError(e, "firmware"));
3220
2893
  }
3221
2894
  pcb("UNZIP VEXOS", 1, 1);
3222
- return state.withFileTransfer(async () => {
3223
- pcb("FACTORY ENB BOOT", 0, 0);
3224
- const result = await conn.writeDataAsync(new FactoryEnableH2DPacket);
3225
- if (!(result instanceof FactoryEnableReplyD2HPacket)) {
3226
- return err(new VexProtocolError("FactoryEnableH2DPacket failed"));
3227
- }
2895
+ return state.withRefreshPaused(async () => {
3228
2896
  const boot = images.find((image) => image.name.endsWith("BOOT.bin"));
3229
2897
  if (boot === undefined) {
3230
2898
  return err(new VexFirmwareError("VEXos archive is missing BOOT.bin"));
@@ -3233,105 +2901,20 @@ async function runUploadFirmware(state, publicUrl, usingVersion, progressCallbac
3233
2901
  if (assertImage === undefined) {
3234
2902
  return err(new VexFirmwareError("VEXos archive is missing assets.bin"));
3235
2903
  }
3236
- const bootWriteRequest = {
3237
- filename: "null.bin",
3238
- vendor: 1 /* USER */,
3239
- loadAddress: USER_FLASH_USR_CODE_START,
3240
- buf: boot.buf,
3241
- downloadTarget: 14 /* FILE_TARGET_B1 */,
3242
- exttype: "bin",
3243
- autoRun: true,
3244
- linkedFile: undefined
3245
- };
3246
- const bootUpload = await conn.uploadFileToDevice(bootWriteRequest, (c, t) => {
3247
- pcb("UPLOAD BOOT", c, t);
3248
- });
3249
- if (bootUpload.isErr())
3250
- return err(bootUpload.error);
3251
- if (!bootUpload.value)
3252
- return ok(false);
3253
- const bootDeadline = Date.now() + 120000;
3254
- let bootComplete = false;
3255
- while (Date.now() < bootDeadline) {
3256
- const result3 = await conn.writeDataAsync(new FactoryStatusH2DPacket, 1e4);
3257
- if (result3 instanceof FactoryStatusReplyD2HPacket) {
3258
- switch (result3.status) {
3259
- case 2:
3260
- pcb("ERASE BOOT", result3.percent, 100);
3261
- break;
3262
- case 3:
3263
- pcb("WRITE BOOT", result3.percent, 100);
3264
- break;
3265
- case 4:
3266
- pcb("VERIFY BOOT", result3.percent, 100);
3267
- break;
3268
- case 8:
3269
- pcb("FINISHING BOOT", result3.percent, 100);
3270
- break;
3271
- }
3272
- if (result3.status === 0 && result3.percent === 100) {
3273
- bootComplete = true;
3274
- break;
3275
- }
3276
- } else {
3277
- return ok(false);
3278
- }
3279
- await sleepInner(500);
3280
- }
3281
- if (!bootComplete)
3282
- return ok(false);
3283
- pcb("FACTORY ENB ASSERT", 0, 0);
3284
- const result5 = await conn.writeDataAsync(new FactoryEnableH2DPacket);
3285
- if (!(result5 instanceof FactoryEnableReplyD2HPacket)) {
3286
- return err(new VexProtocolError("FactoryEnableH2DPacket failed"));
3287
- }
3288
- const assertWriteRequest = {
3289
- filename: "null.bin",
3290
- vendor: 1 /* USER */,
3291
- loadAddress: USER_FLASH_USR_CODE_START,
3292
- buf: assertImage.buf,
3293
- downloadTarget: 13 /* FILE_TARGET_A1 */,
3294
- exttype: "bin",
3295
- autoRun: true,
3296
- linkedFile: undefined
3297
- };
3298
- const assertUpload = await conn.uploadFileToDevice(assertWriteRequest, (c, t) => {
3299
- pcb("UPLOAD ASSERT", c, t);
3300
- });
3301
- if (assertUpload.isErr())
3302
- return err(assertUpload.error);
3303
- if (!assertUpload.value)
3304
- return ok(false);
3305
- const assertDeadline = Date.now() + 120000;
3306
- let assertComplete = false;
3307
- while (Date.now() < assertDeadline) {
3308
- const result7 = await conn.writeDataAsync(new FactoryStatusH2DPacket, 1e4);
3309
- if (result7 instanceof FactoryStatusReplyD2HPacket) {
3310
- switch (result7.status) {
3311
- case 2:
3312
- pcb("ERASE ASSERT", result7.percent, 100);
3313
- break;
3314
- case 3:
3315
- pcb("WRITE ASSERT", result7.percent, 100);
3316
- break;
3317
- case 4:
3318
- pcb("VERIFY ASSERT", result7.percent, 100);
3319
- break;
3320
- case 8:
3321
- pcb("FINISHING ASSERT", result7.percent, 100);
3322
- break;
3323
- }
3324
- if (result7.status === 0 && result7.percent === 100) {
3325
- assertComplete = true;
3326
- break;
3327
- }
3328
- } else {
3329
- return ok(false);
3330
- }
3331
- await sleepInner(500);
3332
- }
3333
- if (!assertComplete)
3334
- return ok(false);
2904
+ const bootFlash = await flashFactoryImage(conn, {
2905
+ image: boot,
2906
+ label: "BOOT",
2907
+ downloadTarget: 14 /* FILE_TARGET_B1 */
2908
+ }, pcb);
2909
+ if (bootFlash.isErr())
2910
+ return err(bootFlash.error);
2911
+ const assetsFlash = await flashFactoryImage(conn, {
2912
+ image: assertImage,
2913
+ label: "ASSETS",
2914
+ downloadTarget: 13 /* FILE_TARGET_A1 */
2915
+ }, pcb);
2916
+ if (assetsFlash.isErr())
2917
+ return err(assetsFlash.error);
3335
2918
  return ok(true);
3336
2919
  });
3337
2920
  }
@@ -3343,8 +2926,7 @@ function getValue(state, key) {
3343
2926
  if (conn == null || !conn.isConnected) {
3344
2927
  return err(new VexNotConnectedError);
3345
2928
  }
3346
- const result = await conn.writeDataAsync(new ReadKeyValueH2DPacket(key));
3347
- return result instanceof ReadKeyValueReplyD2HPacket ? ok(result.value) : err(new VexProtocolError("getValue was not acknowledged"));
2929
+ return conn.request(new ReadKeyValueH2DPacket(key), ReadKeyValueReplyD2HPacket).map((result) => result.value);
3348
2930
  })());
3349
2931
  }
3350
2932
  function setValue(state, key, value) {
@@ -3353,8 +2935,9 @@ function setValue(state, key, value) {
3353
2935
  if (conn == null || !conn.isConnected) {
3354
2936
  return err(new VexNotConnectedError);
3355
2937
  }
3356
- const result = await conn.writeDataAsync(new WriteKeyValueH2DPacket(key, value));
3357
- return result instanceof WriteKeyValueReplyD2HPacket ? ok(undefined) : err(new VexProtocolError("setValue was not acknowledged"));
2938
+ return conn.request(new WriteKeyValueH2DPacket(key, value), WriteKeyValueReplyD2HPacket).map(() => {
2939
+ return;
2940
+ });
3358
2941
  })());
3359
2942
  }
3360
2943
  function listFiles(state, vendor = 1 /* USER */) {
@@ -3363,26 +2946,24 @@ function listFiles(state, vendor = 1 /* USER */) {
3363
2946
  if (conn == null || !conn.isConnected) {
3364
2947
  return err(new VexNotConnectedError);
3365
2948
  }
3366
- const result = await conn.writeDataAsync(new GetDirectoryFileCountH2DPacket(vendor));
3367
- if (!(result instanceof GetDirectoryFileCountReplyD2HPacket)) {
3368
- return err(new VexProtocolError("directory file count was not acknowledged"));
3369
- }
2949
+ const countResult = await conn.request(new GetDirectoryFileCountH2DPacket(vendor), GetDirectoryFileCountReplyD2HPacket);
2950
+ if (countResult.isErr())
2951
+ return err(countResult.error);
3370
2952
  const files = [];
3371
- for (let i = 0;i < result.count; i++) {
3372
- const result2 = await conn.writeDataAsync(new GetDirectoryEntryH2DPacket(i));
3373
- if (!(result2 instanceof GetDirectoryEntryReplyD2HPacket)) {
3374
- return err(new VexProtocolError("directory entry was not acknowledged"));
3375
- }
3376
- if (result2.file != null) {
2953
+ for (let i = 0;i < countResult.value.count; i++) {
2954
+ const entryResult = await conn.request(new GetDirectoryEntryH2DPacket(i), GetDirectoryEntryReplyD2HPacket);
2955
+ if (entryResult.isErr())
2956
+ return err(entryResult.error);
2957
+ if (entryResult.value.file != null) {
3377
2958
  files.push({
3378
- filename: result2.file.filename,
2959
+ filename: entryResult.value.file.filename,
3379
2960
  vendor,
3380
- loadAddress: result2.file.loadAddress,
3381
- size: result2.file.size,
3382
- crc32: result2.file.crc32,
3383
- type: result2.file.type,
3384
- timestamp: result2.file.timestamp,
3385
- version: result2.file.version
2961
+ loadAddress: entryResult.value.file.loadAddress,
2962
+ size: entryResult.value.file.size,
2963
+ crc32: entryResult.value.file.crc32,
2964
+ type: entryResult.value.file.type,
2965
+ timestamp: entryResult.value.file.timestamp,
2966
+ version: entryResult.value.file.version
3386
2967
  });
3387
2968
  }
3388
2969
  }
@@ -3418,10 +2999,10 @@ function listProgram(state) {
3418
2999
  time: n,
3419
3000
  requestedSlot: -1
3420
3001
  };
3421
- const result2 = await conn.writeDataAsync(new GetProgramSlotInfoH2DPacket(1 /* USER */, program.binfile));
3422
- if (result2 instanceof GetProgramSlotInfoReplyD2HPacket) {
3423
- program.slot = result2.slot;
3424
- program.requestedSlot = result2.requestedSlot;
3002
+ const slotInfo = await conn.request(new GetProgramSlotInfoH2DPacket(1 /* USER */, program.binfile), GetProgramSlotInfoReplyD2HPacket);
3003
+ if (slotInfo.isOk()) {
3004
+ program.slot = slotInfo.value.slot;
3005
+ program.requestedSlot = slotInfo.value.requestedSlot;
3425
3006
  }
3426
3007
  programList.push(program);
3427
3008
  }
@@ -3440,7 +3021,7 @@ function readFile(state, request, downloadTarget = 1 /* FILE_TARGET_QSPI */, pro
3440
3021
  } else {
3441
3022
  handle = request;
3442
3023
  }
3443
- return state.withFileTransfer(() => conn.downloadFileToHost(handle, downloadTarget, progressCallback));
3024
+ return state.withRefreshPaused(() => conn.downloadFileToHost(handle, downloadTarget, progressCallback));
3444
3025
  })());
3445
3026
  }
3446
3027
  function removeFile(state, request) {
@@ -3449,7 +3030,7 @@ function removeFile(state, request) {
3449
3030
  if (conn == null || !conn.isConnected) {
3450
3031
  return err(new VexNotConnectedError);
3451
3032
  }
3452
- return state.withFileTransfer(() => conn.removeFile(request));
3033
+ return state.withRefreshPaused(() => conn.removeFile(request));
3453
3034
  })());
3454
3035
  }
3455
3036
  function removeAllFiles(state) {
@@ -3458,7 +3039,7 @@ function removeAllFiles(state) {
3458
3039
  if (conn == null || !conn.isConnected) {
3459
3040
  return err(new VexNotConnectedError);
3460
3041
  }
3461
- return state.withFileTransfer(() => conn.removeAllFiles());
3042
+ return state.withRefreshPaused(() => conn.removeAllFiles());
3462
3043
  })());
3463
3044
  }
3464
3045
  function uploadProgram(state, iniConfig, binFileBuf, coldFileBuf, progressCallback) {
@@ -3471,7 +3052,7 @@ async function runUploadProgram(state, iniConfig, binFileBuf, coldFileBuf, progr
3471
3052
  return err(new VexNotConnectedError);
3472
3053
  }
3473
3054
  let switchedToDownload = false;
3474
- return state.withFileTransfer(async () => {
3055
+ return state.withRefreshPaused(async () => {
3475
3056
  try {
3476
3057
  if (device.isV5Controller) {
3477
3058
  await sleep(250);
@@ -3530,7 +3111,7 @@ function writeFile(state, request, progressCallback) {
3530
3111
  if (conn == null || !conn.isConnected) {
3531
3112
  return err(new VexNotConnectedError);
3532
3113
  }
3533
- return state.withFileTransfer(() => conn.uploadFileToDevice(request, progressCallback));
3114
+ return state.withRefreshPaused(() => conn.uploadFileToDevice(request, progressCallback));
3534
3115
  })());
3535
3116
  }
3536
3117
  function captureScreen(state, progressCallback) {
@@ -3539,7 +3120,7 @@ function captureScreen(state, progressCallback) {
3539
3120
  if (conn == null || !conn.isConnected) {
3540
3121
  return err(new VexNotConnectedError);
3541
3122
  }
3542
- return state.withFileTransfer(() => conn.captureScreen(progressCallback));
3123
+ return state.withRefreshPaused(() => conn.captureScreen(progressCallback));
3543
3124
  })());
3544
3125
  }
3545
3126
 
@@ -3562,10 +3143,13 @@ class VexSerialDevice extends VexEventTarget {
3562
3143
  class V5SerialDeviceState {
3563
3144
  _instance;
3564
3145
  refreshPauseDepth = 0;
3565
- get isFileTransferring() {
3146
+ get isRefreshPaused() {
3566
3147
  return this.refreshPauseDepth > 0;
3567
3148
  }
3568
- async withFileTransfer(operation) {
3149
+ get isFileTransferring() {
3150
+ return this.isRefreshPaused;
3151
+ }
3152
+ async withRefreshPaused(operation) {
3569
3153
  this.refreshPauseDepth++;
3570
3154
  try {
3571
3155
  return await operation();
@@ -3573,6 +3157,9 @@ class V5SerialDeviceState {
3573
3157
  this.refreshPauseDepth--;
3574
3158
  }
3575
3159
  }
3160
+ async withFileTransfer(operation) {
3161
+ return this.withRefreshPaused(operation);
3162
+ }
3576
3163
  brain = {
3577
3164
  activeProgram: 0,
3578
3165
  battery: {
@@ -3602,7 +3189,8 @@ class V5SerialDeviceState {
3602
3189
  },
3603
3190
  {
3604
3191
  battery: 0,
3605
- isAvailable: false
3192
+ isAvailable: false,
3193
+ isCharging: false
3606
3194
  }
3607
3195
  ];
3608
3196
  devices = [];
@@ -3625,8 +3213,14 @@ class V5SerialDeviceState {
3625
3213
 
3626
3214
  class V5Brain {
3627
3215
  state;
3216
+ batteryFacade;
3217
+ buttonFacade;
3218
+ settingsFacade;
3628
3219
  constructor(state) {
3629
3220
  this.state = state;
3221
+ this.batteryFacade = new V5Battery(state);
3222
+ this.buttonFacade = new V5BrainButton(state);
3223
+ this.settingsFacade = new V5BrainSettings(state);
3630
3224
  }
3631
3225
  get isRunningProgram() {
3632
3226
  return this.activeProgram !== 0;
@@ -3659,9 +3253,8 @@ class V5Brain {
3659
3253
  const reply = await conn.runProgram(slot);
3660
3254
  if (reply.isErr())
3661
3255
  return err(reply.error);
3662
- const slotNumber = typeof slot === "string" ? Number.parseInt(slot, 10) : slot;
3663
- if (Number.isFinite(slotNumber))
3664
- this.state.brain.activeProgram = slotNumber;
3256
+ if (typeof slot === "number")
3257
+ this.state.brain.activeProgram = slot;
3665
3258
  return ok(undefined);
3666
3259
  })());
3667
3260
  }
@@ -3678,10 +3271,10 @@ class V5Brain {
3678
3271
  })());
3679
3272
  }
3680
3273
  get battery() {
3681
- return new V5Battery(this.state);
3274
+ return this.batteryFacade;
3682
3275
  }
3683
3276
  get button() {
3684
- return new V5BrainButton(this.state);
3277
+ return this.buttonFacade;
3685
3278
  }
3686
3279
  get cpu0Version() {
3687
3280
  return this.state.brain.cpu0Version;
@@ -3693,7 +3286,7 @@ class V5Brain {
3693
3286
  return this.state.brain.isAvailable;
3694
3287
  }
3695
3288
  get settings() {
3696
- return new V5BrainSettings(this.state);
3289
+ return this.settingsFacade;
3697
3290
  }
3698
3291
  get systemVersion() {
3699
3292
  return this.state.brain.systemVersion;
@@ -3848,16 +3441,28 @@ class V5Radio {
3848
3441
  }
3849
3442
  changeChannel(channel) {
3850
3443
  return new ResultAsync((async () => {
3851
- const result = await this.state._instance.connection?.writeDataAsync(new FileControlH2DPacket(1, channel));
3852
- return result instanceof FileControlReplyD2HPacket ? ok(undefined) : err(new VexProtocolError("changeChannel was not acknowledged"));
3444
+ const conn = this.state._instance.connection;
3445
+ if (conn == null || !conn.isConnected) {
3446
+ return err(new VexNotConnectedError);
3447
+ }
3448
+ return conn.request(new FileControlH2DPacket(1, channel), FileControlReplyD2HPacket).map(() => {
3449
+ return;
3450
+ });
3853
3451
  })());
3854
3452
  }
3855
3453
  }
3856
3454
 
3857
3455
  // src/VexDevice.ts
3456
+ function unrefTimerIfPossible(timer) {
3457
+ if (typeof timer !== "object" || timer === null || !("unref" in timer))
3458
+ return;
3459
+ const unref = timer.unref;
3460
+ if (typeof unref === "function")
3461
+ unref.call(timer);
3462
+ }
3463
+
3858
3464
  class V5SerialDevice extends VexSerialDevice {
3859
3465
  autoReconnect = true;
3860
- autoRefresh = true;
3861
3466
  pauseRefreshOnFileTransfer = true;
3862
3467
  _isReconnecting = false;
3863
3468
  _isDisconnecting = false;
@@ -3865,19 +3470,45 @@ class V5SerialDevice extends VexSerialDevice {
3865
3470
  state = new V5SerialDeviceState(this);
3866
3471
  _disposed = false;
3867
3472
  _refreshGeneration = 0;
3868
- constructor(defaultSerial) {
3473
+ _autoRefresh = false;
3474
+ _isLastRefreshComplete = true;
3475
+ _brain = new V5Brain(this.state);
3476
+ _controllers = [
3477
+ new V5Controller(this.state, 0),
3478
+ new V5Controller(this.state, 1)
3479
+ ];
3480
+ _radio = new V5Radio(this.state);
3481
+ _deviceFacades = [];
3482
+ constructor(defaultSerial, autoRefresh = false) {
3869
3483
  super(defaultSerial);
3870
- let isLastRefreshComplete = true;
3484
+ this.autoRefresh = autoRefresh;
3485
+ }
3486
+ get autoRefresh() {
3487
+ return this._autoRefresh;
3488
+ }
3489
+ set autoRefresh(value) {
3490
+ if (this._autoRefresh === value)
3491
+ return;
3492
+ this._autoRefresh = value;
3493
+ if (value) {
3494
+ this._startRefreshInterval();
3495
+ } else {
3496
+ this._stopRefreshInterval();
3497
+ }
3498
+ }
3499
+ _startRefreshInterval() {
3500
+ if (this._refreshInterval !== undefined || this._disposed)
3501
+ return;
3871
3502
  this._refreshInterval = setInterval(() => {
3872
3503
  if (this._disposed)
3873
3504
  return;
3874
- if (this.autoRefresh && isLastRefreshComplete) {
3505
+ if (this._autoRefresh && this._isLastRefreshComplete) {
3875
3506
  if (!this.isConnected) {
3876
3507
  this.state.brain.isAvailable = false;
3877
3508
  return;
3878
3509
  }
3879
- if (!this.pauseRefreshOnFileTransfer || !this.state.isFileTransferring) {
3880
- isLastRefreshComplete = false;
3510
+ if (!this.pauseRefreshOnFileTransfer || !this.state.isRefreshPaused) {
3511
+ this._isLastRefreshComplete = false;
3881
3512
  (async () => {
3882
3513
  try {
3883
3514
  const r = await this.refresh();
@@ -3886,27 +3517,37 @@ class V5SerialDevice extends VexSerialDevice {
3886
3517
  } catch (error) {
3887
3518
  this.emit("error", error);
3888
3519
  } finally {
3889
- isLastRefreshComplete = true;
3520
+ this._isLastRefreshComplete = true;
3890
3521
  }
3891
3522
  })();
3892
3523
  }
3893
3524
  }
3894
3525
  }, 200);
3526
+ unrefTimerIfPossible(this._refreshInterval);
3527
+ }
3528
+ _stopRefreshInterval() {
3529
+ if (this._refreshInterval === undefined)
3530
+ return;
3531
+ clearInterval(this._refreshInterval);
3532
+ this._refreshInterval = undefined;
3895
3533
  }
3896
3534
  get isV5Controller() {
3897
3535
  return this.deviceType === 1283 /* V5_CONTROLLER */;
3898
3536
  }
3899
3537
  get brain() {
3900
- return new V5Brain(this.state);
3538
+ return this._brain;
3901
3539
  }
3902
3540
  get controllers() {
3903
- return [new V5Controller(this.state, 0), new V5Controller(this.state, 1)];
3541
+ return this._controllers;
3904
3542
  }
3905
3543
  get devices() {
3906
3544
  const rtn = [];
3907
- for (let i = 1;i <= this.state.devices.length; i++) {
3908
- if (this.state.devices[i] != null)
3909
- rtn.push(new V5SmartDevice(this.state, i));
3545
+ for (let i = 1;i < this.state.devices.length; i++) {
3546
+ if (this.state.devices[i] != null) {
3547
+ const facade = this._deviceFacades[i] ?? new V5SmartDevice(this.state, i);
3548
+ this._deviceFacades[i] = facade;
3549
+ rtn.push(facade);
3550
+ }
3910
3551
  }
3911
3552
  return rtn;
3912
3553
  }
@@ -3931,7 +3572,7 @@ class V5SerialDevice extends VexSerialDevice {
3931
3572
  })());
3932
3573
  }
3933
3574
  get radio() {
3934
- return new V5Radio(this.state);
3575
+ return this._radio;
3935
3576
  }
3936
3577
  mockTouch(x, y, press) {
3937
3578
  return new ResultAsync((async () => {
@@ -3952,7 +3593,7 @@ class V5SerialDevice extends VexSerialDevice {
3952
3593
  if (conn != null) {
3953
3594
  if (!conn.isConnected) {
3954
3595
  const opened = await conn.open();
3955
- if (opened.isErr() || opened.value !== true) {
3596
+ if (opened.isErr() || opened.value !== "opened") {
3956
3597
  return err(new VexIoError("failed to open the supplied connection"));
3957
3598
  }
3958
3599
  }
@@ -3971,10 +3612,10 @@ class V5SerialDevice extends VexSerialDevice {
3971
3612
  await c.close();
3972
3613
  return err(result.error);
3973
3614
  }
3974
- if (result.value === undefined) {
3615
+ if (result.value === "no-port") {
3975
3616
  return err(new VexNotConnectedError("no V5 device was found"));
3976
3617
  }
3977
- if (!result.value) {
3618
+ if (result.value === "busy") {
3978
3619
  await c.close();
3979
3620
  continue;
3980
3621
  }
@@ -4006,10 +3647,6 @@ class V5SerialDevice extends VexSerialDevice {
4006
3647
  this.autoReconnect = false;
4007
3648
  this.autoRefresh = false;
4008
3649
  this._disposed = true;
4009
- if (this._refreshInterval !== undefined) {
4010
- clearInterval(this._refreshInterval);
4011
- this._refreshInterval = undefined;
4012
- }
4013
3650
  await this.disconnect();
4014
3651
  }
4015
3652
  reconnect(timeout = 0) {
@@ -4045,9 +3682,9 @@ class V5SerialDevice extends VexSerialDevice {
4045
3682
  await c.close();
4046
3683
  return err(result.error);
4047
3684
  }
4048
- if (result.value === undefined)
3685
+ if (result.value === "no-port")
4049
3686
  break;
4050
- if (!result.value) {
3687
+ if (result.value === "busy") {
4051
3688
  await c.close();
4052
3689
  continue;
4053
3690
  }
@@ -4090,7 +3727,10 @@ class V5SerialDevice extends VexSerialDevice {
4090
3727
  if (this.connection == null)
4091
3728
  return;
4092
3729
  this.connection.on("disconnected", (_data) => {
4093
- if (this.autoReconnect && !this._isDisconnecting) {
3730
+ if (this._isDisconnecting)
3731
+ return;
3732
+ this.emit("disconnected", undefined);
3733
+ if (this.autoReconnect) {
4094
3734
  this.reconnect().mapErr((e) => this.emit("error", e));
4095
3735
  }
4096
3736
  });
@@ -4188,7 +3828,8 @@ class V5SerialDevice extends VexSerialDevice {
4188
3828
  },
4189
3829
  {
4190
3830
  battery: controller1Battery,
4191
- isAvailable: controller1Available
3831
+ isAvailable: controller1Available,
3832
+ isCharging: (flags2 & 128) !== 0
4192
3833
  }
4193
3834
  ],
4194
3835
  radio: {
@@ -4255,23 +3896,22 @@ class IniSectionBuilder extends BaseIniBuilder {
4255
3896
  this.keyTransform = keyTransform;
4256
3897
  }
4257
3898
  addSingleObjProperty(key, maxValueLength) {
4258
- if (this.object[key] == null || this.object[key].toString().length === 0)
3899
+ const value = this.object[key];
3900
+ if (value == null || value.toString().length === 0)
4259
3901
  return;
4260
3902
  const formattedKey = this.keyTransform(key).padEnd(12).slice(0, 12);
4261
- const trimmedVal = this.object[key].toString().slice(0, maxValueLength);
3903
+ const trimmedVal = value.toString().slice(0, maxValueLength);
4262
3904
  const escapedVal = trimmedVal.replace(/["\\\u0000-\u001f\u007f]/g, (character) => `\\x${character.charCodeAt(0).toString(16).padStart(2, "0")}`);
4263
3905
  this.addLine(`${formattedKey} = "${escapedVal}"`);
4264
3906
  }
4265
3907
  addObjProperty(key, maxValueLength) {
4266
- const keys = Array.isArray(key) ? key : [key];
4267
- for (const k of keys) {
3908
+ for (const k of Array.isArray(key) ? key : [key]) {
4268
3909
  this.addSingleObjProperty(k, maxValueLength);
4269
3910
  }
4270
3911
  return this;
4271
3912
  }
4272
3913
  addAllObjProps(maxValueLength) {
4273
- const keys = Object.keys(this.object);
4274
- for (const k of keys) {
3914
+ for (const k of Object.keys(this.object)) {
4275
3915
  this.addSingleObjProperty(k, maxValueLength);
4276
3916
  }
4277
3917
  return this;
@@ -4300,21 +3940,15 @@ class ProgramIniConfig {
4300
3940
  date: "",
4301
3941
  timezone: "0"
4302
3942
  };
4303
- config = {};
3943
+ config = { 22: "adi" };
4304
3944
  controller1 = {};
4305
3945
  controller2 = {};
4306
- constructor() {
4307
- this.config = {
4308
- 22: "adi"
4309
- };
4310
- }
4311
3946
  setProgramDate(date) {
4312
- const d = date;
4313
- this.program.date = d.toISOString();
4314
- const tzo = Math.abs(d.getTimezoneOffset());
4315
- const tzh = tzo / 60 >>> 0;
4316
- const tzm = tzo - tzh * 60;
4317
- this.program.timezone = (d.getTimezoneOffset() > 0 ? "-" : "+") + this.dec2(tzh) + ":" + this.dec2(tzm);
3947
+ this.program.date = date.toISOString();
3948
+ const offset = Math.abs(date.getTimezoneOffset());
3949
+ const hours = offset / 60 >>> 0;
3950
+ const minutes = offset - hours * 60;
3951
+ this.program.timezone = (date.getTimezoneOffset() > 0 ? "-" : "+") + this.dec2(hours) + ":" + this.dec2(minutes);
4318
3952
  }
4319
3953
  createIni() {
4320
3954
  if (this.program.date.length === 0) {
@@ -4323,8 +3957,7 @@ class ProgramIniConfig {
4323
3957
  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();
4324
3958
  }
4325
3959
  dec2(value) {
4326
- const str = ("00" + value.toString(10)).substr(-2, 2);
4327
- return str.toUpperCase();
3960
+ return (value % 100).toString(10).padStart(2, "0").toUpperCase();
4328
3961
  }
4329
3962
  }
4330
3963
  export {
@@ -4456,5 +4089,5 @@ export {
4456
4089
  AckType
4457
4090
  };
4458
4091
 
4459
- //# debugId=AEA86FF140C3172464756E2164756E21
4092
+ //# debugId=658BAE3B57868EE064756E2164756E21
4460
4093
  //# sourceMappingURL=index.js.map