@v5x/serial 0.5.4 → 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.
Files changed (56) hide show
  1. package/README.md +73 -9
  2. package/dist/Vex.d.ts +4 -4
  3. package/dist/VexCRC.d.ts +0 -12
  4. package/dist/VexConnection.d.ts +106 -26
  5. package/dist/VexDevice.d.ts +52 -157
  6. package/{dts/VexDevice.d.ts → dist/VexDeviceState.d.ts} +79 -62
  7. package/dist/VexError.d.ts +50 -0
  8. package/dist/VexEvent.d.ts +15 -10
  9. package/dist/VexFirmware.d.ts +47 -0
  10. package/dist/VexFirmwareVersion.d.ts +4 -43
  11. package/dist/VexIniConfig.d.ts +1 -2
  12. package/dist/VexPacket.d.ts +3 -512
  13. package/dist/VexPacketBase.d.ts +24 -0
  14. package/dist/VexPacketEncoder.d.ts +36 -0
  15. package/{dts/VexPacket.d.ts → dist/VexPacketModels.d.ts} +3 -118
  16. package/dist/VexPacketView.d.ts +5 -3
  17. package/dist/VexTransfers.d.ts +20 -0
  18. package/dist/index.cjs +4175 -0
  19. package/dist/index.cjs.map +25 -0
  20. package/dist/index.d.ts +9 -9
  21. package/dist/index.js +4093 -0
  22. package/dist/index.js.map +25 -0
  23. package/package.json +39 -71
  24. package/dist/v5-serial-protocol.cjs.js +0 -4516
  25. package/dist/v5-serial-protocol.cjs.js.map +0 -1
  26. package/dist/v5-serial-protocol.es.js +0 -4401
  27. package/dist/v5-serial-protocol.es.js.map +0 -1
  28. package/dts/Vex.d.ts +0 -235
  29. package/dts/Vex.js +0 -189
  30. package/dts/Vex.js.map +0 -1
  31. package/dts/VexCRC.d.ts +0 -19
  32. package/dts/VexCRC.js +0 -89
  33. package/dts/VexCRC.js.map +0 -1
  34. package/dts/VexConnection.d.ts +0 -45
  35. package/dts/VexConnection.js +0 -500
  36. package/dts/VexConnection.js.map +0 -1
  37. package/dts/VexDevice.js +0 -944
  38. package/dts/VexDevice.js.map +0 -1
  39. package/dts/VexEvent.d.ts +0 -16
  40. package/dts/VexEvent.js +0 -47
  41. package/dts/VexEvent.js.map +0 -1
  42. package/dts/VexFirmwareVersion.d.ts +0 -55
  43. package/dts/VexFirmwareVersion.js +0 -104
  44. package/dts/VexFirmwareVersion.js.map +0 -1
  45. package/dts/VexIniConfig.d.ts +0 -27
  46. package/dts/VexIniConfig.js +0 -122
  47. package/dts/VexIniConfig.js.map +0 -1
  48. package/dts/VexPacket.js +0 -1036
  49. package/dts/VexPacket.js.map +0 -1
  50. package/dts/VexPacketView.d.ts +0 -18
  51. package/dts/VexPacketView.js +0 -84
  52. package/dts/VexPacketView.js.map +0 -1
  53. package/dts/index.d.ts +0 -9
  54. package/dts/index.js +0 -10
  55. package/dts/index.js.map +0 -1
  56. package/index.d.ts +0 -1098
package/README.md CHANGED
@@ -2,9 +2,10 @@
2
2
 
3
3
  TypeScript implementation of the VEX V5 serial protocol.
4
4
 
5
- This package provides helpers for connecting to V5 devices over the Web Serial
6
- API, reading device state, transferring files, and working with protocol
7
- packets.
5
+ See the [serial library documentation](https://docs.v5x.dev/serial/overview) for browser setup, guides, and high-level API reference.
6
+
7
+ It covers connecting to V5 devices over the Web Serial API, reading device
8
+ state, transferring files, and working with protocol packets.
8
9
 
9
10
  ## Install
10
11
 
@@ -14,16 +15,27 @@ bun add @v5x/serial
14
15
 
15
16
  ## Usage
16
17
 
18
+ Every public async API returns a `neverthrow` `ResultAsync` whose error channel
19
+ is a `VexSerialError`. Inspect the result with `.isOk()` / `.isErr()` or
20
+ `.match()` instead of using `try`/`catch`:
21
+
17
22
  ```ts
18
23
  import { V5SerialConnection } from "@v5x/serial";
19
24
 
20
25
  const connection = new V5SerialConnection(navigator.serial);
21
26
 
22
- const connected = await connection.open();
27
+ const opened = await connection.open();
28
+ if (opened.isErr()) {
29
+ console.error(opened.error); // VexSerialError with a stable .kind
30
+ return;
31
+ }
32
+ // opened.value: true | false | undefined (opened / busy / no port selected)
23
33
 
24
- if (connected) {
25
- const status = await connection.getSystemStatus();
26
- console.log(status);
34
+ const status = await connection.getSystemStatus();
35
+ if (status.isOk()) {
36
+ console.log(status.value);
37
+ } else {
38
+ console.error(status.error.kind, status.error.message);
27
39
  }
28
40
  ```
29
41
 
@@ -31,20 +43,72 @@ Web Serial is browser-only and requires a secure context, such as HTTPS or
31
43
  `localhost`. The user must grant access to a serial device before the connection
32
44
  can open.
33
45
 
46
+ The package ships ESM, CommonJS, and TypeScript declarations. Packet and version
47
+ utilities work in Bun or Node.js, but direct browser device connections require
48
+ the Web Serial API. The `@v5x/cli` package is separate and currently supports
49
+ Linux and macOS. Windows requires a different CLI serial backend.
50
+
34
51
  ## Common Exports
35
52
 
36
53
  - `V5SerialConnection` for opening and managing a serial connection.
37
54
  - `V5SerialDevice` for higher-level device operations.
55
+ - `VexSerialError` and its subclasses (`VexNotConnectedError`,
56
+ `VexProtocolError`, `VexTransferError`, `VexDownloadError`,
57
+ `VexFirmwareError`, `VexIoError`, `VexInvalidArgumentError`) for typed failure
58
+ handling. Each carries a stable `kind` discriminator.
38
59
  - `PacketEncoder`, `DeviceBoundPacket`, and `HostBoundPacket` for low-level
39
60
  protocol work.
40
61
  - `ProgramIniConfig` for creating VEX program metadata.
41
62
  - Protocol enums and types from `Vex.ts`.
42
63
 
64
+ ## Result-returning async APIs
65
+
66
+ All public async methods return `ResultAsync<T, VexSerialError>`, so failures
67
+ are explicit in the type system rather than thrown. State-changing operations
68
+ are awaitable and report errors through the result channel:
69
+
70
+ ```ts
71
+ const r = await device.setMatchMode("disabled");
72
+ if (r.isErr()) console.error(r.error);
73
+
74
+ await device.brain.setActiveProgram(1).mapErr((e) => console.error(e));
75
+ await device.brain.setActiveProgram(0);
76
+ ```
77
+
78
+ The former `device.matchMode = value` and
79
+ `device.brain.activeProgram = value` setters were fire-and-forget and have been
80
+ removed. Migrate to the corresponding `setMatchMode()` / `setActiveProgram()`
81
+ methods and handle the returned `Result`.
82
+
83
+ Legacy methods that resolved to `false`, `null`, or `undefined` on failure now
84
+ return a typed `Err` instead, preserving the prior success value semantics on
85
+ the `Ok` channel (e.g. `open()` still resolves to `Ok(true | false |
86
+ undefined)`).
87
+
88
+ ## Transfers and timeouts
89
+
90
+ Bulk uploads and downloads on one `V5SerialConnection` are queued and run one at
91
+ a time. Await each high-level transfer; do not interleave manual low-level file
92
+ packets. A `V5SerialDevice` pauses its background refresh while a high-level
93
+ transfer is active by default.
94
+
95
+ Protocol requests default to a 1,000 ms response timeout. Individual transfer
96
+ phases use longer timeouts where erase, write, or exit operations need them.
97
+ `reconnect(0)` waits indefinitely, while a positive reconnect timeout is a total
98
+ deadline in milliseconds. A timeout or NACK surfaces as a `VexProtocolError`
99
+ (or a related `VexSerialError` subclass) through the `Result` error channel; it
100
+ does not cancel work already running on the device.
101
+
102
+ User QSPI files are limited to `USER_FLASH_MAX_FILE_SIZE` (2 MiB). Firmware
103
+ updates download an archive containing non-empty `BOOT.bin` and `assets.bin`
104
+ images whose sizes must match the archive metadata. Firmware writes can render a
105
+ device unusable if power or communication is interrupted; keep them out of
106
+ normal application flows and validate the target VEXos version first.
107
+
43
108
  ## Build
44
109
 
45
110
  ```sh
46
111
  bun run build
47
112
  ```
48
113
 
49
- The build emits JavaScript bundles to `dist/` and TypeScript declarations to
50
- `dts/` and `index.d.ts`.
114
+ The build emits JavaScript bundles and TypeScript declarations under `dist/`.
package/dist/Vex.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { type VexFirmwareVersion } from "./VexFirmwareVersion";
2
- import { type HostBoundPacket } from "./VexPacket";
1
+ import { type VexFirmwareVersion } from "./VexFirmwareVersion.js";
2
+ import { type HostBoundPacket } from "./VexPacket.js";
3
3
  export declare const USER_PROG_CHUNK_SIZE = 4096;
4
4
  export declare const USER_FLASH_START = 50331648;
5
5
  export declare const USER_FLASH_SYS_CODE_START = 54525952;
@@ -86,8 +86,8 @@ export declare enum FileDownloadTarget {
86
86
  FILE_TARGET_VBUF = 3,
87
87
  FILE_TARGET_DDRC = 4,
88
88
  FILE_TARGET_DDRE = 5,
89
- FILE_TARGET_FLASH = 6,
90
- FILE_TARGET_RADIO = 7,
89
+ FILE_TARGET_FLASH = 6,// for IQ2
90
+ FILE_TARGET_RADIO = 7,// for IQ2
91
91
  FILE_TARGET_A1 = 13,
92
92
  FILE_TARGET_B1 = 14,
93
93
  FILE_TARGET_B2 = 15
package/dist/VexCRC.d.ts CHANGED
@@ -1,19 +1,7 @@
1
1
  export declare class CrcGenerator {
2
- crc16Table: Uint32Array;
3
2
  crc32Table: Uint32Array;
4
3
  static POLYNOMIAL_CRC32: number;
5
4
  static POLYNOMIAL_CRC16: number;
6
- constructor();
7
- /**
8
- * Calculate CRC16 for buffer
9
- */
10
5
  crc16(buf: Uint8Array, initValue: number): number;
11
- /**
12
- * Generate CRC32 reverse table
13
- */
14
- crc32GenTable(): void;
15
- /**
16
- * Calculate CRC32 for buffer
17
- */
18
6
  crc32(buf: Uint8Array, initValue: number): number;
19
7
  }
@@ -1,45 +1,125 @@
1
- /// <reference types="dom-serial" />
2
- import { AckType, FileDownloadTarget, type IFileBasicInfo, type IFileWriteRequest, type IPacketCallback, type MatchMode, type SlotNumber, type SelectDashScreen } from "./Vex";
3
- import { VexEventTarget } from "./VexEvent";
4
- import { type ProgramIniConfig } from "./VexIniConfig";
5
- import { MatchStatusReplyD2HPacket, DeviceBoundPacket, MatchModeReplyD2HPacket, GetSystemStatusReplyD2HPacket, type HostBoundPacket, Query1ReplyD2HPacket, LoadFileActionReplyD2HPacket, GetSystemFlagsReplyD2HPacket, GetRadioStatusReplyD2HPacket, GetDeviceStatusReplyD2HPacket, SendDashTouchReplyD2HPacket, type SelectDashReplyD2HPacket } from "./VexPacket";
6
- import { type VexFirmwareVersion } from "./VexFirmwareVersion";
1
+ import { AckType, FileDownloadTarget, type IFileBasicInfo, type IFileWriteRequest, type IPacketCallback, type MatchMode, type SlotNumber, type SelectDashScreen } from "./Vex.js";
2
+ import { VexSerialError } from "./VexError.js";
3
+ import { VexEventTarget } from "./VexEvent.js";
4
+ import { type ProgramIniConfig } from "./VexIniConfig.js";
5
+ import { Result, ResultAsync } from "neverthrow";
6
+ import { MatchStatusReplyD2HPacket, DeviceBoundPacket, MatchModeReplyD2HPacket, GetSystemStatusReplyD2HPacket, type HostBoundPacket, Query1ReplyD2HPacket, LoadFileActionReplyD2HPacket, GetSystemFlagsReplyD2HPacket, GetRadioStatusReplyD2HPacket, GetDeviceStatusReplyD2HPacket, SendDashTouchReplyD2HPacket, SelectDashReplyD2HPacket, ScreenCaptureReplyD2HPacket } from "./VexPacket.js";
7
+ import { type VexFirmwareVersion } from "./VexFirmwareVersion.js";
8
+ type HostBoundPacketType<T extends HostBoundPacket> = {
9
+ new (data: ArrayBuffer | Uint8Array): T;
10
+ name: string;
11
+ };
12
+ /** Outcome of {@link VexSerialConnection.open}. */
13
+ export type OpenResult = "opened" | "busy" | "no-port";
14
+ /**
15
+ * Payload of the `warning` event: a non-fatal condition the library
16
+ * recovered from, surfaced so embedders can log or ignore it.
17
+ */
18
+ export interface ConnectionWarning {
19
+ message: string;
20
+ details?: unknown;
21
+ }
22
+ export interface VexSerialConnectionEvents {
23
+ connected: undefined;
24
+ disconnected: undefined;
25
+ warning: ConnectionWarning;
26
+ }
7
27
  /**
8
28
  * A connection to a V5 device.
9
- * Emit events: connected, disconnected
29
+ * Emit events: connected, disconnected, warning
10
30
  */
11
- export declare class VexSerialConnection extends VexEventTarget {
31
+ export declare class VexSerialConnection extends VexEventTarget<VexSerialConnectionEvents> {
12
32
  filters: SerialPortFilter[];
13
33
  writer: WritableStreamDefaultWriter<unknown> | undefined;
14
34
  reader: ReadableStreamDefaultReader<unknown> | undefined;
15
35
  port: SerialPort | undefined;
16
36
  serial: Serial;
17
37
  callbacksQueue: IPacketCallback[];
38
+ private _onPortDisconnect;
39
+ private _closePromise;
40
+ private _wasConnected;
41
+ protected fileTransferTail: Promise<unknown>;
42
+ protected fileTransferDepth: number;
18
43
  get isConnected(): boolean;
44
+ get isFileTransferring(): boolean;
19
45
  constructor(serial: Serial);
46
+ protected reportWarning(message: string, details?: unknown): void;
20
47
  close(): Promise<void>;
21
- open(use?: number | undefined, askUser?: boolean): Promise<boolean | undefined>;
22
- writeData(rawData: DeviceBoundPacket | Uint8Array, resolve: (data: HostBoundPacket | ArrayBuffer | AckType) => void, timeout?: number): void;
48
+ private _hasOpenResources;
49
+ private _doClose;
50
+ /**
51
+ * Open a port. Resolves `"opened"` when a connection is established,
52
+ * `"busy"` when the matching port is already held elsewhere, and
53
+ * `"no-port"` when no matching port was selected. The result is `Err`
54
+ * when a connection is already open (programmer error) or when the
55
+ * port fails to open (permissions, dead device, ...).
56
+ */
57
+ open(use?: number, askUser?: boolean): ResultAsync<OpenResult, VexSerialError>;
58
+ private _open;
23
59
  writeDataAsync(rawData: DeviceBoundPacket | Uint8Array, timeout?: number): Promise<HostBoundPacket | ArrayBuffer | AckType>;
60
+ request<T extends HostBoundPacket>(packet: DeviceBoundPacket, ReplyType: HostBoundPacketType<T>, timeout?: number): ResultAsync<T, VexSerialError>;
24
61
  protected readData(cache: Uint8Array, expectedSize: number): Promise<Uint8Array>;
25
62
  protected startReader(): Promise<void>;
26
- query1(): Promise<Query1ReplyD2HPacket | null>;
27
- getSystemVersion(): Promise<VexFirmwareVersion | null>;
63
+ query1(): ResultAsync<Query1ReplyD2HPacket, VexSerialError>;
64
+ getSystemVersion(): ResultAsync<VexFirmwareVersion, VexSerialError>;
28
65
  }
29
66
  export declare class V5SerialConnection extends VexSerialConnection {
30
67
  filters: SerialPortFilter[];
31
- getDeviceStatus(): Promise<GetDeviceStatusReplyD2HPacket | null>;
32
- getRadioStatus(): Promise<GetRadioStatusReplyD2HPacket | null>;
33
- getSystemFlags(): Promise<GetSystemFlagsReplyD2HPacket | null>;
34
- getSystemStatus(timeout?: number): Promise<GetSystemStatusReplyD2HPacket | null>;
35
- getMatchStatus(): Promise<MatchStatusReplyD2HPacket | null>;
36
- uploadProgramToDevice(iniConfig: ProgramIniConfig, binFileBuf: Uint8Array, coldFileBuf: Uint8Array | undefined, progressCallback: (state: string, current: number, total: number) => void): Promise<boolean | undefined>;
37
- downloadFileToHost(request: IFileBasicInfo, downloadTarget?: FileDownloadTarget, progressCallback?: (current: number, total: number) => void): Promise<Uint8Array>;
38
- uploadFileToDevice(request: IFileWriteRequest, progressCallback?: (current: number, total: number) => void): Promise<boolean>;
39
- setMatchMode(mode: MatchMode): Promise<MatchModeReplyD2HPacket | null>;
40
- loadProgram(value: SlotNumber | string): Promise<LoadFileActionReplyD2HPacket | null>;
41
- stopProgram(): Promise<LoadFileActionReplyD2HPacket | null>;
42
- mockTouch(x: number, y: number, press: boolean): Promise<SendDashTouchReplyD2HPacket | null>;
43
- /** @param port untested */
44
- openScreen(screen: number | SelectDashScreen, port: number): Promise<SelectDashReplyD2HPacket | null>;
68
+ /**
69
+ * Serialize every transfer that touches the device's file-transfer mode
70
+ * through a single connection-level queue. Each call returns the prior
71
+ * tail and chains after it, so transfers always execute in request
72
+ * order without packet interleaving.
73
+ */
74
+ withFileTransfer<T>(operation: () => Promise<T>): Promise<T>;
75
+ getDeviceStatus(): ResultAsync<GetDeviceStatusReplyD2HPacket, VexSerialError>;
76
+ getRadioStatus(): ResultAsync<GetRadioStatusReplyD2HPacket, VexSerialError>;
77
+ getSystemFlags(): ResultAsync<GetSystemFlagsReplyD2HPacket, VexSerialError>;
78
+ getSystemStatus(timeout?: number): ResultAsync<GetSystemStatusReplyD2HPacket, VexSerialError>;
79
+ getMatchStatus(): ResultAsync<MatchStatusReplyD2HPacket, VexSerialError>;
80
+ /**
81
+ * Upload an entire program (INI, optional cold binary, and the user
82
+ * binary) under a single connection-level transaction so that no other
83
+ * file-transfer request can interleave with the multi-file write.
84
+ */
85
+ uploadProgramToDevice(iniConfig: ProgramIniConfig, binFileBuf: Uint8Array, coldFileBuf: Uint8Array | undefined, progressCallback: (state: string, current: number, total: number) => void): ResultAsync<boolean, VexSerialError>;
86
+ private _uploadProgramToDevice;
87
+ downloadFileToHost(request: IFileBasicInfo, downloadTarget?: FileDownloadTarget, progressCallback?: (current: number, total: number) => void): ResultAsync<Uint8Array, VexSerialError>;
88
+ /**
89
+ * Run a download without acquiring the connection-level transfer lock.
90
+ * Intended for callers that already hold a transaction (such as
91
+ * `captureScreen`) and need to issue the download within a larger
92
+ * queued operation.
93
+ */
94
+ downloadFileToHostUnlocked(request: IFileBasicInfo, downloadTarget?: FileDownloadTarget, progressCallback?: (current: number, total: number) => void): ResultAsync<Uint8Array, VexSerialError>;
95
+ private _downloadFileToHostUnlocked;
96
+ uploadFileToDevice(request: IFileWriteRequest, progressCallback?: (current: number, total: number) => void): ResultAsync<boolean, VexSerialError>;
97
+ uploadFileToDeviceUnlocked(request: IFileWriteRequest, progressCallback?: (current: number, total: number) => void): Promise<Result<boolean, VexSerialError>>;
98
+ /**
99
+ * Erase a single file under a single transfer-mode session, exiting
100
+ * file-transfer mode in a `finally` block regardless of how the
101
+ * operation completes.
102
+ */
103
+ removeFile(request: IFileBasicInfo | string): ResultAsync<void, VexSerialError>;
104
+ /**
105
+ * Erase every file in the user vendor namespace under a single
106
+ * transfer-mode session.
107
+ */
108
+ removeAllFiles(): ResultAsync<void, VexSerialError>;
109
+ /**
110
+ * Issue the screen-capture command and validate that the device
111
+ * acknowledged it. Callers must inspect the returned packet (or the
112
+ * error result on NACK) before downloading the framebuffer so that a
113
+ * rejected request performs no download.
114
+ */
115
+ captureScreenSetup(): ResultAsync<ScreenCaptureReplyD2HPacket, VexSerialError>;
116
+ captureScreen(progressCallback?: (current: number, total: number) => void): ResultAsync<Uint8Array, VexSerialError>;
117
+ private _captureScreen;
118
+ setMatchMode(mode: MatchMode): ResultAsync<MatchModeReplyD2HPacket, VexSerialError>;
119
+ runProgram(value: SlotNumber | string): ResultAsync<LoadFileActionReplyD2HPacket, VexSerialError>;
120
+ loadProgram(value: SlotNumber | string): ResultAsync<LoadFileActionReplyD2HPacket, VexSerialError>;
121
+ stopProgram(): ResultAsync<LoadFileActionReplyD2HPacket, VexSerialError>;
122
+ mockTouch(x: number, y: number, press: boolean): ResultAsync<SendDashTouchReplyD2HPacket, VexSerialError>;
123
+ openScreen(screen: number | SelectDashScreen, port: number): ResultAsync<SelectDashReplyD2HPacket, VexSerialError>;
45
124
  }
125
+ export {};
@@ -1,177 +1,72 @@
1
- /// <reference types="dom-serial" />
2
- import { type MatchMode, SerialDeviceType, type ISmartDeviceInfo, SmartDeviceType, FileVendor, type IProgramInfo, type IFileHandle, FileDownloadTarget, type IFileBasicInfo, type IFileWriteRequest, RadioChannelType } from "./Vex";
3
- import { V5SerialConnection } from "./VexConnection";
4
- import { VexEventTarget } from "./VexEvent";
5
- import { VexFirmwareVersion } from "./VexFirmwareVersion";
6
- import { type ProgramIniConfig } from "./VexIniConfig";
7
- export declare function downloadFileFromInternet(link: string): Promise<ArrayBuffer>;
8
- export declare function sleepUntilAsync(f: () => Promise<boolean>, timeout: number, interval?: number): Promise<boolean>;
9
- export declare function sleepUntil(f: () => boolean, timeout: number, interval?: number): Promise<boolean>;
10
- export declare function sleep(ms: number): Promise<unknown>;
11
- export declare abstract class VexSerialDevice extends VexEventTarget {
12
- connection: V5SerialConnection | undefined;
13
- defaultSerial: Serial;
14
- get isConnected(): boolean;
15
- get deviceType(): SerialDeviceType | undefined;
16
- constructor(defaultSerial: Serial);
17
- abstract connect(conn?: V5SerialConnection): Promise<boolean>;
18
- abstract disconnect(): void;
19
- }
20
- declare class V5SerialDeviceState {
21
- _instance: V5SerialDevice;
22
- _isFileTransferring: boolean;
23
- brain: {
24
- activeProgram: number;
25
- battery: {
26
- batteryPercent: number;
27
- isCharging: boolean;
28
- };
29
- button: {
30
- isPressed: boolean;
31
- isDoublePressed: boolean;
32
- };
33
- cpu0Version: VexFirmwareVersion;
34
- cpu1Version: VexFirmwareVersion;
35
- isAvailable: boolean;
36
- settings: {
37
- isScreenReversed: boolean;
38
- isWhiteTheme: boolean;
39
- usingLanguage: number;
40
- };
41
- systemVersion: VexFirmwareVersion;
42
- uniqueId: number;
43
- };
44
- controllers: ({
45
- battery: number;
46
- isAvailable: boolean;
47
- isCharging: boolean;
48
- } | {
49
- battery: number;
50
- isAvailable: boolean;
51
- isCharging?: undefined;
52
- })[];
53
- devices: Array<ISmartDeviceInfo | undefined>;
54
- isFieldControllerConnected: boolean;
55
- matchMode: MatchMode;
56
- radio: {
57
- channel: number;
58
- isAvailable: boolean;
59
- isConnected: boolean;
60
- isVexNet: boolean;
61
- isRadioData: boolean;
62
- latency: number;
63
- signalQuality: number;
64
- signalStrength: number;
65
- };
66
- constructor(instance: V5SerialDevice);
67
- }
68
- export declare class V5Brain {
69
- private readonly state;
70
- constructor(state: V5SerialDeviceState);
71
- get isRunningProgram(): boolean;
72
- get activeProgram(): number;
73
- set activeProgram(value: number);
74
- get battery(): V5Battery;
75
- get button(): V5BrainButton;
76
- get cpu0Version(): VexFirmwareVersion;
77
- get cpu1Version(): VexFirmwareVersion;
78
- get isAvailable(): boolean;
79
- get settings(): V5BrainSettings;
80
- get systemVersion(): VexFirmwareVersion;
81
- get uniqueId(): number;
82
- getValue(key: string): Promise<string | undefined>;
83
- setValue(key: string, value: string): Promise<boolean>;
84
- listFiles(vendor?: FileVendor): Promise<IFileHandle[] | undefined>;
85
- listProgram(): Promise<IProgramInfo[] | undefined>;
86
- readFile(request: IFileBasicInfo | string, downloadTarget?: FileDownloadTarget, progressCallback?: (current: number, total: number) => void): Promise<Uint8Array | undefined>;
87
- removeFile(request: IFileBasicInfo | string): Promise<boolean | undefined>;
88
- removeAllFiles(): Promise<boolean | undefined>;
89
- uploadFirmware(publicUrl?: string, usingVersion?: string, progressCallback?: (state: string, current: number, total: number) => void): Promise<boolean | undefined>;
90
- uploadProgram(iniConfig: ProgramIniConfig, binFileBuf: Uint8Array, coldFileBuf: Uint8Array | undefined, progressCallback: (state: string, current: number, total: number) => void): Promise<boolean | undefined>;
91
- writeFile(request: IFileWriteRequest, progressCallback?: (current: number, total: number) => void): Promise<boolean | undefined>;
92
- /**
93
- *
94
- * @param progressCallback Informs the progress of the download.
95
- * @returns array of bytes where each pixel is represented by 3 consecutive bytes (rgb).
96
- * This array's length is 272 width * 480 height * 3 channels = 391680 bytes.
97
- */
98
- captureScreen(progressCallback?: (current: number, total: number) => void): Promise<Uint8Array | undefined>;
99
- }
100
- export declare class V5Battery {
101
- private readonly state;
102
- constructor(state: V5SerialDeviceState);
103
- get batteryPercent(): number;
104
- get isCharging(): boolean;
105
- }
106
- export declare class V5BrainButton {
107
- private readonly state;
108
- constructor(state: V5SerialDeviceState);
109
- get isPressed(): boolean;
110
- get isDoublePressed(): boolean;
111
- }
112
- export declare class V5BrainSettings {
113
- private readonly state;
114
- constructor(state: V5SerialDeviceState);
115
- get isScreenReversed(): boolean;
116
- get isWhiteTheme(): boolean;
117
- get usingLanguage(): number;
118
- }
119
- export declare class V5Controller {
120
- private readonly state;
121
- private readonly controllerIndex;
122
- constructor(state: V5SerialDeviceState, controllerIndex: number);
123
- get batteryPercent(): number;
124
- get isMasterController(): boolean;
125
- get isAvailable(): boolean;
126
- get isCharging(): boolean | undefined;
127
- }
128
- export declare class V5SmartDevice {
129
- private readonly state;
130
- private readonly deviceIndex;
131
- constructor(state: V5SerialDeviceState, index: number);
132
- protected getDeviceInfo(): ISmartDeviceInfo | undefined;
133
- get isAvailable(): boolean;
134
- get port(): number;
135
- get type(): SmartDeviceType;
136
- get version(): number;
137
- }
138
- export declare class V5Radio {
139
- private readonly state;
140
- constructor(state: V5SerialDeviceState);
141
- get channel(): number;
142
- get isAvailable(): boolean;
143
- get isConnected(): boolean;
144
- get isVexNet(): boolean;
145
- get isRadioData(): boolean;
146
- get latency(): number;
147
- changeChannel(channel: RadioChannelType): Promise<boolean>;
148
- }
1
+ import { type MatchMode } from "./Vex.js";
2
+ import { V5SerialConnection } from "./VexConnection.js";
3
+ import { V5Brain, V5Controller, V5Radio, V5SerialDeviceState, V5SmartDevice, VexSerialDevice } from "./VexDeviceState.js";
4
+ import { VexSerialError } from "./VexError.js";
5
+ import { ResultAsync } from "neverthrow";
6
+ export { VexSerialDevice, V5Brain, V5Battery, V5BrainButton, V5BrainSettings, V5Controller, V5SmartDevice, V5Radio, V5SerialDeviceState, } from "./VexDeviceState.js";
7
+ export { sleep, sleepUntil, sleepUntilAsync, downloadFileFromInternet, uploadFirmware, } from "./VexFirmware.js";
149
8
  export declare class V5SerialDevice extends VexSerialDevice {
150
9
  autoReconnect: boolean;
151
- autoRefresh: boolean;
152
10
  pauseRefreshOnFileTransfer: boolean;
153
11
  protected _isReconnecting: boolean;
12
+ private _isDisconnecting;
154
13
  private _refreshInterval;
155
14
  state: V5SerialDeviceState;
156
- constructor(defaultSerial: Serial);
15
+ private _disposed;
16
+ private _refreshGeneration;
17
+ private _autoRefresh;
18
+ private _isLastRefreshComplete;
19
+ private readonly _brain;
20
+ private readonly _controllers;
21
+ private readonly _radio;
22
+ private readonly _deviceFacades;
23
+ constructor(defaultSerial: Serial, autoRefresh?: boolean);
24
+ get autoRefresh(): boolean;
25
+ set autoRefresh(value: boolean);
26
+ private _startRefreshInterval;
27
+ private _stopRefreshInterval;
157
28
  get isV5Controller(): boolean;
158
29
  get brain(): V5Brain;
159
30
  get controllers(): [V5Controller, V5Controller];
160
31
  get devices(): V5SmartDevice[];
161
32
  get isFieldControllerConnected(): boolean;
162
33
  get matchMode(): MatchMode;
34
+ /**
35
+ * @deprecated Setting this property dispatches a fire-and-forget
36
+ * request whose result cannot be observed. Use {@link setMatchMode}
37
+ * instead, which returns a {@link ResultAsync} that resolves to an
38
+ * error result when the device refuses or is disconnected.
39
+ */
163
40
  set matchMode(value: MatchMode);
41
+ /**
42
+ * Update the match mode and resolve only after the device
43
+ * acknowledges the command. Resolves to an error result when the
44
+ * device NACKs, the request times out, or no connection is open.
45
+ */
46
+ setMatchMode(mode: MatchMode): ResultAsync<void, VexSerialError>;
164
47
  get radio(): V5Radio;
165
- mockTouch(x: number, y: number, press: boolean): Promise<boolean>;
166
- connect(conn?: V5SerialConnection): Promise<boolean>;
48
+ mockTouch(x: number, y: number, press: boolean): ResultAsync<void, VexSerialError>;
49
+ connect(conn?: V5SerialConnection): ResultAsync<void, VexSerialError>;
50
+ private _connect;
167
51
  disconnect(): Promise<void>;
168
52
  dispose(): Promise<void>;
169
53
  /**
170
- * @param timeout defaults to 0. If timeout is 0, then it will attempt to reconnect forever
171
- * @returns
54
+ * @param timeout defaults to 0. If timeout is 0, then it will attempt to reconnect forever.
172
55
  */
173
- reconnect(timeout?: number): Promise<boolean>;
56
+ reconnect(timeout?: number): ResultAsync<void, VexSerialError>;
57
+ private _reconnect;
58
+ private waitForReconnectToFinish;
174
59
  private doAfterConnect;
175
- refresh(): Promise<boolean>;
60
+ /**
61
+ * Refresh the high-level device snapshot. All required replies are
62
+ * collected before any public state is mutated, so callers never see
63
+ * a half-updated view. A failed or missing reply resolves to an `Ok`
64
+ * of `false` (the previous snapshot is preserved and only the
65
+ * `isAvailable` flag is updated) so transient communication loss does
66
+ * not surface as a hard error result.
67
+ */
68
+ refresh(): ResultAsync<boolean, VexSerialError>;
69
+ private _refresh;
70
+ private _buildSnapshot;
71
+ private _applySnapshotIfCurrent;
176
72
  }
177
- export {};