feat(device): add Sony INZONE H5 (WH-G500)#524
Conversation
Implements the Sony vendor HCI protocol over the 2.4 GHz USB dongle (VID 054C, PID 0EBF). Supports: - Battery (level + charging state) via BATTERY_INFO GET - Chatmix via GAME_CHAT_MIX_BALANCE GET (device 0..90 mapped to 0..128) - Sidetone via SIDETONE_VOLUME SET (0..128 mapped to device 0..50) - Mic volume via MIC_VOLUME SET (0..128 mapped to device 0..50) The control protocol lives on the Sony-vendor HID collection (usage page 0xFF04, report ID 0x02). Each report wraps an HCI packet: host issues COMMAND (opcode 0xFC00), device replies with EVENT (event code 0xFF). The exchange() helper builds the COMMAND, computes the checksum, validates the response shell, matches event_id + TID, and skips intervening NTFY_ACTIVE pushes from the dongle.
|
Code review — 2 issues found Issue 1 (Bug): Transaction counter wraps onto TID=1 (lines 228–231) HeadsetControl/lib/devices/sony_inzone_h5.hpp Lines 228 to 231 in bf9dcf1 After 65535 exchange() calls, transaction_counter_ wraps from 0xFFFF to 0, the guard fires, and the next pre-increment yields 1. The comment on line 230 explicitly states the dongle's own NTFY_ACTIVE uses TID=1 — yet the guard only skips 0 and lands on 1. The matching loop accepts ETYPE_NTFY_ACTIVE when both event_id and tid match, so an unsolicited NTFY_ACTIVE could be returned as the authoritative reply (stale battery data, etc.). Relevant matching logic: HeadsetControl/lib/devices/sony_inzone_h5.hpp Lines 257 to 265 in bf9dcf1 Suggested fix (replace lines 228–231): uint16_t tid = ++transaction_counter_;
if (tid <= 1) {
tid = transaction_counter_ = 2; // skip 0 (overflow) and 1 (dongle NTFY_ACTIVE TID)
}Issue 2 (CLAUDE.md): Sequential field assignment instead of designated initializers (lines 368–379) HeadsetControl/lib/devices/sony_inzone_h5.hpp Lines 368 to 379 in bf9dcf1 parseEvent() initializes ParsedEvent with sequential field assignment (ev.event_id = ..., ev.event_type = ...) instead of designated initializer syntax. CLAUDE.md rule: Designated initializers for struct initialization. ParsedEvent is a plain aggregate; the conditional payload is expressible with a ternary. Suggested fix (replace lines 368–379): return ParsedEvent {
.event_id = buf[9],
.event_type = buf[10],
.address = address,
.transaction_id = static_cast<uint16_t>(buf[11])
| static_cast<uint16_t>(buf[12]) << 8,
.payload = (hid_length > 12)
? std::vector<uint8_t>(buf.begin() + 13, buf.begin() + hid_length + 1)
: std::vector<uint8_t> {},
}; |
Note: this has been implemented using Claude. It works for me but I can not judge the code. Feel free to close this if you do not want to review AI code.
Changes made
Implements the Sony vendor HCI protocol over the 2.4 GHz USB dongle (VID 054C, PID 0EBF). Supports:
The control protocol lives on the Sony-vendor HID collection (usage page 0xFF04, report ID 0x02). Each report wraps an HCI packet: host issues COMMAND (opcode 0xFC00), device replies with EVENT (event code 0xFF). The exchange() helper builds the COMMAND, computes the checksum, validates the response shell, matches event_id + TID, and skips intervening NTFY_ACTIVE pushes from the dongle.
Checklist