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.
Files changed (82) hide show
  1. package/LINUX_HID.md +85 -0
  2. package/README.md +74 -10
  3. package/SECURITY.md +24 -0
  4. package/dist/dualsense.d.ts +24 -8
  5. package/dist/dualsense.d.ts.map +1 -1
  6. package/dist/dualsense.js +53 -17
  7. package/dist/dualsense.js.map +1 -1
  8. package/dist/hid/bt_checksum.d.ts +7 -0
  9. package/dist/hid/bt_checksum.d.ts.map +1 -1
  10. package/dist/hid/bt_checksum.js +33 -1
  11. package/dist/hid/bt_checksum.js.map +1 -1
  12. package/dist/hid/dualsense_hid.d.ts +77 -0
  13. package/dist/hid/dualsense_hid.d.ts.map +1 -1
  14. package/dist/hid/dualsense_hid.js +193 -0
  15. package/dist/hid/dualsense_hid.js.map +1 -1
  16. package/dist/hid/factory_info.d.ts +53 -0
  17. package/dist/hid/factory_info.d.ts.map +1 -0
  18. package/dist/hid/factory_info.js +166 -0
  19. package/dist/hid/factory_info.js.map +1 -0
  20. package/dist/hid/firmware_info.d.ts +46 -0
  21. package/dist/hid/firmware_info.d.ts.map +1 -0
  22. package/dist/hid/firmware_info.js +109 -0
  23. package/dist/hid/firmware_info.js.map +1 -0
  24. package/dist/hid/hid_provider.d.ts +8 -0
  25. package/dist/hid/hid_provider.d.ts.map +1 -1
  26. package/dist/hid/hid_provider.js +7 -0
  27. package/dist/hid/hid_provider.js.map +1 -1
  28. package/dist/hid/index.d.ts +3 -0
  29. package/dist/hid/index.d.ts.map +1 -1
  30. package/dist/hid/index.js +3 -0
  31. package/dist/hid/index.js.map +1 -1
  32. package/dist/hid/node_hid_provider.d.ts +2 -0
  33. package/dist/hid/node_hid_provider.d.ts.map +1 -1
  34. package/dist/hid/node_hid_provider.js +14 -0
  35. package/dist/hid/node_hid_provider.js.map +1 -1
  36. package/dist/hid/pairing_info.d.ts +9 -0
  37. package/dist/hid/pairing_info.d.ts.map +1 -0
  38. package/dist/hid/pairing_info.js +33 -0
  39. package/dist/hid/pairing_info.js.map +1 -0
  40. package/dist/hid/web_hid_provider.d.ts +14 -0
  41. package/dist/hid/web_hid_provider.d.ts.map +1 -1
  42. package/dist/hid/web_hid_provider.js +79 -8
  43. package/dist/hid/web_hid_provider.js.map +1 -1
  44. package/dist/input.d.ts +6 -0
  45. package/dist/input.d.ts.map +1 -1
  46. package/dist/input.js +24 -0
  47. package/dist/input.js.map +1 -1
  48. package/dist/manager.d.ts +57 -4
  49. package/dist/manager.d.ts.map +1 -1
  50. package/dist/manager.js +248 -66
  51. package/dist/manager.js.map +1 -1
  52. package/nodehid_example/debug.ts +35 -13
  53. package/nodehid_example/single.ts +32 -5
  54. package/package.json +1 -1
  55. package/src/dualsense.ts +65 -23
  56. package/src/hid/bt_checksum.ts +39 -0
  57. package/src/hid/dualsense_hid.ts +230 -0
  58. package/src/hid/factory_info.ts +206 -0
  59. package/src/hid/firmware_info.ts +157 -0
  60. package/src/hid/hid_provider.ts +14 -0
  61. package/src/hid/index.ts +3 -0
  62. package/src/hid/node_hid_provider.ts +14 -0
  63. package/src/hid/pairing_info.ts +33 -0
  64. package/src/hid/web_hid_provider.ts +87 -8
  65. package/src/input.ts +25 -0
  66. package/src/manager.ts +285 -71
  67. package/webhid_example/build/asset-manifest.json +3 -3
  68. package/webhid_example/build/index.html +1 -1
  69. package/webhid_example/build/static/js/main.2ba4cfae.js +3 -0
  70. package/webhid_example/build/static/js/main.2ba4cfae.js.map +1 -0
  71. package/webhid_example/src/App.tsx +5 -1
  72. package/webhid_example/src/hud/AudioIndicator.tsx +4 -2
  73. package/webhid_example/src/hud/BatteryIndicator.tsx +4 -2
  74. package/webhid_example/src/hud/ColorIndicator.tsx +72 -0
  75. package/webhid_example/src/hud/ControllerConnection.tsx +29 -2
  76. package/webhid_example/src/hud/Debugger.tsx +31 -1
  77. package/webhid_example/src/hud/LightbarFadeButtons.tsx +2 -2
  78. package/webhid_example/src/hud/MuteLedControls.tsx +3 -2
  79. package/webhid_example/src/hud/index.tsx +1 -0
  80. package/webhid_example/build/static/js/main.fcf0c900.js +0 -3
  81. package/webhid_example/build/static/js/main.fcf0c900.js.map +0 -1
  82. /package/webhid_example/build/static/js/{main.fcf0c900.js.LICENSE.txt → main.2ba4cfae.js.LICENSE.txt} +0 -0
@@ -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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"}
@@ -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
- controller.connection.on("change", ({ state }) => {
19
- log(
20
- player,
21
- `Connected: ${state ? "yes" : "no"} - ${
22
- state ? (controller.wireless ? "bluetooth" : "usb") : ""
23
- }`,
24
- );
25
- if (state) {
26
- log(player, `Device: ${controller.deviceId ?? "unknown"}`);
27
- if (controller.serialNumber) {
28
- log(player, `Serial: ${controller.serialNumber}`);
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
- // Log stick positions
191
- controller.left.analog.on("change", (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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dualsense-ts",
3
- "version": "6.3.0",
3
+ "version": "6.5.0",
4
4
  "description": "A natural interface for your DualSense controller, with Typescript",
5
5
  "keywords": [
6
6
  "dualsense",
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
- /** Buffered battery reading, sampled on a slow cadence */
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
- /** Unique identifier for the connected device (path or fingerprint) */
132
- public get deviceId(): string | undefined {
133
- return this.hid.provider.deviceId;
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
- /** Hardware serial number of the connected device, if available */
137
- public get serialNumber(): string | undefined {
138
- return this.hid.provider.serialNumber;
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
- /** Refresh connection state */
241
- let lastConnected = false;
242
- setInterval(() => {
243
- const {
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 && !lastConnected) {
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
- lastConnected = connected;
256
- if (!connected) this.hid.provider.connect();
257
- }, 200);
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(this.playerLeds.bitmask, this.playerLeds.brightness);
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]);
@@ -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
+
@@ -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[],