Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions captures/razer-diamondback-chroma/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Razer Diamondback Chroma (`1532:004c`) hardware report, 2026-09-30

Reporter's own mouse, firmware "Mouse 1.0", wired, Windows. Connected through
OpenMouse Bridge with an unmodified `RazerHidClient`; the Bridge listed seven
HID paths for the device and opened all of them.

- `hardware-test-2026-09-30.json`: the app's hardware test export. Identity,
firmware, DPI (1800) and polling (500 Hz) read back; 800 DPI and 1000 Hz each
wrote, read back and were restored. Verdict: pass.

What it does not settle:

- Polling was read back but not measured: the sampler averaged 305 Hz against
the reported 500 Hz and flagged dropouts, so it skipped rather than failed.
- The DPI stage read (`0x04`/`0x86`) gave nothing usable, so no stage editor
is offered on this model.
- No raw feature reports were captured in this session.
132 changes: 132 additions & 0 deletions captures/razer-diamondback-chroma/hardware-test-2026-09-30.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
{
"device": {
"present": true,
"brand": "Razer",
"name": "Razer Diamondback Chroma",
"vendorId": 5426,
"productId": 76,
"productName": "Razer Diamondback Chroma",
"transport": "bridge",
"connectionType": "Wired",
"pollingRateHz": 500,
"supportedPollingRates": [
125,
500,
1000
],
"dpi": 1800,
"dpiStages": null,
"activeDpiStage": null,
"batteryPercent": null,
"batteryState": "Unknown",
"firmware": [
"Mouse 1.0"
],
"liftOffDistance": null,
"driverFamily": "razer",
"deviceMode": null,
"collectionsSummary": "interfaces 0x0001:0x0002, 0x000C:0x0001, 0x0001:0x0006, 0x0001:0x0080, 0x0001:0x0000",
"signalStrength": null,
"receiverOnline": null,
"receiverRfId": null,
"pairingInProgress": false
},
"results": [
{
"key": "connection",
"label": "Device connected",
"status": "pass",
"detail": "Connected through OpenMouse Bridge"
},
{
"key": "interface",
"label": "Control interface",
"status": "pass",
"detail": "interfaces 0x0001:0x0002, 0x000C:0x0001, 0x0001:0x0006, 0x0001:0x0080, 0x0001:0x0000"
},
{
"key": "identity",
"label": "Device identity",
"status": "pass",
"detail": "Razer Razer Diamondback Chroma"
},
{
"key": "driver",
"label": "Driver identification",
"status": "pass",
"detail": "Razer razer"
},
{
"key": "dpi",
"label": "DPI read-back",
"status": "pass",
"detail": "1,800 DPI"
},
{
"key": "pollingRead",
"label": "Polling rate read-back",
"status": "pass",
"detail": "500 Hz"
},
{
"key": "battery",
"label": "Battery read-back",
"status": "skip",
"detail": "Not reported by this device."
},
{
"key": "firmware",
"label": "Firmware read-back",
"status": "pass",
"detail": "Mouse 1.0"
},
{
"key": "liftOff",
"label": "Lift-off read-back",
"status": "skip",
"detail": "Not reported by this device."
},
{
"key": "link",
"label": "Wireless link (receiver)",
"status": "skip",
"detail": null
},
{
"key": "flashRead",
"label": "Flash / EEPROM read-back",
"status": "pass",
"detail": "decoded fields are in range (dpi, polling)"
},
{
"key": "brandWirelessBattery",
"label": "Razer wireless battery",
"status": "skip",
"detail": null
},
{
"key": "sampling",
"label": "Polling rate sampling",
"status": "skip",
"detail": "avg 305 Hz vs reported 500 Hz — dropout or rate mismatch detected, so the sample is not counted as a failure."
},
{
"key": "flashWrite",
"label": "Flash write round-trip",
"status": "pass",
"detail": "wrote 800 DPI → read back → restored 1,800 DPI · wrote 1,000 Hz → read back → restored 500 Hz · Lift-off skipped"
}
],
"verdict": "pass",
"durationMs": 17802.09999999404,
"runAt": "2026-09-30T21:58:33.335Z",
"build": "BETA · v2.0.58d",
"supportedPage": {
"listed": true,
"status": "likely",
"label": "Test Needed",
"matchedBy": "pid",
"pageModel": "Diamondback Chroma",
"detail": "listed as Test Needed on the supported-devices page — this passing verification supports moving it to Supported."
}
}
92 changes: 89 additions & 3 deletions docs/razer-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Identifiers verified on hardware:
- `1532:00a3` — Cobra, wired (separate driver)
- `1532:00b6` — DeathAdder V3 Pro, wired (firmware 2.1)
- `1532:00b7` — DeathAdder V3 Pro, stock HyperSpeed receiver (firmware 2.1)
- `1532:004c`: Diamondback Chroma, wired (firmware 1.0, through OpenMouse Bridge)

Mouse Dock Pro uses the same 90-byte protocol as the paired mouse. It has no
fixed polling list: if the paired mouse answers the extended polling command it
Expand Down Expand Up @@ -375,9 +376,11 @@ What is deliberately **not** attempted on an untested model:
`asymmetricLiftOff` is set, which only the four Viper V2/V3 Pro ids have. An
untested mouse that answers class `0x0b` still gets the plain three-stop
tracking control, which costs reads only.
- Lighting, button mapping and macros. The generic driver implements none of
them for any model — the only lighting controls anywhere in this project are
the dedicated Cobra and Viper Mini drivers.
- Lighting, button mapping and macros. Macros are not implemented for any
Razer model. Lighting and button mapping are per-product allowlists
(`standardMatrixLighting`, `buttonMapping`) that only list models someone
has connected; beyond them, the only lighting controls are the dedicated
Cobra and Viper Mini drivers.

To promote a model to verified:

Expand Down Expand Up @@ -868,3 +871,86 @@ other effects also use `0x3f`, but every other Cobra effect answers on `0x1f`
and breathing does too, so the single `0x1f` choice holds.

Brightness is not implemented: this driver covers effects and colour only.

## Diamondback Chroma (`1532:004c`)

Driven by the generic `RazerHidClient` on transaction id `0xff`. Verified on
firmware 1.0 over the cable, through OpenMouse Bridge on Windows: identity,
DPI and legacy polling read back, and an 800 DPI and a 1000 Hz write each
round-tripped and were restored. The report is in
`captures/razer-diamondback-chroma/`.

It is the one model this driver lights, through openrazer's older
standard-matrix family, and **the lighting has not been tried on hardware
yet**:

| Write | Class / ID | Notes |
| --- | --- | --- |
| Off / Spectrum / Wave / Static / Reactive / Breathing | `0x03` / `0x0a` | effect id first, no storage byte or led; one effect drives every LED |
| Backlight brightness | `0x03` / `0x03` | storage byte, backlight led (`0x05`), level on a 0-255 scale |

| Read | Class / ID | Notes |
| --- | --- | --- |
| Backlight brightness | `0x03` / `0x83` | level in the third byte |

The effect write has no read-back, so the panel shows the last effect it wrote
and marks the card write-only. Brightness is read on every refresh and
confirmed after each write. Wave always runs in direction `0x01`.

openrazer sends all of these on `0xff` except breathing, which it lists on
`0x3f` in the same block where it lists the Cobra. The Cobra's breathing
answered on its usual id, so breathing goes out on `0xff` here too. **If
breathing alone fails, that is the first thing to change.**

To test the lighting, with Synapse quit:

1. Open the Lighting tab and note the brightness it reads.
2. Pick each effect and watch the mouse: Off, Spectrum, Wave, Static, Reactive
(click to trigger it), and the three breathing modes.
3. Change the Static colour, the Reactive speed and both Breathing dual
colours.
4. Change the brightness, reload, and confirm the new level reads back.
5. Unplug the mouse and plug it back in, and note whether the effect and the
brightness survived. Nothing reads the effect back, so this is the only way
to learn whether it is stored.
6. Report any effect that errors or leaves the LEDs unchanged.

## Basilisk V3 (`1532:0099`) and Basilisk V3 35K (`1532:00cb`)

Driven by the generic `RazerHidClient`. Not verified by this project; a user
reported the mouse connecting with no lighting card, which is what added the
lighting. **The lighting has not been tried on hardware yet.** It follows
openrazer's extended-matrix family for these two ids, every command on
transaction id `0x1f`, addressed to one led at a time:

| Zone | Led | Notes |
| --- | --- | --- |
| Mouse | `0x00` (`ZERO_LED`) | every LED at once; the only way to reach the underglow strip |
| Scroll wheel | `0x01` | |
| Logo | `0x04` | |

| Write | Class / ID | Notes |
| --- | --- | --- |
| Off / Spectrum / Wave / Static | `0x0f` / `0x02` | `[storage, led, effect, ...]`; wave direction `0x01`, speed `0x28` |
| Brightness | `0x0f` / `0x04` | `[storage, led, level]`, level on a 0-255 scale |

| Read | Class / ID | Notes |
| --- | --- | --- |
| Brightness | `0x0f` / `0x84` | level in the third byte, read per led on every refresh |

openrazer creates wave, spectrum, static and brightness for these models and
no "none"; Off is the same family's effect `0x00`, so it is offered and is
the first thing to drop if it fails. Reactive and breathing exist in the family
but openrazer does not expose them here, so they are not offered.

To test, with Synapse quit:

1. Open the Lighting tab. Three zones should show, each with the brightness
it read; note the three levels.
2. On the Mouse zone pick Spectrum, Wave, Static (change the colour) and Off,
and watch the whole mouse including the underglow strip.
3. Repeat on Scroll wheel and Logo, and confirm only that zone changes.
4. Change one zone's brightness, reload, and confirm the new level reads back.
5. Unplug and replug the mouse and note whether the effects and brightness
survived.
6. Report any effect that errors or leaves the LEDs unchanged.
22 changes: 21 additions & 1 deletion src/drivers/razer/devices.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const VERIFIED_SINCE: ReadonlyArray<[number, VerifiedProfile]> = [
// Same mouse over the cable, same session: 13/13 writes persisted, 126 Hz
// peak measured at 125, battery reports "Charging".
[0x00b6, { model: "DeathAdder V3 Pro (Wired)", wireless: false, maxDpi: 30000, transactionId: RAZER_TRANSACTION_ID, rates: RATES_1K, highRate: false }],
// Diamondback Chroma (firmware 1.0) over the cable through OpenMouse Bridge:
// answers on `0xff`, and DPI and legacy polling each round-tripped.
[0x004c, { model: "Diamondback Chroma", wireless: false, maxDpi: 16000, transactionId: RAZER_TRANSACTION_ID_FF, rates: RATES_1K, highRate: false }],
];

const VERIFIED = [...REFACTOR_BASELINE, ...VERIFIED_SINCE];
Expand All @@ -77,7 +80,7 @@ const VERIFIED = [...REFACTOR_BASELINE, ...VERIFIED_SINCE];
* hardware-tested", so it is pinned like the others without claiming to be
* verified.
*/
const HARDWARE_VERIFIED: readonly number[] = [0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00c0, 0x00c1, 0x00b8, 0x00b7, 0x00b6];
const HARDWARE_VERIFIED: readonly number[] = [0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00c0, 0x00c1, 0x00b8, 0x00b7, 0x00b6, 0x004c];

test("every pinned product keeps exactly the profile it was given", () => {
// A silent change to any of these would only show up on hardware, which is
Expand Down Expand Up @@ -269,6 +272,23 @@ test("button mapping is only offered on connections where class 0x02 answered",
}
});

test("extended-matrix lighting is offered on the Basilisk V3 pair OpenRazer drives that way", () => {
// Untested on hardware: a reporter with the mouse connected and asked for
// the lighting, which is the only way an effect write without a read-back
// ever gets checked. Each id here needs its owner to watch the LEDs.
const offered = RAZER_PRODUCT_IDS.filter((id) => RAZER_PRODUCTS.get(id)?.extendedMatrixLighting === true);
assert.deepEqual(offered, [0x0099, 0x00cb]);
for (const id of offered) assert.notEqual(RAZER_PRODUCTS.get(id)?.standardMatrixLighting, true);
});

test("standard-matrix lighting is only offered on a model someone is testing it on", () => {
// Effect writes have no read-back, so a mouse that ignores them looks the
// same as one that obeys. Every entry needs its owner to watch the LEDs.
const offered = RAZER_PRODUCT_IDS.filter((id) => RAZER_PRODUCTS.get(id)?.standardMatrixLighting === true);
assert.deepEqual(offered, [0x004c]);
for (const id of offered) assert.equal(RAZER_PRODUCTS.get(id)?.verified, true);
});

test("no product is claimed by both this registry and a dedicated Razer driver", () => {
// `driverFor` returns the first match in DEVICE_DRIVERS, so an overlap would
// silently kill whichever driver is registered later.
Expand Down
Loading
Loading