DGM20 control for Linux: protocol library, CLI and local web UI

Reverse-engineered from Maono Link 4.0.88 (DGM20_OLD.dll) and verified
against a DGM20 (352f:0105, firmware 2.1.2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 22:45:59 -05:00
co-authored by Claude Opus 5.5
commit d239c214b4
14 changed files with 1097 additions and 0 deletions
+74
View File
@@ -0,0 +1,74 @@
# 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 | RGB ring brightness | 0-100 (the app does not show it for this model) |
| 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.