@v5x/serial 0.5.6 → 0.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -4
- package/dist/Vex.d.ts +3 -1
- package/dist/VexConnection.d.ts +48 -3
- package/dist/VexDevice.d.ts +22 -1
- package/dist/VexDeviceState.d.ts +18 -5
- package/dist/VexError.d.ts +1 -0
- package/dist/VexEvent.d.ts +0 -1
- package/dist/VexFirmware.d.ts +1 -0
- package/dist/VexPacketCore.d.ts +5 -0
- package/dist/VexPacketEncoder.d.ts +2 -0
- package/dist/VexPacketModels.d.ts +1 -1
- package/dist/VexPacketRegistry.d.ts +3 -0
- package/dist/VexScreenCapture.d.ts +2 -0
- package/dist/VexTransfers.d.ts +1 -0
- package/dist/index.cjs +802 -963
- package/dist/index.cjs.map +14 -14
- package/dist/index.js +898 -1011
- package/dist/index.js.map +14 -14
- package/dist/packet-core.cjs +383 -0
- package/dist/packet-core.cjs.map +14 -0
- package/dist/packet-core.js +341 -0
- package/dist/packet-core.js.map +14 -0
- package/package.json +11 -4
package/README.md
CHANGED
|
@@ -29,7 +29,10 @@ if (opened.isErr()) {
|
|
|
29
29
|
console.error(opened.error); // VexSerialError with a stable .kind
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
if (opened.value !== "opened") {
|
|
33
|
+
console.error(`Unable to open a compatible port: ${opened.value}`);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
33
36
|
|
|
34
37
|
const status = await connection.getSystemStatus();
|
|
35
38
|
if (status.isOk()) {
|
|
@@ -81,9 +84,9 @@ removed. Migrate to the corresponding `setMatchMode()` / `setActiveProgram()`
|
|
|
81
84
|
methods and handle the returned `Result`.
|
|
82
85
|
|
|
83
86
|
Legacy methods that resolved to `false`, `null`, or `undefined` on failure now
|
|
84
|
-
return a typed `Err` instead
|
|
85
|
-
the `Ok` channel
|
|
86
|
-
|
|
87
|
+
return a typed `Err` instead. `open()` reports non-error connection outcomes on
|
|
88
|
+
the `Ok` channel as `"opened"`, `"busy"`, or `"no-port"`; only `"opened"`
|
|
89
|
+
indicates an established connection.
|
|
87
90
|
|
|
88
91
|
## Transfers and timeouts
|
|
89
92
|
|
|
@@ -112,3 +115,33 @@ bun run build
|
|
|
112
115
|
```
|
|
113
116
|
|
|
114
117
|
The build emits JavaScript bundles and TypeScript declarations under `dist/`.
|
|
118
|
+
|
|
119
|
+
### Packet registry and browser bundle measurement
|
|
120
|
+
|
|
121
|
+
The complete entry point registers every reply class explicitly. Packet
|
|
122
|
+
decoding no longer discovers classes by enumerating the packet-model module at
|
|
123
|
+
runtime. Consumers that only need framing, CRC, packet base classes, and a
|
|
124
|
+
custom reply registry can import `@v5x/serial/packet-core`; that entry point
|
|
125
|
+
does not retain file-transfer, firmware, screenshot, or dashboard models.
|
|
126
|
+
Register only the reply classes the application accepts with
|
|
127
|
+
`PacketEncoder.getInstance().registerPacketTypes(...)`.
|
|
128
|
+
|
|
129
|
+
Run `bun run measure:bundles` in this package to report reproducible minified
|
|
130
|
+
byte sizes for the complete browser entry and the packet-core entry.
|
|
131
|
+
|
|
132
|
+
### File-transfer window semantics
|
|
133
|
+
|
|
134
|
+
The `windowSize` returned by `InitFileTransferReplyD2HPacket` is the maximum
|
|
135
|
+
data size for one `ReadFile` or `WriteFile` block. It is not a count of blocks
|
|
136
|
+
that may be outstanding. This follows from the wire model: read and write
|
|
137
|
+
replies carry only the shared CDC2 command and function IDs; write replies have
|
|
138
|
+
no address, sequence number, or request identifier with which to correlate an
|
|
139
|
+
individual outstanding block. A read address can validate a reply after it is
|
|
140
|
+
routed, but cannot make write failures unambiguous.
|
|
141
|
+
|
|
142
|
+
Transfers therefore intentionally remain stop-and-wait. The advertised value
|
|
143
|
+
is clamped to the library's 4096-byte block limit and used only as the chunk
|
|
144
|
+
size. There is no safe before/after pipelining benchmark to run because the
|
|
145
|
+
protocol does not expose the correlation needed to enable pipelining without
|
|
146
|
+
risking data corruption. Hardware throughput remains dependent on one USB
|
|
147
|
+
round trip per block.
|
package/dist/Vex.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="dom-serial" preserve="true" />
|
|
1
2
|
import { type VexFirmwareVersion } from "./VexFirmwareVersion.js";
|
|
2
3
|
import { type HostBoundPacket } from "./VexPacket.js";
|
|
3
4
|
export declare const USER_PROG_CHUNK_SIZE = 4096;
|
|
@@ -134,7 +135,8 @@ export declare enum AckType {
|
|
|
134
135
|
CDC2_NACK_FILE_EXISTS = 219,
|
|
135
136
|
CDC2_NACK_FILE_SYS_FULL = 220,
|
|
136
137
|
TIMEOUT = 256,
|
|
137
|
-
WRITE_ERROR = 257
|
|
138
|
+
WRITE_ERROR = 257,
|
|
139
|
+
NOT_CONNECTED = 258
|
|
138
140
|
}
|
|
139
141
|
export declare enum SmartDeviceType {
|
|
140
142
|
EMPTY = 0,
|
package/dist/VexConnection.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="dom-serial" preserve="true" />
|
|
1
2
|
import { AckType, FileDownloadTarget, type IFileBasicInfo, type IFileWriteRequest, type IPacketCallback, type MatchMode, type SlotNumber, type SelectDashScreen } from "./Vex.js";
|
|
2
3
|
import { VexSerialError } from "./VexError.js";
|
|
3
4
|
import { VexEventTarget } from "./VexEvent.js";
|
|
@@ -34,17 +35,29 @@ export declare class VexSerialConnection extends VexEventTarget<VexSerialConnect
|
|
|
34
35
|
reader: ReadableStreamDefaultReader<unknown> | undefined;
|
|
35
36
|
port: SerialPort | undefined;
|
|
36
37
|
serial: Serial;
|
|
37
|
-
|
|
38
|
+
private pendingCallbacks;
|
|
39
|
+
private rawCallbacks;
|
|
40
|
+
private pendingCommandTails;
|
|
38
41
|
private _onPortDisconnect;
|
|
39
42
|
private _closePromise;
|
|
43
|
+
private _openPromise;
|
|
44
|
+
private _isClosing;
|
|
40
45
|
private _wasConnected;
|
|
41
46
|
protected fileTransferTail: Promise<unknown>;
|
|
42
47
|
protected fileTransferDepth: number;
|
|
48
|
+
/** Pending callbacks, exposed as a snapshot for backwards compatibility. */
|
|
49
|
+
get callbacksQueue(): IPacketCallback[];
|
|
43
50
|
get isConnected(): boolean;
|
|
44
51
|
get isFileTransferring(): boolean;
|
|
45
52
|
constructor(serial: Serial);
|
|
46
53
|
protected reportWarning(message: string, details?: unknown): void;
|
|
54
|
+
/**
|
|
55
|
+
* Connection events are notifications only: a consumer callback must not
|
|
56
|
+
* alter the lifecycle of the serial transport that produced it.
|
|
57
|
+
*/
|
|
58
|
+
private emitSafely;
|
|
47
59
|
close(): Promise<void>;
|
|
60
|
+
private _closeAfterOpen;
|
|
48
61
|
private _hasOpenResources;
|
|
49
62
|
private _doClose;
|
|
50
63
|
/**
|
|
@@ -52,14 +65,31 @@ export declare class VexSerialConnection extends VexEventTarget<VexSerialConnect
|
|
|
52
65
|
* `"busy"` when the matching port is already held elsewhere, and
|
|
53
66
|
* `"no-port"` when no matching port was selected. The result is `Err`
|
|
54
67
|
* when a connection is already open (programmer error) or when the
|
|
55
|
-
* port fails to open (permissions, dead device, ...).
|
|
68
|
+
* port fails to open (permissions, dead device, ...). Concurrent calls
|
|
69
|
+
* join the same open attempt and receive its result.
|
|
56
70
|
*/
|
|
57
71
|
open(use?: number, askUser?: boolean): ResultAsync<OpenResult, VexSerialError>;
|
|
58
72
|
private _open;
|
|
59
73
|
writeDataAsync(rawData: DeviceBoundPacket | Uint8Array, timeout?: number): Promise<HostBoundPacket | ArrayBuffer | AckType>;
|
|
74
|
+
/**
|
|
75
|
+
* A command ID identifies a reply packet type, not an individual request.
|
|
76
|
+
* Keep requests with the same reply identifiers off the wire until the
|
|
77
|
+
* preceding request has resolved, while allowing unrelated commands to run
|
|
78
|
+
* concurrently.
|
|
79
|
+
*/
|
|
80
|
+
private serializeCommand;
|
|
81
|
+
private writeDataAsyncUnserialized;
|
|
60
82
|
request<T extends HostBoundPacket>(packet: DeviceBoundPacket, ReplyType: HostBoundPacketType<T>, timeout?: number): ResultAsync<T, VexSerialError>;
|
|
61
|
-
protected readData(cache:
|
|
83
|
+
protected readData(cache: ReceiveBuffer, expectedSize: number): Promise<void>;
|
|
62
84
|
protected startReader(): Promise<void>;
|
|
85
|
+
private pendingKey;
|
|
86
|
+
private getPendingQueue;
|
|
87
|
+
private enqueuePendingCallback;
|
|
88
|
+
private removePendingCallback;
|
|
89
|
+
private shiftPendingCallback;
|
|
90
|
+
private shiftRawCallback;
|
|
91
|
+
private hasPendingCallbacks;
|
|
92
|
+
private drainPendingCallbacks;
|
|
63
93
|
query1(): ResultAsync<Query1ReplyD2HPacket, VexSerialError>;
|
|
64
94
|
getSystemVersion(): ResultAsync<VexFirmwareVersion, VexSerialError>;
|
|
65
95
|
}
|
|
@@ -122,4 +152,19 @@ export declare class V5SerialConnection extends VexSerialConnection {
|
|
|
122
152
|
mockTouch(x: number, y: number, press: boolean): ResultAsync<SendDashTouchReplyD2HPacket, VexSerialError>;
|
|
123
153
|
openScreen(screen: number | SelectDashScreen, port: number): ResultAsync<SelectDashReplyD2HPacket, VexSerialError>;
|
|
124
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* A growable receive queue. Parsed packets are copied out before their bytes
|
|
157
|
+
* are discarded, so views into this reusable storage never escape the reader.
|
|
158
|
+
*/
|
|
159
|
+
declare class ReceiveBuffer {
|
|
160
|
+
private storage;
|
|
161
|
+
private start;
|
|
162
|
+
private end;
|
|
163
|
+
get byteLength(): number;
|
|
164
|
+
get bytes(): Uint8Array<ArrayBuffer>;
|
|
165
|
+
append(chunk: Uint8Array): void;
|
|
166
|
+
copy(length: number): Uint8Array<ArrayBuffer>;
|
|
167
|
+
discard(length: number): void;
|
|
168
|
+
private reserve;
|
|
169
|
+
}
|
|
125
170
|
export {};
|
package/dist/VexDevice.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="dom-serial" preserve="true" />
|
|
1
2
|
import { type MatchMode } from "./Vex.js";
|
|
2
3
|
import { V5SerialConnection } from "./VexConnection.js";
|
|
3
4
|
import { V5Brain, V5Controller, V5Radio, V5SerialDeviceState, V5SmartDevice, VexSerialDevice } from "./VexDeviceState.js";
|
|
@@ -5,6 +6,10 @@ import { VexSerialError } from "./VexError.js";
|
|
|
5
6
|
import { ResultAsync } from "neverthrow";
|
|
6
7
|
export { VexSerialDevice, V5Brain, V5Battery, V5BrainButton, V5BrainSettings, V5Controller, V5SmartDevice, V5Radio, V5SerialDeviceState, } from "./VexDeviceState.js";
|
|
7
8
|
export { sleep, sleepUntil, sleepUntilAsync, downloadFileFromInternet, uploadFirmware, } from "./VexFirmware.js";
|
|
9
|
+
export interface V5SerialDeviceOptions {
|
|
10
|
+
autoRefresh?: boolean;
|
|
11
|
+
refreshIntervalMs?: number;
|
|
12
|
+
}
|
|
8
13
|
export declare class V5SerialDevice extends VexSerialDevice {
|
|
9
14
|
autoReconnect: boolean;
|
|
10
15
|
pauseRefreshOnFileTransfer: boolean;
|
|
@@ -13,16 +18,26 @@ export declare class V5SerialDevice extends VexSerialDevice {
|
|
|
13
18
|
private _refreshInterval;
|
|
14
19
|
state: V5SerialDeviceState;
|
|
15
20
|
private _disposed;
|
|
21
|
+
private _lifecycleGeneration;
|
|
22
|
+
private _disconnectListener;
|
|
16
23
|
private _refreshGeneration;
|
|
17
24
|
private _autoRefresh;
|
|
25
|
+
private _refreshIntervalMs;
|
|
18
26
|
private _isLastRefreshComplete;
|
|
19
27
|
private readonly _brain;
|
|
20
28
|
private readonly _controllers;
|
|
21
29
|
private readonly _radio;
|
|
22
30
|
private readonly _deviceFacades;
|
|
23
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Device lifecycle events are notifications only: consumer callbacks must
|
|
33
|
+
* not alter automatic refresh or reconnect work that produced them.
|
|
34
|
+
*/
|
|
35
|
+
private _emitSafely;
|
|
36
|
+
constructor(defaultSerial: Serial, options?: boolean | V5SerialDeviceOptions);
|
|
24
37
|
get autoRefresh(): boolean;
|
|
25
38
|
set autoRefresh(value: boolean);
|
|
39
|
+
get refreshIntervalMs(): number;
|
|
40
|
+
set refreshIntervalMs(value: number);
|
|
26
41
|
private _startRefreshInterval;
|
|
27
42
|
private _stopRefreshInterval;
|
|
28
43
|
get isV5Controller(): boolean;
|
|
@@ -56,7 +71,13 @@ export declare class V5SerialDevice extends VexSerialDevice {
|
|
|
56
71
|
reconnect(timeout?: number): ResultAsync<void, VexSerialError>;
|
|
57
72
|
private _reconnect;
|
|
58
73
|
private waitForReconnectToFinish;
|
|
74
|
+
protected createConnection(): V5SerialConnection;
|
|
75
|
+
private _isLifecycleCurrent;
|
|
76
|
+
private _staleLifecycleResult;
|
|
77
|
+
private _commitConnection;
|
|
78
|
+
private _detachDisconnectListener;
|
|
59
79
|
private doAfterConnect;
|
|
80
|
+
private _discardConnection;
|
|
60
81
|
/**
|
|
61
82
|
* Refresh the high-level device snapshot. All required replies are
|
|
62
83
|
* collected before any public state is mutated, so callers never see
|
package/dist/VexDeviceState.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="dom-serial" preserve="true" />
|
|
1
2
|
import { type MatchMode, SerialDeviceType, type SlotNumber, type ISmartDeviceInfo, SmartDeviceType, FileVendor, type IProgramInfo, type IFileHandle, type IFileBasicInfo, type IFileWriteRequest, FileDownloadTarget, RadioChannelType } from "./Vex.js";
|
|
2
3
|
import { type V5SerialConnection } from "./VexConnection.js";
|
|
3
4
|
import { VexEventTarget } from "./VexEvent.js";
|
|
@@ -64,11 +65,18 @@ export declare class V5SerialDeviceState {
|
|
|
64
65
|
systemVersion: VexFirmwareVersion;
|
|
65
66
|
uniqueId: number;
|
|
66
67
|
};
|
|
67
|
-
controllers:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
controllers: [
|
|
69
|
+
{
|
|
70
|
+
battery: number;
|
|
71
|
+
isAvailable: boolean;
|
|
72
|
+
isCharging: boolean | undefined;
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
battery: number;
|
|
76
|
+
isAvailable: boolean;
|
|
77
|
+
isCharging: boolean | undefined;
|
|
78
|
+
}
|
|
79
|
+
];
|
|
72
80
|
devices: Array<ISmartDeviceInfo | undefined>;
|
|
73
81
|
isFieldControllerConnected: boolean;
|
|
74
82
|
matchMode: MatchMode;
|
|
@@ -169,6 +177,11 @@ export declare class V5Controller {
|
|
|
169
177
|
get batteryPercent(): number;
|
|
170
178
|
get isMasterController(): boolean;
|
|
171
179
|
get isAvailable(): boolean;
|
|
180
|
+
/**
|
|
181
|
+
* Whether the controller is charging. The V5 system-status response only
|
|
182
|
+
* reports this state for the primary controller, so the partner controller
|
|
183
|
+
* returns `undefined`.
|
|
184
|
+
*/
|
|
172
185
|
get isCharging(): boolean | undefined;
|
|
173
186
|
}
|
|
174
187
|
export declare class V5SmartDevice {
|
package/dist/VexError.d.ts
CHANGED
package/dist/VexEvent.d.ts
CHANGED
|
@@ -16,6 +16,5 @@ export declare class VexEventTarget<TEvents extends object = Record<EventName, u
|
|
|
16
16
|
on<K extends EventMapKey<TEvents>>(eventName: K, listener: EventListener<TEvents[K]>): void;
|
|
17
17
|
remove<K extends EventMapKey<TEvents>>(eventName: K, listener: EventListener<TEvents[K]>): void;
|
|
18
18
|
clearListeners(): void;
|
|
19
|
-
private normalizeEventName;
|
|
20
19
|
}
|
|
21
20
|
export {};
|
package/dist/VexFirmware.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export declare class PacketEncoder {
|
|
|
11
11
|
allPacketsTable: Map<number, Map<number | undefined, typeof HostBoundPacket>>;
|
|
12
12
|
static getInstance(): PacketEncoder;
|
|
13
13
|
private constructor();
|
|
14
|
+
/** Register reply packet classes without retaining an entire module object. */
|
|
15
|
+
registerPacketTypes(types: Iterable<typeof HostBoundPacket>): void;
|
|
14
16
|
/** Look up the reply class registered for a command ID pair. */
|
|
15
17
|
getPacketType(commandId: number | undefined, commandExtendedId: number | undefined): typeof HostBoundPacket | undefined;
|
|
16
18
|
/** Create the vex CDC header. */
|
|
@@ -235,7 +235,7 @@ export declare class ReadFileReplyD2HPacket extends HostBoundPacket {
|
|
|
235
235
|
static COMMAND_EXTENDED_ID: number;
|
|
236
236
|
addr: number;
|
|
237
237
|
length: number;
|
|
238
|
-
buf:
|
|
238
|
+
buf: Uint8Array;
|
|
239
239
|
constructor(data: DataArray);
|
|
240
240
|
}
|
|
241
241
|
export declare class LinkFileReplyD2HPacket extends HostBoundPacket {
|
package/dist/VexTransfers.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="dom-serial" preserve="true" />
|
|
1
2
|
import { type IFileBasicInfo, type IFileHandle, FileVendor, type IProgramInfo, type IFileWriteRequest, FileDownloadTarget } from "./Vex.js";
|
|
2
3
|
import { type ProgramIniConfig } from "./VexIniConfig.js";
|
|
3
4
|
import type { V5SerialDeviceState } from "./VexDeviceState.js";
|