dualsense-ts 6.3.0 → 6.5.0
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/LINUX_HID.md +85 -0
- package/README.md +74 -10
- package/SECURITY.md +24 -0
- package/dist/dualsense.d.ts +24 -8
- package/dist/dualsense.d.ts.map +1 -1
- package/dist/dualsense.js +53 -17
- package/dist/dualsense.js.map +1 -1
- package/dist/hid/bt_checksum.d.ts +7 -0
- package/dist/hid/bt_checksum.d.ts.map +1 -1
- package/dist/hid/bt_checksum.js +33 -1
- package/dist/hid/bt_checksum.js.map +1 -1
- package/dist/hid/dualsense_hid.d.ts +77 -0
- package/dist/hid/dualsense_hid.d.ts.map +1 -1
- package/dist/hid/dualsense_hid.js +193 -0
- package/dist/hid/dualsense_hid.js.map +1 -1
- package/dist/hid/factory_info.d.ts +53 -0
- package/dist/hid/factory_info.d.ts.map +1 -0
- package/dist/hid/factory_info.js +166 -0
- package/dist/hid/factory_info.js.map +1 -0
- package/dist/hid/firmware_info.d.ts +46 -0
- package/dist/hid/firmware_info.d.ts.map +1 -0
- package/dist/hid/firmware_info.js +109 -0
- package/dist/hid/firmware_info.js.map +1 -0
- package/dist/hid/hid_provider.d.ts +8 -0
- package/dist/hid/hid_provider.d.ts.map +1 -1
- package/dist/hid/hid_provider.js +7 -0
- package/dist/hid/hid_provider.js.map +1 -1
- package/dist/hid/index.d.ts +3 -0
- package/dist/hid/index.d.ts.map +1 -1
- package/dist/hid/index.js +3 -0
- package/dist/hid/index.js.map +1 -1
- package/dist/hid/node_hid_provider.d.ts +2 -0
- package/dist/hid/node_hid_provider.d.ts.map +1 -1
- package/dist/hid/node_hid_provider.js +14 -0
- package/dist/hid/node_hid_provider.js.map +1 -1
- package/dist/hid/pairing_info.d.ts +9 -0
- package/dist/hid/pairing_info.d.ts.map +1 -0
- package/dist/hid/pairing_info.js +33 -0
- package/dist/hid/pairing_info.js.map +1 -0
- package/dist/hid/web_hid_provider.d.ts +14 -0
- package/dist/hid/web_hid_provider.d.ts.map +1 -1
- package/dist/hid/web_hid_provider.js +79 -8
- package/dist/hid/web_hid_provider.js.map +1 -1
- package/dist/input.d.ts +6 -0
- package/dist/input.d.ts.map +1 -1
- package/dist/input.js +24 -0
- package/dist/input.js.map +1 -1
- package/dist/manager.d.ts +57 -4
- package/dist/manager.d.ts.map +1 -1
- package/dist/manager.js +248 -66
- package/dist/manager.js.map +1 -1
- package/nodehid_example/debug.ts +35 -13
- package/nodehid_example/single.ts +32 -5
- package/package.json +1 -1
- package/src/dualsense.ts +65 -23
- package/src/hid/bt_checksum.ts +39 -0
- package/src/hid/dualsense_hid.ts +230 -0
- package/src/hid/factory_info.ts +206 -0
- package/src/hid/firmware_info.ts +157 -0
- package/src/hid/hid_provider.ts +14 -0
- package/src/hid/index.ts +3 -0
- package/src/hid/node_hid_provider.ts +14 -0
- package/src/hid/pairing_info.ts +33 -0
- package/src/hid/web_hid_provider.ts +87 -8
- package/src/input.ts +25 -0
- package/src/manager.ts +285 -71
- package/webhid_example/build/asset-manifest.json +3 -3
- package/webhid_example/build/index.html +1 -1
- package/webhid_example/build/static/js/main.2ba4cfae.js +3 -0
- package/webhid_example/build/static/js/main.2ba4cfae.js.map +1 -0
- package/webhid_example/src/App.tsx +5 -1
- package/webhid_example/src/hud/AudioIndicator.tsx +4 -2
- package/webhid_example/src/hud/BatteryIndicator.tsx +4 -2
- package/webhid_example/src/hud/ColorIndicator.tsx +72 -0
- package/webhid_example/src/hud/ControllerConnection.tsx +29 -2
- package/webhid_example/src/hud/Debugger.tsx +31 -1
- package/webhid_example/src/hud/LightbarFadeButtons.tsx +2 -2
- package/webhid_example/src/hud/MuteLedControls.tsx +3 -2
- package/webhid_example/src/hud/index.tsx +1 -0
- package/webhid_example/build/static/js/main.fcf0c900.js +0 -3
- package/webhid_example/build/static/js/main.fcf0c900.js.map +0 -1
- /package/webhid_example/build/static/js/{main.fcf0c900.js.LICENSE.txt → main.2ba4cfae.js.LICENSE.txt} +0 -0
package/dist/manager.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"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"}
|
package/nodehid_example/debug.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Dualsense } from "../src/dualsense";
|
|
|
2
2
|
import { DualsenseManager } from "../src/manager";
|
|
3
3
|
import { TriggerEffect } from "../src/elements/trigger_feedback";
|
|
4
4
|
import { ChargeStatus } from "../src/hid/battery_state";
|
|
5
|
+
import { formatFirmwareVersion } from "../src/hid/firmware_info";
|
|
5
6
|
|
|
6
7
|
/** Map a -1..1 stick value to 0..1 */
|
|
7
8
|
function norm(value: number): number {
|
|
@@ -13,21 +14,42 @@ function log(player: number, ...args: unknown[]) {
|
|
|
13
14
|
console.log(`[P${player + 1}]`, ...args);
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
/** Log transport-level connection details (available immediately) */
|
|
18
|
+
function logConnection(controller: Dualsense, player: number) {
|
|
19
|
+
const connected = controller.connection.active;
|
|
20
|
+
log(
|
|
21
|
+
player,
|
|
22
|
+
`Connected: ${connected ? "yes" : "no"} - ${
|
|
23
|
+
connected ? (controller.wireless ? "bluetooth" : "usb") : ""
|
|
24
|
+
}`,
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Log firmware/factory identity (available after onReady) */
|
|
29
|
+
function logIdentity(controller: Dualsense, player: number) {
|
|
30
|
+
if (controller.hid.identity) {
|
|
31
|
+
log(player, `Identity: ${controller.hid.identity}`);
|
|
32
|
+
}
|
|
33
|
+
const fw = controller.firmwareInfo;
|
|
34
|
+
log(player, `Firmware: v${formatFirmwareVersion(fw.mainFirmwareVersion)} | HW: ${fw.hardwareInfo} | DSP: ${fw.dspFirmwareVersion} | Built: ${fw.buildDate} ${fw.buildTime}`);
|
|
35
|
+
const fi = controller.factoryInfo;
|
|
36
|
+
log(player, `Factory: ${fi.colorName} | ${fi.boardRevision} | Serial: ${fi.serialNumber}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
16
39
|
/** Set up all debug bindings for a single controller */
|
|
17
40
|
function bindController(controller: Dualsense, player: number) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
41
|
+
// Log the current connection state immediately.
|
|
42
|
+
logConnection(controller, player);
|
|
43
|
+
|
|
44
|
+
controller.connection.on("change", () => {
|
|
45
|
+
logConnection(controller, player);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Log identity details once firmware/factory info is available. On
|
|
49
|
+
// initial bind onReady fires synchronously (already resolved). On
|
|
50
|
+
// reconnect it fires after the background verification completes.
|
|
51
|
+
controller.hid.onReady(() => {
|
|
52
|
+
logIdentity(controller, player);
|
|
31
53
|
});
|
|
32
54
|
|
|
33
55
|
// Log battery level on connect and when it changes
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Dualsense } from "../src/dualsense";
|
|
2
2
|
import { TriggerEffect } from "../src/elements/trigger_feedback";
|
|
3
3
|
import { ChargeStatus } from "../src/hid/battery_state";
|
|
4
|
+
import { formatFirmwareVersion } from "../src/hid/firmware_info";
|
|
4
5
|
|
|
5
6
|
/** Map a -1..1 stick value to 0..1 */
|
|
6
7
|
function norm(value: number): number {
|
|
@@ -18,6 +19,16 @@ function main() {
|
|
|
18
19
|
state ? (controller.wireless ? "bluetooth" : "usb") : ""
|
|
19
20
|
}`,
|
|
20
21
|
);
|
|
22
|
+
if (state) {
|
|
23
|
+
const fw = controller.firmwareInfo;
|
|
24
|
+
console.log(
|
|
25
|
+
`Firmware: v${formatFirmwareVersion(fw.mainFirmwareVersion)} | HW: ${fw.hardwareInfo} | DSP: ${fw.dspFirmwareVersion} | Built: ${fw.buildDate} ${fw.buildTime}`,
|
|
26
|
+
);
|
|
27
|
+
const fi = controller.factoryInfo;
|
|
28
|
+
console.log(
|
|
29
|
+
`Factory: ${fi.colorName} | ${fi.boardRevision} | Serial: ${fi.serialNumber}`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
21
32
|
});
|
|
22
33
|
|
|
23
34
|
// Battery
|
|
@@ -187,17 +198,33 @@ function main() {
|
|
|
187
198
|
console.log(`Headphone: ${state ? "connected" : "disconnected"}`);
|
|
188
199
|
});
|
|
189
200
|
|
|
190
|
-
//
|
|
191
|
-
controller.left.analog
|
|
201
|
+
// Demonstrate listener removal: PS button toggles stick logging
|
|
202
|
+
const leftStickHandler = (analog: typeof controller.left.analog) => {
|
|
192
203
|
console.log(
|
|
193
204
|
`Left — x: ${analog.x.state.toFixed(2)}, y: ${analog.y.state.toFixed(2)}`,
|
|
194
205
|
);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
controller.right.analog.on("change", (analog) => {
|
|
206
|
+
};
|
|
207
|
+
const rightStickHandler = (analog: typeof controller.right.analog) => {
|
|
198
208
|
console.log(
|
|
199
209
|
`Right — x: ${analog.x.state.toFixed(2)}, y: ${analog.y.state.toFixed(2)}`,
|
|
200
210
|
);
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
let stickLogging = true;
|
|
214
|
+
controller.left.analog.on("change", leftStickHandler);
|
|
215
|
+
controller.right.analog.on("change", rightStickHandler);
|
|
216
|
+
|
|
217
|
+
controller.ps.on("press", () => {
|
|
218
|
+
stickLogging = !stickLogging;
|
|
219
|
+
if (stickLogging) {
|
|
220
|
+
controller.left.analog.on("change", leftStickHandler);
|
|
221
|
+
controller.right.analog.on("change", rightStickHandler);
|
|
222
|
+
console.log("Stick logging: on");
|
|
223
|
+
} else {
|
|
224
|
+
controller.left.analog.off("change", leftStickHandler);
|
|
225
|
+
controller.right.analog.off("change", rightStickHandler);
|
|
226
|
+
console.log("Stick logging: off");
|
|
227
|
+
}
|
|
201
228
|
});
|
|
202
229
|
}
|
|
203
230
|
|
package/package.json
CHANGED
package/src/dualsense.ts
CHANGED
|
@@ -23,6 +23,10 @@ import {
|
|
|
23
23
|
InputId,
|
|
24
24
|
ChargeStatus,
|
|
25
25
|
PulseOptions,
|
|
26
|
+
FirmwareInfo,
|
|
27
|
+
FactoryInfo,
|
|
28
|
+
DualsenseColor,
|
|
29
|
+
DualsenseColorMap,
|
|
26
30
|
} from "./hid";
|
|
27
31
|
import { Intensity } from "./math";
|
|
28
32
|
|
|
@@ -105,18 +109,39 @@ export class Dualsense extends Input<Dualsense> {
|
|
|
105
109
|
/** The 5 white player indicator LEDs */
|
|
106
110
|
public readonly playerLeds = new PlayerLeds();
|
|
107
111
|
|
|
108
|
-
/**
|
|
112
|
+
/**
|
|
113
|
+
* Buffered battery reading, sampled on a slow cadence
|
|
114
|
+
* Battery readings are prone to flip-flopping, so we buffer them
|
|
115
|
+
*/
|
|
109
116
|
private readonly pendingBattery = {
|
|
110
117
|
peakLevel: 0,
|
|
111
118
|
status: ChargeStatus.Discharging as ChargeStatus,
|
|
112
119
|
};
|
|
113
120
|
|
|
114
|
-
/** Represents the underlying HID device. Provides input events */
|
|
121
|
+
/** Represents the underlying HID device. Provides input events. */
|
|
115
122
|
public readonly hid: DualsenseHID;
|
|
116
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Firmware and hardware information.
|
|
126
|
+
* Contains sensible defaults until the device reports its actual values.
|
|
127
|
+
*/
|
|
128
|
+
public get firmwareInfo(): FirmwareInfo {
|
|
129
|
+
return this.hid.firmwareInfo;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Factory information (serial number, body color, board revision).
|
|
134
|
+
* Contains sensible defaults until the device reports its actual values.
|
|
135
|
+
* On Linux over Bluetooth the defaults persist (kernel limitation).
|
|
136
|
+
*/
|
|
137
|
+
public get factoryInfo(): FactoryInfo {
|
|
138
|
+
return this.hid.factoryInfo;
|
|
139
|
+
}
|
|
140
|
+
|
|
117
141
|
/** A virtual button representing whether or not a controller is connected */
|
|
118
142
|
public readonly connection: Momentary;
|
|
119
143
|
|
|
144
|
+
/** True if any input at all is active or changing */
|
|
120
145
|
public get active(): boolean {
|
|
121
146
|
return Object.values(this).some(
|
|
122
147
|
(input) => input !== this && input instanceof Input && input.active,
|
|
@@ -128,14 +153,16 @@ export class Dualsense extends Input<Dualsense> {
|
|
|
128
153
|
return this.hid.wireless;
|
|
129
154
|
}
|
|
130
155
|
|
|
131
|
-
/**
|
|
132
|
-
public get
|
|
133
|
-
|
|
156
|
+
/** Body color of the controller */
|
|
157
|
+
public get color(): DualsenseColor {
|
|
158
|
+
const { colorCode } = this.hid.factoryInfo;
|
|
159
|
+
if (colorCode in DualsenseColorMap) return DualsenseColorMap[colorCode];
|
|
160
|
+
return DualsenseColor.Unknown;
|
|
134
161
|
}
|
|
135
162
|
|
|
136
|
-
/**
|
|
137
|
-
public get serialNumber(): string
|
|
138
|
-
return this.hid.
|
|
163
|
+
/** Factory-stamped serial number of the controller */
|
|
164
|
+
public get serialNumber(): string {
|
|
165
|
+
return this.hid.factoryInfo.serialNumber;
|
|
139
166
|
}
|
|
140
167
|
|
|
141
168
|
constructor(params: DualsenseParams = {}) {
|
|
@@ -227,6 +254,10 @@ export class Dualsense extends Input<Dualsense> {
|
|
|
227
254
|
});
|
|
228
255
|
|
|
229
256
|
this.connection[InputSet](false);
|
|
257
|
+
// If a HID instance was supplied externally (e.g. by DualsenseManager),
|
|
258
|
+
// the owner is responsible for driving discovery + reconnection. Otherwise
|
|
259
|
+
// construct a default platform provider and run our own discovery loop.
|
|
260
|
+
const externallyManaged = params.hid != null;
|
|
230
261
|
this.hid = params.hid ?? new DualsenseHID(new PlatformHIDProvider());
|
|
231
262
|
this.hid.register((state: DualsenseHIDState) => {
|
|
232
263
|
this.processHID(state);
|
|
@@ -237,24 +268,32 @@ export class Dualsense extends Input<Dualsense> {
|
|
|
237
268
|
const lightbarMemo = { key: "" };
|
|
238
269
|
const playerLedsMemo = { key: "" };
|
|
239
270
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
provider: { connected },
|
|
245
|
-
} = this.hid;
|
|
246
|
-
|
|
271
|
+
// Mirror transport-level connect/disconnect into the connection Momentary,
|
|
272
|
+
// and invalidate output memos on rising-edge connect so the output loop
|
|
273
|
+
// re-pushes desired state to the new device.
|
|
274
|
+
this.hid.onConnectionChange((connected) => {
|
|
247
275
|
this.connection[InputSet](connected);
|
|
248
|
-
if (connected
|
|
249
|
-
// Invalidate memos so the output loop restores desired state on reconnect.
|
|
276
|
+
if (connected) {
|
|
250
277
|
triggerFeedbackMemo.left = "";
|
|
251
278
|
triggerFeedbackMemo.right = "";
|
|
252
279
|
lightbarMemo.key = "";
|
|
253
280
|
playerLedsMemo.key = "";
|
|
254
281
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
282
|
+
});
|
|
283
|
+
// Seed the initial state in case the provider was already attached.
|
|
284
|
+
this.connection[InputSet](this.hid.provider.connected);
|
|
285
|
+
|
|
286
|
+
// Standalone mode: poll for devices and reconnect on drop. In managed
|
|
287
|
+
// mode the manager owns this and we must NOT race with it.
|
|
288
|
+
if (!externallyManaged) {
|
|
289
|
+
setInterval(() => {
|
|
290
|
+
if (!this.hid.provider.connected) {
|
|
291
|
+
void Promise.resolve(this.hid.provider.connect()).catch(() => {
|
|
292
|
+
/* surfaced via onError */
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}, 200);
|
|
296
|
+
}
|
|
258
297
|
|
|
259
298
|
/** Refresh battery state on a slow cadence to filter transient glitches */
|
|
260
299
|
setInterval(() => {
|
|
@@ -314,13 +353,16 @@ export class Dualsense extends Input<Dualsense> {
|
|
|
314
353
|
|
|
315
354
|
const playerLedsKey = this.playerLeds.toKey();
|
|
316
355
|
if (playerLedsKey !== playerLedsMemo.key) {
|
|
317
|
-
this.hid.setPlayerLeds(
|
|
356
|
+
this.hid.setPlayerLeds(
|
|
357
|
+
this.playerLeds.bitmask,
|
|
358
|
+
this.playerLeds.brightness,
|
|
359
|
+
);
|
|
318
360
|
playerLedsMemo.key = playerLedsKey;
|
|
319
361
|
}
|
|
320
|
-
|
|
321
362
|
}, 1000 / 30);
|
|
322
363
|
}
|
|
323
364
|
|
|
365
|
+
/** Average rumble strength across both halves of the controller. */
|
|
324
366
|
private get rumbleIntensity(): number {
|
|
325
367
|
return (this.left.rumble() + this.right.rumble()) / 2;
|
|
326
368
|
}
|
|
@@ -338,7 +380,7 @@ export class Dualsense extends Input<Dualsense> {
|
|
|
338
380
|
return this.rumbleIntensity;
|
|
339
381
|
}
|
|
340
382
|
|
|
341
|
-
/** Distributes HID event values to the controller's inputs */
|
|
383
|
+
/** Distributes HID event values to the controller's public inputs. */
|
|
342
384
|
private processHID(state: DualsenseHIDState): void {
|
|
343
385
|
this.ps[InputSet](state[InputId.Playstation]);
|
|
344
386
|
this.options[InputSet](state[InputId.Options]);
|
package/src/hid/bt_checksum.ts
CHANGED
|
@@ -56,3 +56,42 @@ export function computeBluetoothReportChecksum(buffer: Uint8Array): number {
|
|
|
56
56
|
return result >>> 0;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/** Standard CRC-32 lookup table (polynomial 0xEDB88320) */
|
|
60
|
+
const crc32Table: number[] = (() => {
|
|
61
|
+
const table: number[] = [];
|
|
62
|
+
for (let n = 0; n < 256; n++) {
|
|
63
|
+
let c = n;
|
|
64
|
+
for (let k = 0; k < 8; k++) {
|
|
65
|
+
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
66
|
+
}
|
|
67
|
+
table[n] = c >>> 0;
|
|
68
|
+
}
|
|
69
|
+
return table;
|
|
70
|
+
})();
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Compute CRC-32 for a Bluetooth feature report.
|
|
74
|
+
* The CRC covers the HID transaction header (0x53), the report ID,
|
|
75
|
+
* and all payload bytes except the last 4 (which hold the CRC itself).
|
|
76
|
+
* Uses standard CRC-32 with final inversion.
|
|
77
|
+
*/
|
|
78
|
+
export function computeFeatureReportChecksum(
|
|
79
|
+
reportId: number,
|
|
80
|
+
buffer: Uint8Array,
|
|
81
|
+
): number {
|
|
82
|
+
let crc = 0xffffffff >>> 0;
|
|
83
|
+
|
|
84
|
+
// Feed prefix bytes: 0x53 (SET_REPORT feature) + report ID
|
|
85
|
+
crc = (crc >>> 8) ^ crc32Table[(crc ^ 0x53) & 0xff];
|
|
86
|
+
crc = (crc >>> 8) ^ crc32Table[(crc ^ reportId) & 0xff];
|
|
87
|
+
|
|
88
|
+
// Feed payload data (exclude last 4 bytes reserved for CRC)
|
|
89
|
+
const dataLen = buffer.length - 4;
|
|
90
|
+
for (let i = 0; i < dataLen; i++) {
|
|
91
|
+
crc = (crc >>> 8) ^ crc32Table[(crc ^ buffer[i]) & 0xff];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Final XOR (standard CRC-32 finalization)
|
|
95
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
96
|
+
}
|
|
97
|
+
|
package/src/hid/dualsense_hid.ts
CHANGED
|
@@ -5,9 +5,14 @@ import {
|
|
|
5
5
|
DefaultDualsenseHIDState,
|
|
6
6
|
} from "./hid_provider";
|
|
7
7
|
import { computeBluetoothReportChecksum } from "./bt_checksum";
|
|
8
|
+
import { FirmwareInfo, DefaultFirmwareInfo, readFirmwareInfo } from "./firmware_info";
|
|
9
|
+
import { FactoryInfo, DefaultFactoryInfo, readFactoryInfo } from "./factory_info";
|
|
10
|
+
import { readMacAddress } from "./pairing_info";
|
|
8
11
|
|
|
9
12
|
export type HIDCallback = (state: DualsenseHIDState) => void;
|
|
10
13
|
export type ErrorCallback = (error: Error) => void;
|
|
14
|
+
export type ReadyCallback = () => void;
|
|
15
|
+
export type ConnectionCallback = (connected: boolean) => void;
|
|
11
16
|
|
|
12
17
|
const SCOPE_A = 1;
|
|
13
18
|
const SCOPE_B = 2;
|
|
@@ -28,10 +33,26 @@ export class DualsenseHID {
|
|
|
28
33
|
private readonly subscribers = new Set<HIDCallback>();
|
|
29
34
|
/** Subscribers waiting for error updates */
|
|
30
35
|
private readonly errorSubscribers = new Set<ErrorCallback>();
|
|
36
|
+
/** Subscribers waiting for firmware/factory info to become available */
|
|
37
|
+
private readonly readySubscribers = new Set<ReadyCallback>();
|
|
38
|
+
/** Subscribers tracking transport-level connect/disconnect events */
|
|
39
|
+
private readonly connectionSubscribers = new Set<ConnectionCallback>();
|
|
40
|
+
/** True once firmware/factory info has been loaded for the current connection */
|
|
41
|
+
private identityResolved = false;
|
|
42
|
+
/** Pending retry timer for identity loading after a transient failure */
|
|
43
|
+
private identityRetryTimer?: ReturnType<typeof setTimeout>;
|
|
44
|
+
/** Number of identity-load attempts made for the current connection */
|
|
45
|
+
private identityRetryCount = 0;
|
|
31
46
|
/** Queue of pending HID commands */
|
|
32
47
|
private pendingCommands: CommandEvent[] = [];
|
|
33
48
|
/** Most recent HID state of the device */
|
|
34
49
|
public state: DualsenseHIDState = { ...DefaultDualsenseHIDState };
|
|
50
|
+
/** Firmware and hardware information, populated after connection */
|
|
51
|
+
public firmwareInfo: FirmwareInfo = DefaultFirmwareInfo;
|
|
52
|
+
/** Factory information (serial, color, board revision), populated after connection */
|
|
53
|
+
public factoryInfo: FactoryInfo = DefaultFactoryInfo;
|
|
54
|
+
/** Bluetooth MAC address from Feature Report 0x09, populated after connection */
|
|
55
|
+
public macAddress?: string;
|
|
35
56
|
|
|
36
57
|
constructor(
|
|
37
58
|
readonly provider: HIDProvider,
|
|
@@ -39,6 +60,24 @@ export class DualsenseHID {
|
|
|
39
60
|
) {
|
|
40
61
|
provider.onData = this.set.bind(this);
|
|
41
62
|
provider.onError = this.handleError.bind(this);
|
|
63
|
+
provider.onConnect = () => {
|
|
64
|
+
// Keep cached firmware/factory info from the prior session so that
|
|
65
|
+
// consumers see identity details immediately on a reconnection
|
|
66
|
+
// event. The background loadIdentity() call will verify and refresh
|
|
67
|
+
// the cache — if the hardware identity turns out different (e.g. a
|
|
68
|
+
// different controller grabbed the same slot), the fields get
|
|
69
|
+
// overwritten then.
|
|
70
|
+
this.firmwareFetch = undefined;
|
|
71
|
+
this.factoryFetch = undefined;
|
|
72
|
+
this.identityResolved = false;
|
|
73
|
+
this.cancelIdentityRetry();
|
|
74
|
+
this.connectionSubscribers.forEach((cb) => cb(true));
|
|
75
|
+
void this.loadIdentity();
|
|
76
|
+
};
|
|
77
|
+
provider.onDisconnect = () => {
|
|
78
|
+
this.cancelIdentityRetry();
|
|
79
|
+
this.connectionSubscribers.forEach((cb) => cb(false));
|
|
80
|
+
};
|
|
42
81
|
|
|
43
82
|
setInterval(() => {
|
|
44
83
|
if (this.pendingCommands.length > 0) {
|
|
@@ -79,6 +118,56 @@ export class DualsenseHID {
|
|
|
79
118
|
if (type === "error") this.errorSubscribers.add(callback);
|
|
80
119
|
}
|
|
81
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Subscribe to notification when firmware/factory info finishes loading
|
|
123
|
+
* after a connect. Fires once per connection — either when identity has
|
|
124
|
+
* been resolved, or when we've given up retrying. If identity is already
|
|
125
|
+
* resolved at the time of subscription, the callback fires synchronously.
|
|
126
|
+
*/
|
|
127
|
+
public onReady(callback: ReadyCallback): () => void {
|
|
128
|
+
if (this.identityResolved) {
|
|
129
|
+
callback();
|
|
130
|
+
return () => {};
|
|
131
|
+
}
|
|
132
|
+
this.readySubscribers.add(callback);
|
|
133
|
+
return () => this.readySubscribers.delete(callback);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** True if firmware/factory info has been loaded (or given up on) for the current connection */
|
|
137
|
+
public get ready(): boolean {
|
|
138
|
+
return this.identityResolved;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Subscribe to transport-level connect/disconnect events. Useful for
|
|
143
|
+
* mirroring connection state into an Input without polling. Returns
|
|
144
|
+
* an unsubscribe function.
|
|
145
|
+
*/
|
|
146
|
+
public onConnectionChange(callback: ConnectionCallback): () => void {
|
|
147
|
+
this.connectionSubscribers.add(callback);
|
|
148
|
+
return () => this.connectionSubscribers.delete(callback);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Stable hardware identity for this controller, derived from the most
|
|
153
|
+
* trustworthy info available. Prefers the Bluetooth MAC address (from
|
|
154
|
+
* Feature Report 0x09, works on every transport and platform), then
|
|
155
|
+
* falls back to the factory serial, then firmware deviceInfo.
|
|
156
|
+
* Returns undefined until identity info has been read.
|
|
157
|
+
*/
|
|
158
|
+
public get identity(): string | undefined {
|
|
159
|
+
if (this.macAddress) {
|
|
160
|
+
return `mac:${this.macAddress}`;
|
|
161
|
+
}
|
|
162
|
+
if (this.factoryInfo.serialNumber !== DefaultFactoryInfo.serialNumber) {
|
|
163
|
+
return `serial:${this.factoryInfo.serialNumber}`;
|
|
164
|
+
}
|
|
165
|
+
if (this.firmwareInfo.deviceInfo !== DefaultFirmwareInfo.deviceInfo) {
|
|
166
|
+
return `device:${this.firmwareInfo.deviceInfo}`;
|
|
167
|
+
}
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
|
|
82
171
|
/** Update the HID state and pass it along to all state subscribers */
|
|
83
172
|
private set(state: DualsenseHIDState): void {
|
|
84
173
|
this.state = state;
|
|
@@ -90,6 +179,147 @@ export class DualsenseHID {
|
|
|
90
179
|
this.errorSubscribers.forEach((callback) => callback(error));
|
|
91
180
|
}
|
|
92
181
|
|
|
182
|
+
/** Maximum identity-load retry attempts per connection */
|
|
183
|
+
private static readonly IDENTITY_MAX_ATTEMPTS = 5;
|
|
184
|
+
/** Backoff schedule (ms) for identity-load retries */
|
|
185
|
+
private static readonly IDENTITY_BACKOFF_MS = [500, 1500, 3000, 5000];
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Attempt to read firmware + factory info for the current connection,
|
|
189
|
+
* with retry on failure. Marks identity as resolved on success or after
|
|
190
|
+
* exhausting all attempts (so consumers don't wait forever).
|
|
191
|
+
*
|
|
192
|
+
* If cached firmware/factory info exists from a prior session, identity
|
|
193
|
+
* is resolved immediately (so the connection event has full details),
|
|
194
|
+
* then a background verification re-reads the device to confirm.
|
|
195
|
+
*/
|
|
196
|
+
private async loadIdentity(): Promise<void> {
|
|
197
|
+
if (!this.provider.connected) return;
|
|
198
|
+
|
|
199
|
+
// Fast path: if we already have cached identity from a prior session,
|
|
200
|
+
// mark resolved immediately so consumers see it on the connection event.
|
|
201
|
+
// Then continue to the verification read below.
|
|
202
|
+
const hadCachedIdentity = this.identity !== undefined;
|
|
203
|
+
if (hadCachedIdentity) {
|
|
204
|
+
this.markIdentityResolved();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this.identityRetryCount += 1;
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
// Read MAC address first — simple feature report, no firmware gate.
|
|
211
|
+
const mac = await readMacAddress(this.provider);
|
|
212
|
+
if (mac) this.macAddress = mac;
|
|
213
|
+
|
|
214
|
+
// Always read fresh from the device (bypass the idempotency cache).
|
|
215
|
+
const fw = await readFirmwareInfo(this.provider);
|
|
216
|
+
if (fw) {
|
|
217
|
+
this.firmwareInfo = fw;
|
|
218
|
+
this.firmwareFetch = Promise.resolve(fw);
|
|
219
|
+
|
|
220
|
+
const fi = await readFactoryInfo(
|
|
221
|
+
this.provider,
|
|
222
|
+
fw.hardwareInfo,
|
|
223
|
+
fw.mainFirmwareVersionRaw,
|
|
224
|
+
);
|
|
225
|
+
this.factoryInfo = fi ?? DefaultFactoryInfo;
|
|
226
|
+
this.factoryFetch = Promise.resolve(this.factoryInfo);
|
|
227
|
+
|
|
228
|
+
if (!hadCachedIdentity) {
|
|
229
|
+
this.markIdentityResolved();
|
|
230
|
+
}
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
} catch {
|
|
234
|
+
// Treat throws the same as undefined — fall through to retry logic.
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Failure — clear in-flight promises so the next attempt can retry.
|
|
238
|
+
this.firmwareFetch = undefined;
|
|
239
|
+
this.factoryFetch = undefined;
|
|
240
|
+
|
|
241
|
+
if (
|
|
242
|
+
this.identityRetryCount >= DualsenseHID.IDENTITY_MAX_ATTEMPTS ||
|
|
243
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
244
|
+
!this.provider.connected
|
|
245
|
+
) {
|
|
246
|
+
this.markIdentityResolved();
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const delay =
|
|
251
|
+
DualsenseHID.IDENTITY_BACKOFF_MS[
|
|
252
|
+
Math.min(
|
|
253
|
+
this.identityRetryCount - 1,
|
|
254
|
+
DualsenseHID.IDENTITY_BACKOFF_MS.length - 1,
|
|
255
|
+
)
|
|
256
|
+
];
|
|
257
|
+
this.identityRetryTimer = setTimeout(() => {
|
|
258
|
+
this.identityRetryTimer = undefined;
|
|
259
|
+
void this.loadIdentity();
|
|
260
|
+
}, delay);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** Mark identity loading as complete and notify subscribers */
|
|
264
|
+
private markIdentityResolved(): void {
|
|
265
|
+
if (this.identityResolved) return;
|
|
266
|
+
this.identityResolved = true;
|
|
267
|
+
this.identityRetryCount = 0;
|
|
268
|
+
const callbacks = Array.from(this.readySubscribers);
|
|
269
|
+
this.readySubscribers.clear();
|
|
270
|
+
callbacks.forEach((cb) => cb());
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Cancel any pending identity-load retry */
|
|
274
|
+
private cancelIdentityRetry(): void {
|
|
275
|
+
if (this.identityRetryTimer) {
|
|
276
|
+
clearTimeout(this.identityRetryTimer);
|
|
277
|
+
this.identityRetryTimer = undefined;
|
|
278
|
+
}
|
|
279
|
+
this.identityRetryCount = 0;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** In-flight firmware info fetch, deduped across callers within a connection */
|
|
283
|
+
private firmwareFetch?: Promise<FirmwareInfo>;
|
|
284
|
+
/** In-flight factory info fetch, deduped across callers within a connection */
|
|
285
|
+
private factoryFetch?: Promise<FactoryInfo>;
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Read firmware info from the controller (Feature Report 0x20).
|
|
289
|
+
* Idempotent: returns the cached value if already fetched, or the
|
|
290
|
+
* in-flight promise if a fetch is already underway.
|
|
291
|
+
*/
|
|
292
|
+
public fetchFirmwareInfo(): Promise<FirmwareInfo> {
|
|
293
|
+
if (this.firmwareInfo !== DefaultFirmwareInfo) return Promise.resolve(this.firmwareInfo);
|
|
294
|
+
if (this.firmwareFetch) return this.firmwareFetch;
|
|
295
|
+
this.firmwareFetch = readFirmwareInfo(this.provider).then((info) => {
|
|
296
|
+
this.firmwareInfo = info ?? DefaultFirmwareInfo;
|
|
297
|
+
return this.firmwareInfo;
|
|
298
|
+
});
|
|
299
|
+
return this.firmwareFetch;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Read factory info (serial number, body color, board revision) from the controller.
|
|
304
|
+
* Requires firmware info to be fetched first for feature gating.
|
|
305
|
+
* Idempotent across the lifetime of a single connection.
|
|
306
|
+
*/
|
|
307
|
+
public fetchFactoryInfo(): Promise<FactoryInfo> {
|
|
308
|
+
if (this.factoryInfo !== DefaultFactoryInfo) return Promise.resolve(this.factoryInfo);
|
|
309
|
+
if (this.factoryFetch) return this.factoryFetch;
|
|
310
|
+
if (this.firmwareInfo === DefaultFirmwareInfo) return Promise.resolve(DefaultFactoryInfo);
|
|
311
|
+
const fwInfo = this.firmwareInfo;
|
|
312
|
+
this.factoryFetch = readFactoryInfo(
|
|
313
|
+
this.provider,
|
|
314
|
+
fwInfo.hardwareInfo,
|
|
315
|
+
fwInfo.mainFirmwareVersionRaw,
|
|
316
|
+
).then((info) => {
|
|
317
|
+
this.factoryInfo = info ?? DefaultFactoryInfo;
|
|
318
|
+
return this.factoryInfo;
|
|
319
|
+
});
|
|
320
|
+
return this.factoryFetch;
|
|
321
|
+
}
|
|
322
|
+
|
|
93
323
|
/** Condense all pending commands into one HID feature report */
|
|
94
324
|
private static buildFeatureReport(
|
|
95
325
|
events: CommandEvent[],
|