Receivers
无线 Logitech 设备配对所用的 USB 接收器,通过 HID++ 1.0 寄存器驱动,以 USB 厂商/产品 ID 识别。
A receiver is the USB dongle that wireless Logitech devices pair to. OpenLogi detects the receiver on its USB/HID channel, then enumerates the devices paired to it.
Unlike device features (which use HID++ 2.0), receivers are driven through
HID++ 1.0 registers and are always addressed at device index 0xFF
(RECEIVER_DEVICE_INDEX). They are identified purely by their USB vendor/product
ID — openlogi-hidpp's receiver::detect() matches the channel's VID/PID
against the known sets and returns a Receiver.
Implementation status
Receiver support in the vendored hidpp crate is deliberately conservative —
public documentation is scarce. Logi Bolt is the most complete (developed and
tested against real hardware); Unifying covers discovery and enumeration but
its pairing/management surface is thinner and welcomes hardware testing.
Detection
| Receiver | VID:PID | Transport |
|---|---|---|
| Logi Bolt | 046D:C548 | HID++ 1.0 registers (BLE-based) |
| Unifying | 046D:C52B, 046D:C532, 046D:C539 | HID++ 1.0 registers (Unifying / DJ) |
| Lightspeed | 046D:C53F, 046D:C547 | Unifying registers, G-series dongles |
receiver::detect(chan) returns Some(Receiver) for a known dongle, or None
otherwise.
The Lightspeed dongles bundled with G-series devices answer the same HID++
1.0 registers as Unifying, so they are detected, enumerated, routed, and paired
through the Unifying code path — only the user-facing name differs
(Lightspeed Receiver). C53F is the nano receiver of wireless mice such as the
G305, verified against a G305 (paired device wpid 0x4074); C547 ships with
newer devices such as the G915 keyboard and the G502 X LIGHTSPEED, verified
against a G915 (wpid 0x407c). C539 is the Lightspeed gaming receiver, listed
with the Unifying PIDs because it is routed as one.
Common API
The Receiver enum wraps the concrete receiver kinds and exposes the shared
surface:
| Item | Description |
|---|---|
Receiver::Bolt(_) / Receiver::Unifying(_) | The detected receiver kind. |
name() | Human-readable name (e.g. "Logi Bolt Receiver"). |
get_unique_id() | A string that uniquely identifies this receiver (serial or equivalent). |
RECEIVER_DEVICE_INDEX (0xFF) | The device index used to address the receiver on the channel. |
Errors surface as ReceiverError — UnknownReceiver, or a wrapped HID++ 1.0
Protocol error.
Logi Bolt
The current Logitech receiver. Bolt is BLE-based, pairs up to 6 devices,
and authenticates new devices with a passkey before pairing. bolt::Receiver
exposes:
| Function | Purpose |
|---|---|
count_pairings() | Number of currently paired devices (offline ones included). |
collect_paired_devices() | Enumerate all paired devices (Vec<DeviceConnection>). |
get_device_pairing_information(index) | Pairing info for one slot (DevicePairingInformation). |
get_device_codename(index) | The device's codename / name. |
get_notification_state() / set_notification_state(..) | Read / enable receiver notifications. |
trigger_device_arrival() | Re-fire DeviceConnection events for all paired devices (enumeration). |
discover_devices(timeout) / cancel_device_discovery() | Start / stop discovery of pairable devices (≤ 60 s). |
pair_device(slot, address, authentication, entropy) | Begin pairing a discovered device. |
unpair_device(index) | Remove a pairing. |
listen() | Subscribe to receiver Events. |
Pairing flow
discover_devices(Some(secs))— the receiver emitsEvent::DeviceDiscoveryDeviceDetails(carrying the deviceaddress,kind,wpid,authentication) andEvent::DeviceDiscoveryDeviceNamefor each nearby device.pair_device(slot, address, authentication, entropy)—entropysets passkey complexity (for mice, the number of left/right clicks the user must enter).- The receiver completes pairing and emits
Event::DeviceConnection.
Events (bolt::Event)
| Variant | When |
|---|---|
DeviceConnection(DeviceConnection) | A device connects / disconnects (requires wireless notifications enabled). |
DeviceDiscoveryStatus { discovery_enabled } | Discovery mode toggles. |
DeviceDiscoveryDeviceDetails { counter, kind, wpid, address, authentication } | A device is discovered (details + address required to pair). |
DeviceDiscoveryDeviceName { .. } | The discovered device's name. |
DeviceKind covers Keyboard, Mouse, Numpad, Presenter, Remote,
Trackball, Touchpad, Tablet, Gamepad, Joystick, Headset (plus
Unknown).
Unifying
The previous-generation receiver. Unifying pairs up to 6 devices over the
proprietary Unifying / DJ protocol; once addressed by their slot index, paired
devices speak HID++ 2.0. unifying::Receiver exposes:
| Function | Purpose |
|---|---|
count_pairings() | Number of paired devices (offline ones included). |
get_receiver_info() | Receiver info, including pairing_slots (ReceiverInfo). |
get_device_pairing_information(index) | Pairing info for one slot (DevicePairingInformation). |
trigger_device_arrival() | Re-fire connection events for online devices (startup enumeration). |
get_unique_id() | Receiver serial / unique id. |
listen() | Subscribe to receiver Events. |
Enumerating paired devices (Rust)
use std::sync::Arc;
use hidpp::{
channel::HidppChannel,
receiver::{self, Receiver},
};
// chan: Arc<HidppChannel> bound to the receiver's HID interface.
let Some(rx) = receiver::detect(Arc::clone(&chan)) else {
return; // not a known Logitech receiver
};
println!("{} — {}", rx.name(), rx.get_unique_id().await?);
match rx {
Receiver::Bolt(bolt) => {
for dev in bolt.collect_paired_devices().await? {
// dev: bolt::DeviceConnection — one paired device
let _ = dev;
}
}
Receiver::Unifying(uni) => {
let events = uni.listen();
uni.trigger_device_arrival().await?; // re-fires DeviceConnection events
while let Ok(event) = events.recv().await {
// handle unifying::Event::DeviceConnection { .. }
let _ = event;
break;
}
}
_ => {}
}No receiver
Bluetooth-direct and wired devices enumerate as their own inventory — no receiver involved. See Connect a device.