Hi, I'm from the Udcap VR Gloves development team. While running regression tests for Udcap VR Gloves compatibility with SlimeVR, we found an issue in the desktop connect-trackers flow.
Steps to Reproduce
Case 1: Udcap VR Gloves receiver connected, no other program occupying the serial port
-
Plug in a Udcap VR Gloves receiver (CH340 chip, VID/PID = 0x1A86:0x7522) alongside a real SlimeVR tracker (also CH340)
-
Open the SlimeVR desktop app, click to Connect Trackers
Result: The flow gets stuck at "unable to get logs from tracker" (NO_SERIAL_LOGS_ERROR), and never automatically tries the next CH340 device
Case 2: Udcap Driver already running and occupying the receiver's serial port
-
Plug in a Udcap VR Gloves receiver
-
Start the Udcap Driver, pair the gloves (the receiver's serial port is now occupied)
-
Open the SlimeVR desktop app, click to Connect Trackers
Result: The flow gets stuck at "looking for tracker" — SlimeVR tries to open the already-occupied port, fails, and doesn't fall back to other ports
Root Cause
After reviewing the code, the issue traces to DesktopSerialHandler.openSerial() (DesktopSerialHandler.kt:96-100):
val newPort: SerialPort? = ports.find {
(auto && isKnownBoard(SerialPortWrapper(it)))
...
}
find {} returns only the first port matching isKnownBoard
isKnownBoard only checks a VID/PID whitelist (CH340 = 0x1A86:0x7522), so it cannot distinguish a real SlimeVR tracker from another CH340-based device
- When the first match is not a tracker (or its port is occupied), there is no fallback to try the next matching port
Additional Finding: Infinite Retry Loop When Port Is Occupied
The stuck-at-"looking for tracker" behavior in Case 2 is caused by a separate issue in ProvisioningHandler.java.
Both start() (line 53) and initSerial() (line 68) set provisioningStatus via direct field assignment instead of calling changeStatus():
// ProvisioningHandler.java:47-55
public void start(String ssid, String password, String port) {
this.provisioningStatus = ProvisioningStatus.NONE; // direct assignment
...
}
// ProvisioningHandler.java:67-68
public void initSerial(String port) {
this.provisioningStatus = ProvisioningStatus.SERIAL_INIT; // direct assignment
...
}
Because changeStatus() is the only method that updates lastStatusChange (line 222) and broadcasts status updates to GUI listeners, this causes two problems:
-
lastStatusChange is never updated from its initial value of -1
The timeout check in provisioningTick() (line 122) becomes a no-op guard:
System.currentTimeMillis() - (-1) > 3000 // always true
This causes initSerial() to be called every ~1 second in an infinite retry loop attempting to open the same occupied port.
-
The GUI never receives the SERIAL_INIT status update
The GUI defaults to NONE and shows "looking for tracker" indefinitely, while the server is actually stuck in a SERIAL_INIT → retry loop.
Furthermore, the NO_SERIAL_DEVICE_FOUND guard (lines 112-119) never triggers because:
vrServer.serialHandler.getKnownPorts().findAny().isEmpty()
returns false — the occupied CH340 device still appears in the OS port enumeration.
Suggestion
Are there plans for a fallback/retry mechanism so that when the first candidate device fails to connect or communicate, the system automatically tries the next isKnownBoard port? Or perhaps exposing port selection in the UI so users can manually choose the correct one when auto-selection picks the wrong device?
Addon
My English ability is limited, and all of the above content was translated with the aid of machine translation. If anything comes across as offensive or unclear, that is not my intention. I apologize.
Hi, I'm from the Udcap VR Gloves development team. While running regression tests for Udcap VR Gloves compatibility with SlimeVR, we found an issue in the desktop connect-trackers flow.
Steps to Reproduce
Case 1: Udcap VR Gloves receiver connected, no other program occupying the serial port
Plug in a Udcap VR Gloves receiver (CH340 chip, VID/PID = 0x1A86:0x7522) alongside a real SlimeVR tracker (also CH340)
Open the SlimeVR desktop app, click to Connect Trackers
Result: The flow gets stuck at "unable to get logs from tracker" (NO_SERIAL_LOGS_ERROR), and never automatically tries the next CH340 device
Case 2: Udcap Driver already running and occupying the receiver's serial port
Plug in a Udcap VR Gloves receiver
Start the Udcap Driver, pair the gloves (the receiver's serial port is now occupied)
Open the SlimeVR desktop app, click to Connect Trackers
Result: The flow gets stuck at "looking for tracker" — SlimeVR tries to open the already-occupied port, fails, and doesn't fall back to other ports
Root Cause
After reviewing the code, the issue traces to
DesktopSerialHandler.openSerial()(DesktopSerialHandler.kt:96-100):find {}returns only the first port matchingisKnownBoardisKnownBoardonly checks a VID/PID whitelist (CH340 =0x1A86:0x7522), so it cannot distinguish a real SlimeVR tracker from another CH340-based deviceAdditional Finding: Infinite Retry Loop When Port Is Occupied
The stuck-at-"looking for tracker" behavior in Case 2 is caused by a separate issue in
ProvisioningHandler.java.Both
start()(line 53) andinitSerial()(line 68) setprovisioningStatusvia direct field assignment instead of callingchangeStatus():Because
changeStatus()is the only method that updateslastStatusChange(line 222) and broadcasts status updates to GUI listeners, this causes two problems:lastStatusChangeis never updated from its initial value of-1The timeout check in
provisioningTick()(line 122) becomes a no-op guard:This causes
initSerial()to be called every ~1 second in an infinite retry loop attempting to open the same occupied port.The GUI never receives the
SERIAL_INITstatus updateThe GUI defaults to
NONEand shows "looking for tracker" indefinitely, while the server is actually stuck in aSERIAL_INIT→ retry loop.Furthermore, the
NO_SERIAL_DEVICE_FOUNDguard (lines 112-119) never triggers because:returns
false— the occupied CH340 device still appears in the OS port enumeration.Suggestion
Are there plans for a fallback/retry mechanism so that when the first candidate device fails to connect or communicate, the system automatically tries the next
isKnownBoardport? Or perhaps exposing port selection in the UI so users can manually choose the correct one when auto-selection picks the wrong device?Addon
My English ability is limited, and all of the above content was translated with the aid of machine translation. If anything comes across as offensive or unclear, that is not my intention. I apologize.