Files
dgm20-linux/PROTOCOL.md
T
justinandClaude Opus 5.5 1fcf73ed9d Drop the brightness control, survive and explain a frozen mic
- Remove RGB brightness: firmware 2.1.2 stores the value but the LEDs
  never change, so the control did nothing. PROTOCOL.md notes why.
- Lock the device per transaction (flock) so the CLI and the web
  service can't interleave and steal each other's replies.
- Detect a mic that is plugged in but no longer answering and tell the
  user to replug it (a USB reset is not enough; settings survive).
  Seen when hardware buttons are held while settings are being written.
- Web page keeps the last known value when a poll comes back partial,
  instead of drawing unanswered settings as off.
- New screenshot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:45:18 -05:00

75 lines
3.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DGM20 control protocol
These notes come from Maono Link 4.0.88 for Windows. The app loads a per-model plugin, and the
plugin for USB `352f:0105` is `DGM20_OLD.dll`. Every value below was checked against a real mic
(firmware 2.1.2) unless it is marked otherwise.
## Transport
The mic has USB audio interfaces 0-2 and a HID interface 3. Interface 3 carries a vendor usage page
(`0xFF01`) with four reports:
| report | direction | size |
|--------|-----------|------|
| 0x50 | out | 15 |
| 0x51 | out | 63 |
| 0x10 | in | 15 |
| 0x11 | in | 63 |
The app uses only 0x51 (requests) and 0x11 (replies). On Linux the interface is a hidraw node: a
65-byte `write()` (the report id plus 64 data bytes) sends a request, and `read()` returns replies.
## Packet
```
offset size field
0 1 report id: 0x51 request, 0x11 reply
1 1 0xC4
2 1 length of bytes 1..end, including the checksum
3 2 0x0000
5 1 type
6 n payload, u16 little-endian words
6+n 2 checksum, u16 LE = -(sum of bytes 1 .. 5+n)
```
The rest of the 64 bytes is zero-padded.
| type | request payload | reply |
|------|-----------------|-------|
| 2 | (reply only) | write ack: `status` (0 = ok) |
| 3 | `addr, value` pairs | type-2 ack. The mic also sends type-3 packets on its own when a setting changes on the hardware, such as the touch pad. |
| 4 | `addr` | `addr, value` |
| 5 | `addr, count, data...` | bulk write. The app uses it only to write the serial number; don't. |
| 6 | `addr, count` | `addr, count, values...` (range read) |
## Registers
| reg | meaning | values |
|--------|---------|--------|
| 0x0003 | model name, 8 words, ASCII | `"DGM20"` |
| 0x000B | firmware version, 3 words | `2, 1, 2` |
| 0x001E | serial number, up to 20 words | |
| 0x1008 | DFU mode (read) | 0 = normal |
| 0x100A | factory reset | write 1 |
| 0x2022 | mute | 0 / 1 |
| 0x2026 | headphone monitoring | 2000 = on, 3000 = off |
| 0x2027 | noise cancellation | 0 / 1 |
| 0x2028 | noise cancellation strength | 0-100 |
| 0x202A | labelled RGB ring brightness in the app's shared code | stores 0-100, but the LEDs do not change on firmware 2.1.2; not exposed |
| 0x202C | vocal enhancement | 0 / 1 |
| 0x204B | level-meter enable | not answered by firmware 2.1.2 |
Maono Link reads settings once, in this order: 0x204B, then 0x2022, then a range read of 0x2027
(count 2), then 0x2026, then 0x202C. After that it relies on type-3 packets the mic sends on its
own.
## Present in the plugin but not used for this model
The DLL shares widgets with the PD200X plugin, so it contains EQ and RGB-colour code. That code
is never instantiated for the DGM20, and the mic does not answer reads of these registers. They
are listed here for anyone exploring.
- **EQ:** 5 parametric bands, each 5 words, starting at 0x204D + 5·i. The HPF is at 0x2066 and the
LPF at 0x206B. Each band is `[enable, type, freq Hz, gain dB×10+2000, Q×100]`.
- **Light on/off:** 0x2036. **Colour index:** 0x2038.