Skip to content

Uhk60 c2usb integration#1482

Open
benedekkupper wants to merge 39 commits intomasterfrom
uhk60-c2usb-integration
Open

Uhk60 c2usb integration#1482
benedekkupper wants to merge 39 commits intomasterfrom
uhk60-c2usb-integration

Conversation

@benedekkupper
Copy link
Copy Markdown
Contributor

@benedekkupper benedekkupper commented Feb 7, 2026

major refactoring of UHK60 right USB interface

  • start using Kconfig for device configuration values (see right/Kconfig.device)
  • use generated usb_device_config.h header
  • organize HID report manipulation into self-contained sources and headers
  • remove kusb interfacing code, except for buspal
  • update c2usb dependency handling
  • merge zephyr c2usb interface with UHK60
  • use single report for system and media usages
  • remove unused gamepad interface

This PR is work in progress, the following tasks are still ahead:

@mondalaci
Copy link
Copy Markdown
Member

@benedekkupper Please let me know when I should test a CI build.

@benedekkupper benedekkupper force-pushed the uhk60-c2usb-integration branch 5 times, most recently from c094435 to f2f5ac6 Compare February 8, 2026 22:12
Copy link
Copy Markdown
Collaborator

@kareltucek kareltucek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for initial review: looks great. Thanks for all those refactors - they are spot on. I didn't expect you to go this deep into our side of code.

Are there any areas that should I focus on specifically with review?

I mean, are there any notable changes in logic, or potentially controversial areas? (I have tried to read through all the changes, but it is easy to miss things among minor changes, mass renames, etc....)


static void addBasicScancode(uint8_t scancode, macro_usb_keyboard_reports_t* reports)
{
if (!scancode) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if it is safe to remove these...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is safe to remove them, because the call chain checks for zero values too. It does mean that zero values are processed longer, so if you want to speed up the error handling, I can restore these checks.

EventVector_KeyboardLedState = 1 << 10,
EventVector_UsbMacroCommandWaitingForExecution = 1 << 11,
EventVector_ProtocolChanged = 1 << 12,
// EventVector_ProtocolChanged = 1 << 12, // unused
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the protocol change (nkro vs 6kro) now handled?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although, I think it is correct that the usb_report_udpater logic shouldn't be needed these days, as everything is stored in nkro format, so indeed this should be a no issue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the UHK60 handles this internally, just like the UHK80 already does.

@kareltucek
Copy link
Copy Markdown
Collaborator

create zephyr RTOS design for throttling report sending in usb_report_updater

What exactly do you have in mind?

What comes to mind given this prompt:

  • It is fine if the send function blocks for the next couple transport windows. Considering hogp, this means it is fine if you block the main thread for 20ms or so. If you need longer, an error should be returned to trigger resending.
  • If you give us a function which tells us whether c2usb is readyForNextReport, we can use it and wait with report calculation. With current implementation, this would mean that we poll you once every millisecond. As for alternatives:
    • If you also tell us for how long to sleep, we can use that information in sleep calculation.
    • Proper solution would be to wait via a semaphore until we receive a callback, but I don't think this is worth the code complexity.
    • (The simplest polling solution is preferred.)

Whether and how the reports should be queued - I assume a queue of length 1 - the switching of active and "inactive" report buffers:

  • In case of usb transport, I think it makes sense for one report to be waiting in the usb stack for transport while another is already being constructed. I.e., "ready" function should return true once there is a free spot in the queue.
  • In hogp case, due to high latency, optimal would be to calculate the time when a report should be constructed with respect to the next transport window. The simple version would be to calculate next report once the previous report has been sent. In any case, this can be encapsulated in the suggested "readyForNextReport" function.

Assume it takes 1ms to construct a report. (Well, I should make some statistics of this.)

@kareltucek
Copy link
Copy Markdown
Collaborator

verification of UHK60 functionality @kareltucek @mondalaci

UHK60 crashes somewhere in initUsb.

What is the state of testing on your end @benedekkupper . Can you efficiently test and debug with actual UHK60 hardware, or is that up to me?

@kareltucek
Copy link
Copy Markdown
Collaborator

I have pushed a minor PID fix of west_agent.py.

//return;
}
std::copy(buffer.begin(), buffer.end(), in_buffer_.data() + sizeof(in_id_));
auto result = send_report(in_buffer_);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you been dropping all errors here all along?

@benedekkupper
Copy link
Copy Markdown
Contributor Author

Are there any areas that should I focus on specifically with review?

I mean, are there any notable changes in logic, or potentially controversial areas? (I have tried to read through all the changes, but it is easy to miss things among minor changes, mass renames, etc....)

The key areas are the usb_report_updater.c (as always) and hid/transport.cpp, I'm not entirely confident about the changes affecting the keyboard LED states, and the UsbReportUpdateSemaphore, so please take a closer look at those.

create zephyr RTOS design for throttling report sending in usb_report_updater

What exactly do you have in mind?

What comes to mind given this prompt:

* It is fine if the send function blocks for the next couple transport windows. Considering hogp, this means it is fine if you block the main thread for 20ms or so. If you need longer, an error should be returned to trigger resending.

* If you give us a function which tells us whether c2usb is `readyForNextReport`, we can use it and wait with report calculation. With current implementation, this would mean that we poll you once every millisecond. As for alternatives:
  
  * If you also tell us for how long to sleep, we can use that information in sleep calculation.
  * Proper solution would be to wait via a semaphore until we receive a callback, but I don't think this is worth the code complexity.
  * (The simplest polling solution is preferred.)

Now it will return -EBUSY when the previous report wasn't sent out yet. Hid_KeyboardReportSentCallback and co. with HID_TRANSPORT_BLE will be called when the report was sent (that's your readyForNextReport), so you can pick up from there.

Whether and how the reports should be queued - I assume a queue of length 1 - the switching of active and "inactive" report buffers:

* In case of usb transport, I think it makes sense for one report to be waiting in the usb stack for transport while another is already being constructed. I.e., "ready" function should return true once there is a free spot in the queue.

This is doable, but it needs to split handling USB and BLE report sending, so I'd do it in another round.

* In hogp case, due to high latency, optimal would be to calculate the time when a report should be constructed with respect to the next transport window. The simple version would be to calculate next report once the previous report has been sent. In any case, this can be encapsulated in the suggested "readyForNextReport" function.

Assume it takes 1ms to construct a report. (Well, I should make some statistics of this.)

Don't design too much around this high latency, there is a new BLE spec version already supported by nRF Connect SDK, that can drastically reduce this (LE Shorter Connection Intervals)

UHK60 crashes somewhere in initUsb.

What is the state of testing on your end @benedekkupper . Can you efficiently test and debug with actual UHK60 hardware, or is that up to me?

I have debugged the firmware a bit, but not in a production environment, I flashed the firmware without bootloader present. The keys and mouse movement is working in general, I didn't test further so far due to the limited time availability. Do you have a JTAG/SWD debugger attached, or you use some kind of log and trace functionality? Did yo flash the CI build that crashed, or your local build? Make sure you run the usual west command sequence before build: west config manifest.file west_mcuxsdk.yml && west update && west patch

@kareltucek
Copy link
Copy Markdown
Collaborator

Do you have a JTAG/SWD debugger attached, or you use some kind of log and trace functionality?

I tried to attach to a gdb via an swd, but failed. Can look into it deeper on monday I think.

It was a local build.

@kareltucek
Copy link
Copy Markdown
Collaborator

As for those crashes:

  • when deploying from vscode without bootloader, everything works fine for both release and debug builds.
  • when I flash the regular way - via bootloader and connect to vscode gdb and let the code continue, I get a crash (again with both (export) DEBUG=0 and DEBUG=1 firmwares):
bt
#0  HardFault_Handler () at /opt/west2/firmware/right/src/trace_reasons.c:123
#1  <signal handler called>
#2  0x00034452 in usb::df::function::deinit(usb::df::config::interface const&) ()
#3  0x000323e8 in usb::df::device::set_config(usb::df::config::view, usb::df::device::event) ()
#4  0x2000ee40 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

info registers
r0             0x880bd301          2282476289
r1             0x780               1920
r2             0x787               1927
r3             0x880bd301          2282476289
r4             0x15881             88193
r5             0x1                 1
r6             0x0                 0
r7             0x2000ee00          536931840
r8             0x0                 0
r9             0x1fff1c60          536812640
r10            0x1                 1
r11            0x0                 0
r12            0x0                 0
sp             0x2000ede0          0x2000ede0
lr             0xfffffff1          -15
pc             0x2b7d8             0x2b7d8 <HardFault_Handler>
xpsr           0x10f0003           17760259
fpscr          0x60000010          1610612752
msp            0x2000ede0          0x2000ede0
psp            0x0                 0x0
primask        0x0                 0
basepri        0x0                 0
faultmask      0x0                 0
control        0x0                 0
apsr           0xf0000             983040
epsr           0x1000000           16777216
ipsr           0x3                 3
iapsr          0xf0003             983043
eapsr          0x10f0000           17760256
iepsr          0x1000003           16777219

x/x 0xE000ED28
0xe000ed28:	0x00008200
x/x 0xE000ED2C
0xe000ed2c:	0x40000000
x/x 0xE000ED34
0xe000ed34:	0x880bd301
x/x 0xE000ED38
0xe000ed38:	0x880bd301

@kareltucek
Copy link
Copy Markdown
Collaborator

create zephyr RTOS design for throttling report sending in usb_report_updater

Is there any specific concern regarding this? It seems to me that the UsbReportUpdateSemaphore takes care of things quite optimally for now, and so can be checked off.


I went through the usb_report_updater and hid/transport.cpp, and I don't see any obvious issues.

I am running this firmware on uhk80 and it works like a charm so far.

@kareltucek
Copy link
Copy Markdown
Collaborator

I have lost the ability to flash uhk80 via Agent with this PR.

@benedekkupper
Copy link
Copy Markdown
Contributor Author

I have lost the ability to flash uhk80 via Agent with this PR.

What error message are you getting?

@benedekkupper benedekkupper force-pushed the uhk60-c2usb-integration branch 2 times, most recently from 037c4a4 to a074135 Compare February 21, 2026 10:12
@kareltucek
Copy link
Copy Markdown
Collaborator

It wasn't able to find the bootloader.

@kareltucek
Copy link
Copy Markdown
Collaborator

(I mean the Agent.)

@benedekkupper
Copy link
Copy Markdown
Contributor Author

Is the USB HID index of the agent command interface still hardcoded in the agent?

@kareltucek
Copy link
Copy Markdown
Collaborator

No iirc, but I have no hard data for it.

@benedekkupper
Copy link
Copy Markdown
Contributor Author

@kareltucek I can reproduce the crash, but I'm unable to debug it, as the crash only happens when the bootloader starts the application, and not the debugger. Can you provide some further information about the crash site? Maybe a wireshark capture of the USB communication up to the point of the crash?

@benedekkupper
Copy link
Copy Markdown
Contributor Author

@kareltucek @mondalaci @pcooke9 can you sum up the list of regressions on your side in this PR compared to master?

@kareltucek
Copy link
Copy Markdown
Collaborator

I am now aware only of this, but given that only dongle is affected, I suspect that it is not a c2usb issue:

#1406 remains present via dongle when powering the PC back on with Windows Fast Startup enabled. (I'm still unable to reproduce it when resuming from hibernation or S3 states.)

I am a bit apprehensive about the hogp freezes that I reported above, as I am not aware of any related fixes, but it looks like Phil is not affected, and the last time I tested, I didn't run into it.

@pcooke9
Copy link
Copy Markdown

pcooke9 commented Apr 4, 2026

#1406 remains present via dongle when powering the PC back on with Windows Fast Startup enabled.

This appears to be the only issue I'm aware of now.

@pcooke9
Copy link
Copy Markdown

pcooke9 commented Apr 4, 2026

I am a bit apprehensive about the hogp freezes that I reported above, as I am not aware of any related fixes, but it looks like Phil is not affected, and the last time I tested, I didn't run into it.

I don't recall any freezes here. Was it a hard freeze, requiring a reboot/reset?

Can you give more details to help me try to reproduce it? Did you also have a dongle, USB, or more than one BLE device connected when it froze?

@kareltucek
Copy link
Copy Markdown
Collaborator

kareltucek commented Apr 7, 2026

I don't recall any freezes here. Was it a hard freeze, requiring a reboot/reset?

Actually, after some time (10 or so seconds) the board would usually have crashed, so I don't recall having to hard reset it often. But yes, it would require power-cycle.

The freeze kicked in right after a hogp host connected. (Either right after pairing, or right after connection if it was already paired.)

Did you also have a dongle, USB, or more than one BLE device connected when it froze?

Argh. I didn't write that down. 🙈

@kareltucek
Copy link
Copy Markdown
Collaborator

kareltucek commented Apr 7, 2026

@benedekkupper do you have some idea on how to make the error numbers traceable? On uhk-code level, they are anonymous integers that lead into hid::result which is practically ungreppable, but after some digging leads into c2usb.hpp, where resides a clearly incomplete "enum" that however contains no numbers - just more defines, this time without a clear trace as to where they go.

One hypothesis is that they might be standard errno.h numbers. But as a reader of the code, how should I know that?


Once a host is successfully paired, things seem to work reliably.

However, often after a "successful" pairing, the device ends up in a non-functional state, returning some of -16, -104 and -128 error codes.

The only solution is to forget the connection on the device and repair again :-(. Just disconnecting such connection after we detect the problem doesn't seem to suffice.

This seems like a regression to me. Not sure about its source.

One such failed attempt (android device):

<wrn> Bt: Pairing completed: n/a (n/a, d4:5e:89:65:a3:f8), bonded 1
--- Pairing ended, success = 1: Successfuly bonded! ---
<inf> Bt: BtManager: Scheduling scan/adv in 100ms. (BtPair_EndPairing)
<inf> Bt: Pairing complete, passing connection 7 to authenticatedConnection handler. Selected conn is 7
<inf> Conn: Host: 6(Unregistered Ble, Connected), Peer host2, Selected
<inf> Bt: Established HID connection with host2 (Unregistered Ble, d4:5e:89:65:a3:f8)
<inf> Conn: Host: 6(Unregistered Ble, Ready), Peer host2, Selected
<inf> Conn: Host: 6(Unregistered Ble, Ready), Peer host2, Active
<inf> Bt: BtManager: Scheduling scan/adv in 100ms. (connectHid)
<inf> Notify: Notification: Pairing succeeded!
<inf> Bt: BtManager: Scheduling scan/adv in 100ms. (pairing_complete)
<inf> Bt: BtManager: Start 'advertising' (0).
<inf> Bt: Adv: 'NUS' started
Send failed: -104
Send failed: -104
Send failed: -104
Send failed: -104
Send failed: -104
Send failed: -104
Send failed: -104
Send failed: -104
Send failed: -104
Send failed: -104
Send failed: -104
Send failed: -104
Send failed: -104
Send failed: -104
Probable jump detected at site UhkModuleDriver2! -193, -47
Probable jump detected at site UhkModuleDriver2! -193, -47
Probable jump detected at site UhkModuleDriver2! -193, -47
Probable jump detected at site UhkModuleDriver2! -193, -47
Probable jump detected at site UhkModuleDriver2! -196, -47
Probable jump detected at site UhkModuleDriver2! -198, -46
Send failed: -104
Probable jump detected at site MouseController1! -198, -46
Probable jump detected at site MouseController2! -198, -46
Send failed: -128
Send failed: -104
Send failed: -104
Send failed: -128
<inf> hogp: starting HID app REPORT: 1
<wrn> bt_gatt: Device is not subscribed to characteristic
<wrn> bt_gatt: Device is not subscribed to characteristic
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16
Send failed: -16

Steps to reproduce:

  • Pair android phone.
  • Start mousing immediately.
  • Observe no cursor movement, just a long stream of errors.
  • If it works fine, then:
  • Long press the corresponding device slot switch action to clear the bonds, start over.

@kareltucek kareltucek force-pushed the uhk60-c2usb-integration branch from b66442e to 66431d5 Compare April 7, 2026 16:18
On Windows after pairing and left connected with cable, the device shows as
"UHK 80 Right NUS", which is confusing for the user.
@benedekkupper
Copy link
Copy Markdown
Contributor Author

benedekkupper commented Apr 7, 2026

@benedekkupper do you have some idea on how to make the error numbers traceable? On uhk-code level, they are anonymous integers that lead into hid::result which is practically ungreppable, but after some digging leads into c2usb.hpp, where resides a clearly incomplete "enum" that however contains no numbers - just more defines, this time without a clear trace as to where they go.

The c2usb error type is just an alias to the C++ standard std::errc, which itself is an alias to POSIX error codes. (With the notable difference that c2usb::result includes the negation in the type, unlike the others.) It would be futile to try to map the different error codes that can occur through zephyr's USB and BLE APIs to a different type...

Once a host is successfully paired, things seem to work reliably.

Before I was testing with the right half only, not knowing that it doesn't advertise anymore if it doesn't have a connection to the left side yet. Now I could connect over BLE to Windows 11 PC, and haven't found any issues. I will test other OSes on Friday.

This seems like a regression to me. Not sure about its source.

On my side there hasn't been any noteworthy changes to BLE, other than the report sending, which now doesn't block but returns an error instead.

@pcooke9
Copy link
Copy Markdown

pcooke9 commented Apr 8, 2026

Regarding hogp freezes; I tested with both v16.2.0-2ff017c and 16.2.1-acebaf1, but the UHK80 never froze or crashed. I tried to reproduce it for at least thirty minutes or so.🤷🏻‍♂️

The following is the only unresponsive mouse output that I observed in this testing (only happens occasionally):

16.2.1-acebaf1
Bridge cable and USB-both halves to PC
Android phone BLE

After pairing phone, the mouse cursor will temporarily be visible on the phone, but unresponsive. Mouse keys and touchpad output don't work, but other keystrokes and functions are fine. Switching host to USB works as normal, but mouse output remains unresponsive when switching back to phone.

Rebooting the UHK80 resolves it.

UART adapter output:

<wrn> Bt: Pairing completed: n/a (n/a, 94:e1:29:c9:80:67), bonded 1
--- Pairing ended, success = 1: Successfuly bonded! ---
<inf> Bt: BtManager: Scheduling scan/adv in 100ms. (BtPair_EndPairing)
<inf> Bt: Pairing complete, passing connection 6 to authenticatedConnection handler. Selected conn is 6
<inf> Conn: Host: 5(Unregistered Ble, Connected), Peer host1, Selected
<inf> Bt: Established HID connection with host1 (Unregistered Ble, 94:e1:29:c9:80:67)
<inf> Conn: Host: 5(Unregistered Ble, Ready), Peer host1, Selected
<inf> Conn: Host: 5(Unregistered Ble, Ready), Peer host1, Active
<inf> Bt: BtManager: Scheduling scan/adv in 100ms. (connectHid)
<inf> Notify: Notification: Pairing succeeded!
<inf> Bt: BtManager: Scheduling scan/adv in 100ms. (pairing_complete)
<inf> Bt: BtManager: Start 'advertising' (0).
<inf> Bt: Adv: 'NUS' started
<wrn> UsbReports: Send failed: Connection reset by peer

<wrn> UsbReports: Send failed: Connection reset by peer

<wrn> UsbReports: Send failed: Connection reset by peer

<wrn> UsbReports: Send failed: Connection reset by peer

<wrn> UsbReports: Send failed: Connection reset by peer

<wrn> UsbReports: Send failed: Connection reset by peer

<wrn> UsbReports: Send failed: Connection reset by peer

<wrn> UsbReports: Send failed: Connection reset by peer

<wrn> UsbReports: Send failed: Connection reset by peer

<wrn> UsbReports: Send failed: Connection reset by peer

<inf> hogp: starting HID app REPORT: 1
<wrn> bt_gatt: Device is not subscribed to characteristic
<wrn> UsbReports: Send failed: Device or resource busy

<wrn> UsbReports: Send failed: Device or resource busy

<wrn> UsbReports: Send failed: Device or resource busy

<wrn> UsbReports: Send failed: Device or resource busy

<wrn> UsbReports: Send failed: Device or resource busy

<wrn> UsbReports: Send failed: Device or resource busy

<wrn> UsbReports: Send failed: Device or resource busy

<wrn> UsbReports: Send failed: Device or resource busy

<wrn> UsbReports: Send failed: Device or resource busy

<wrn> UsbReports: Send failed: Device or resource busy

<wrn> UsbReports: Send failed: Device or resource busy

<inf> Bt: Kicking HID connections to check if HOGP is healthy.
HOGP HealthCheck: OK (registered, peer connected, interval 9)
<inf> Bt: BtConn_KickHid: the connection looks fine.

<wrn> UsbReports: Send failed: Device or resource busy

<wrn> UsbReports: Send failed: Device or resource busy

<wrn> UsbReports: Send failed: Device or resource busy

Even more rare, but similar variation to the above; sometimes the OLED shows the phone (BLE) as the active host, but output is going to the USB host instead. (lost UART output for this one, sorry)

@pcooke9
Copy link
Copy Markdown

pcooke9 commented Apr 8, 2026

In case I'm missing something; is simply having set devMode true in $onInit enough, or do I need to do anything else to get better logs?

@kareltucek
Copy link
Copy Markdown
Collaborator

Not at the moment.

It is possible to tweak log levels using log status and log enable {dbg|inf|wrn|err} {logChannel} in the zephyr console (or the same with zephyr prefix in macro), but I don't know what to look for in any of the increased log levels. In practice, I am seeing exactly just as little as you do.

Anyways, this is one variation of what I am seeing - one of them is busy, one of them is connection reset by peer and the last one is key has been revoked. I hope Benedek will be able to shed some light on it, otherwise it is going to be a couple daunting sessions for me in order to trace the origins of those messages.

@kareltucek
Copy link
Copy Markdown
Collaborator

Even more rare, but similar variation to the above; sometimes the OLED shows the phone (BLE) as the active host, but output is going to the USB host instead. (lost UART output for this one, sorry)

When you get into this state, what happens if you switchHost to usb and then again to the BLE?

@pcooke9
Copy link
Copy Markdown

pcooke9 commented Apr 9, 2026

one of them is connection reset by peer

I've seen this as well.

When you get into this state, what happens if you switchHost to usb and then again to the BLE?

I can't remember for sure, but I'll let you know if I see it again.

@kareltucek
Copy link
Copy Markdown
Collaborator

@kareltucek for your attention: f66708e

Right. That explains why only dongle operation is affected. It is also not a regression.

My guess is that the Hid_MouseScrollResolutionsChanged doesn't get called when the instance().ms_enum_.msos2_support() state changes in the above workaround. (Or doesn't get called with the correct arguments.)

extern "C" void Hid_MouseScrollResolutionsChanged(
    hid_transport_t transport, float verticalMultiplier, float horizontalMultiplier)
{
#if DEVICE_IS_UHK_DONGLE
    DongleScrollMultipliers.vertical = verticalMultiplier;
    DongleScrollMultipliers.horizontal = horizontalMultiplier;
    StateSync_UpdateProperty(StateSyncPropertyId_DongleScrollMultipliers, NULL);
#endif
}

I am adding a naive update check into the main loop for it... I guess it is not worth to spend more time on it.

@pcooke9
Copy link
Copy Markdown

pcooke9 commented Apr 10, 2026

I just noticed a couple of issues that are present with FW v16.2.1-3db9354, but not v16.2.0-2ff017c (so something done on April 7th?).

  1. UHK80 shows an error when booting my PC. Only seems to happen when USB is plugged in; doesn't happen if dongle is the only thing connected.

When reaching the Windows login screen, the LEDs turn white (if left-half USB isn't connected, left side LEDs aren't affected) and then OLED shows triangle warning icon.

Agent error panel shows:

udc: Failed to allocate net_buf 1012
ASSERTION FAIL @ WEST_TOPDIR/zephyr/lib/net_buf/buf.c:460

  1. UHK80 crash loop when opening the Epic Games Launcher on PC.

EDIT: Also happens when clicking the "Sign in" button on the Epic Games website https://store.epicgames.com/en-US (Google Chrome or Microsoft Edge browsers. Doesn't happen with Firefox.)

Logs collected when using FW v16.2.1-2cbc849:

UART Log
<err> udc: Failed to allocate net_buf 2050

ASSERTION FAIL @ WEST_TOPDIR/zephyr/lib/net_buf/buf.c:460
 <inf> udc_nrf: Preinit
*** Booting nRF Connect SDK v2.8.0-1d4b8cd3280e ***
*** Using Zephyr OS v3.7.99-c6951670cc67 ***
Wormhole is open, reboot to power mode 0 0
Going to resume!
----------
UHK 80 Right USB started
<inf> fs_nvs: 3 Sectors of 4096 bytes
<inf> fs_nvs: alloc wra: 2, f38
<inf> fs_nvs: data wra: 2, 278
<inf> bt_sdc_hci_driver: SoftDevice Controller build revision:
                         fe 2c f9 6a 7f 36 22 2e  a0 79 c0 40 be 2c 03 20 |.,.j.6". .y.@.,.
                         40 c2 f3 32                                      |@..2
<inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
<inf> bt_hci_core: HW Variant: nRF52x (0x0002)
<inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 254.63788 Build 573996906
<inf> bt_hci_core: No ID address. App must call settings_load()
Settings: Found peer 'left' with address e93e9ac473e2
<inf> bt_hci_core: Identity: CD:EE:3C:39:FD:1A (random)
<inf> bt_hci_core: HCI: version 6.0 (0x0e) revision 0x104e, manufacturer 0x0059
<inf> bt_hci_core: LMP: version 6.0 (0x0e) subver 0x104e

uhk80:right$ Reading hardware config
Reading user config
Applying user config
Flashed User Config version: 13.0.0 (native version: 13.0.0., at 2cbc849 / 16f4a0371ac3035d1848c4ad59a04388)
<inf> StateSync: Setting battery mode to 0
Allocating unregistered bonds
<inf> StateSync: Resetting left right link! Unidirectional
User config applied
CRASH DETECTED, waiting for 5 seconds to allow Agent to reenumerate
<wrn> udc_nrf: USB Address incorrect 0x02

<inf> Conn: Host: 0(USB, Ready)

<inf> Conn: Host: 0(USB, Ready), Active
 <inf> udc_nrf: Preinit
*** Booting nRF Connect SDK v2.8.0-1d4b8cd3280e ***
*** Using Zephyr OS v3.7.99-c6951670cc67 ***
Wormhole is open, reboot to power mode 0 0
Going to resume!
----------
UHK 80 Right USB started
<inf> fs_nvs: 3 Sectors of 4096 bytes
<inf> fs_nvs: alloc wra: 2, f30
<inf> fs_nvs: data wra: 2, 288
<inf> bt_sdc_hci_driver: SoftDevice Controller build revision:
                         fe 2c f9 6a 7f 36 22 2e  a0 79 c0 40 be 2c 03 20 |.,.j.6". .y.@.,.
                         40 c2 f3 32                                      |@..2
<inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
<inf> bt_hci_core: HW Variant: nRF52x (0x0002)
<inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 254.63788 Build 573996906
<inf> bt_hci_core: No ID address. App must call settings_load()
Settings: Found peer 'left' with address e93e9ac473e2
<inf> bt_hci_core: Identity: CD:EE:3C:39:FD:1A (random)
<inf> bt_hci_core: HCI: version 6.0 (0x0e) revision 0x104e, manufacturer 0x0059
<inf> bt_hci_core: LMP: version 6.0 (0x0e) subver 0x104e

uhk80:right$ Reading hardware config
Reading user config
Applying user config
Flashed User Config version: 13.0.0 (native version: 13.0.0., at 2cbc849 / 16f4a0371ac3035d1848c4ad59a04388)
<inf> StateSync: Setting battery mode to 0
Allocating unregistered bonds
<inf> StateSync: Resetting left right link! Unidirectional
User config applied
Enabling UART
<inf> NusServer: NUS Server module initialized.
<inf> Conn: UartLeft: (Ready)
<inf> StateSync: Resetting left right link! Bidirectional
 <inf> udc_nrf: Preinit
*** Booting nRF Connect SDK v2.8.0-1d4b8cd3280e ***
*** Using Zephyr OS v3.7.99-c6951670cc67 ***
Wormhole is open, reboot to power mode 0 0
Going to resume!
----------
UHK 80 Right USB started
<inf> fs_nvs: 3 Sectors of 4096 bytes
<inf> fs_nvs: alloc wra: 2, f30
<inf> fs_nvs: data wra: 2, 288
<inf> bt_sdc_hci_driver: SoftDevice Controller build revision:
                         fe 2c f9 6a 7f 36 22 2e  a0 79 c0 40 be 2c 03 20 |.,.j.6". .y.@.,.
                         40 c2 f3 32                                      |@..2
<inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
<inf> bt_hci_core: HW Variant: nRF52x (0x0002)
<inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 254.63788 Build 573996906
<inf> bt_hci_core: No ID address. App must call settings_load()
Settings: Found peer 'left' with address e93e9ac473e2
<inf> bt_hci_core: Identity: CD:EE:3C:39:FD:1A (random)
<inf> bt_hci_core: HCI: version 6.0 (0x0e) revision 0x104e, manufacturer 0x0059
<inf> bt_hci_core: LMP: version 6.0 (0x0e) subver 0x104e

uhk80:right$ Reading hardware config
Reading user config
Applying user config
Flashed User Config version: 13.0.0 (native version: 13.0.0., at 2cbc849 / 16f4a0371ac3035d1848c4ad59a04388)
<inf> StateSync: Setting battery mode to 0
Allocating unregistered bonds
<inf> StateSync: Resetting left right link! Unidirectional
User config applied
CRASH DETECTED, waiting for 5 seconds to allow Agent to reenumerate
<wrn> udc_nrf: USB Address incorrect 0x02
<inf> Conn: Host: 0(USB, Ready)
<inf> Conn: Host: 0(USB, Ready), Active
 <inf> udc_nrf: Preinit
*** Booting nRF Connect SDK v2.8.0-1d4b8cd3280e ***
*** Using Zephyr OS v3.7.99-c6951670cc67 ***
Wormhole is open, reboot to power mode 0 0
Going to resume!
----------
UHK 80 Right USB started
<inf> fs_nvs: 3 Sectors of 4096 bytes
<inf> fs_nvs: alloc wra: 2, f30
<inf> fs_nvs: data wra: 2, 288
<inf> bt_sdc_hci_driver: SoftDevice Controller build revision:
                         fe 2c f9 6a 7f 36 22 2e  a0 79 c0 40 be 2c 03 20 |.,.j.6". .y.@.,.
                         40 c2 f3 32                                      |@..2
<inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
<inf> bt_hci_core: HW Variant: nRF52x (0x0002)
<inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 254.63788 Build 573996906
<inf> bt_hci_core: No ID address. App must call settings_load()
Settings: Found peer 'left' with address e93e9ac473e2
<inf> bt_hci_core: Identity: CD:EE:3C:39:FD:1A (random)
<inf> bt_hci_core: HCI: version 6.0 (0x0e) revision 0x104e, manufacturer 0x0059
<inf> bt_hci_core: LMP: version 6.0 (0x0e) subver 0x104e

uhk80:right$ Reading hardware config
Reading user config
Applying user config
Flashed User Config version: 13.0.0 (native version: 13.0.0., at 2cbc849 / 16f4a0371ac3035d1848c4ad59a04388)
<inf> StateSync: Setting battery mode to 0
Allocating unregistered bonds
<inf> StateSync: Resetting left right link! Unidirectional
User config applied
Enabling UART
<inf> NusServer: NUS Server module initialized.
Scan module initialized
<inf> NusClient: NUS Client module initialized
 <inf> udc_nrf: Preinit
*** Booting nRF Connect SDK v2.8.0-1d4b8cd3280e ***
*** Using Zephyr OS v3.7.99-c6951670cc67 ***
Wormhole is open, reboot to power mode 0 0
Going to resume!
----------
UHK 80 Right USB started
<inf> fs_nvs: 3 Sectors of 4096 bytes
<inf> fs_nvs: alloc wra: 2, f30
<inf> fs_nvs: data wra: 2, 298
<inf> bt_sdc_hci_driver: SoftDevice Controller build revision:
                         fe 2c f9 6a 7f 36 22 2e  a0 79 c0 40 be 2c 03 20 |.,.j.6". .y.@.,.
                         40 c2 f3 32                                      |@..2
<inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
<inf> bt_hci_core: HW Variant: nRF52x (0x0002)
<inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 254.63788 Build 573996906
<inf> bt_hci_core: No ID address. App must call settings_load()
Settings: Found peer 'left' with address e93e9ac473e2
<inf> bt_hci_core: Identity: CD:EE:3C:39:FD:1A (random)
<inf> bt_hci_core: HCI: version 6.0 (0x0e) revision 0x104e, manufacturer 0x0059
<inf> bt_hci_core: LMP: version 6.0 (0x0e) subver 0x104e

uhk80:right$ Reading hardware config
Reading user config
Applying user config
Flashed User Config version: 13.0.0 (native version: 13.0.0., at 2cbc849 / 16f4a0371ac3035d1848c4ad59a04388)
<inf> StateSync: Setting battery mode to 0
Allocating unregistered bonds
<inf> StateSync: Resetting left right link! Unidirectional
User config applied
CRASH DETECTED, waiting for 5 seconds to allow Agent to reenumerate
<wrn> udc_nrf: USB Address incorrect 0x01
<inf> Conn: Host: 0(USB, Ready)
<inf> Conn: Host: 0(USB, Ready), Active
 <inf> udc_nrf: Preinit
*** Booting nRF Connect SDK v2.8.0-1d4b8cd3280e ***
*** Using Zephyr OS v3.7.99-c6951670cc67 ***
Wormhole is open, reboot to power mode 0 0
Going to resume!
----------
UHK 80 Right USB started
<inf> fs_nvs: 3 Sectors of 4096 bytes
<inf> fs_nvs: alloc wra: 2, f30
<inf> fs_nvs: data wra: 2, 298
<inf> bt_sdc_hci_driver: SoftDevice Controller build revision:
                         fe 2c f9 6a 7f 36 22 2e  a0 79 c0 40 be 2c 03 20 |.,.j.6". .y.@.,.
                         40 c2 f3 32                                      |@..2
<inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
<inf> bt_hci_core: HW Variant: nRF52x (0x0002)
<inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 254.63788 Build 573996906
<inf> bt_hci_core: No ID address. App must call settings_load()
Settings: Found peer 'left' with address e93e9ac473e2
<inf> bt_hci_core: Identity: CD:EE:3C:39:FD:1A (random)
<inf> bt_hci_core: HCI: version 6.0 (0x0e) revision 0x104e, manufacturer 0x0059
<inf> bt_hci_core: LMP: version 6.0 (0x0e) subver 0x104e

uhk80:right$ Reading hardware config
Reading user config
Applying user config
Flashed User Config version: 13.0.0 (native version: 13.0.0., at 2cbc849 / 16f4a0371ac3035d1848c4ad59a04388)
<inf> StateSync: Setting battery mode to 0
Allocating unregistered bonds
<inf> StateSync: Resetting left right link! Unidirectional
User config applied
Enabling UART
<inf> NusServer: NUS Server module initialized.
Scan module initialized
<inf> NusClient: NUS Client module initialized
 <inf> udc_nrf: Preinit
*** Booting nRF Connect SDK v2.8.0-1d4b8cd3280e ***
*** Using Zephyr OS v3.7.99-c6951670cc67 ***
Wormhole is open, reboot to power mode 0 0
Going to resume!
----------
UHK 80 Right USB started
<inf> fs_nvs: 3 Sectors of 4096 bytes
<inf> fs_nvs: alloc wra: 2, f30
<inf> fs_nvs: data wra: 2, 298
<inf> bt_sdc_hci_driver: SoftDevice Controller build revision:
                         fe 2c f9 6a 7f 36 22 2e  a0 79 c0 40 be 2c 03 20 |.,.j.6". .y.@.,.
                         40 c2 f3 32                                      |@..2
<inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
<inf> bt_hci_core: HW Variant: nRF52x (0x0002)
<inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 254.63788 Build 573996906
<inf> bt_hci_core: No ID address. App must call settings_load()
Settings: Found peer 'left' with address e93e9ac473e2
<inf> bt_hci_core: Identity: CD:EE:3C:39:FD:1A (random)
<inf> bt_hci_core: HCI: version 6.0 (0x0e) revision 0x104e, manufacturer 0x0059
<inf> bt_hci_core: LMP: version 6.0 (0x0e) subver 0x104e

uhk80:right$ Reading hardware config
Reading user config
Applying user config
Flashed User Config version: 13.0.0 (native version: 13.0.0., at 2cbc849 / 16f4a0371ac3035d1848c4ad59a04388)
<inf> StateSync: Setting battery mode to 0
Allocating unregistered bonds
<inf> StateSync: Resetting left right link! Unidirectional
User config applied
CRASH DETECTED, waiting for 5 seconds to allow Agent to reenumerate
<wrn> udc_nrf: USB Address incorrect 0x02
<inf> Conn: Host: 0(USB, Ready)
<inf> Conn: Host: 0(USB, Ready), Active
Enabling UART
<inf> NusServer: NUS Server module initialized.
Scan module initialized
<inf> NusClient: NUS Client module initialized
<inf> Bt: Starting bluetooth services.
<inf> Bt: BtManager: Start 'advertising and scanning' (0).
Bt: filling scan filters
<inf> Conn: UartLeft: (Ready)
<inf> StateSync: Resetting left right link! Bidirectional
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
<inf> StateSync: Skipping wake up, tid is 0
Filters matched: left (n/a, e2:73:c4:9a:3e:e9), connectable:1
Scan connecting: left (n/a, e2:73:c4:9a:3e:e9)
<inf> StateSync: Setting battery mode to 1
<inf> StateSync: Batteries: 63% 0% (3869 / 4066 mV; 0 / 0 mV)
<inf> StateSync: Batteries: 63% 0% (3869 / 4066 mV; 0 / 0 mV)
<inf> Bt: MTU exchanging left (n/a, e2:73:c4:9a:3e:e9)
<inf> Bt: Connected left (n/a, e2:73:c4:9a:3e:e9), 29 7
<wrn> bt_smp: Unexpected SMP code 0x0b
<inf> Bt: MTU exchange done for left (n/a, e2:73:c4:9a:3e:e9)
<inf> Conn: NusServerLeft: (Connected), Peer left
<inf> Bt: Initiating NUS connection with left (n/a, e2:73:c4:9a:3e:e9)
<wrn> NusClient: MTU exchange failed with left (n/a, e2:73:c4:9a:3e:e9), err -120
<inf> Conn: NusServerLeft: (Ready), Peer left
<inf> Bt: BtManager: Scheduling scan/adv in 100ms. (SetConnectionConfigured)
<inf> Bt: BtManager: Start 'advertising' (0).
<inf> Bt: Adv: 'HID "and NUS"' started
<inf> StateSync: Batteries: 63% 83% (3869 / 4066 mV; 3804 / 4000 mV)
<inf> StateSync: Batteries: 63% 83% (3869 / 4066 mV; 3808 / 4000 mV)
<inf> StateSync: Batteries: 63% 83% (3869 / 4066 mV; 3808 / 4000 mV)
<inf> StateSync: Batteries: 63% 83% (3868 / 4066 mV; 3808 / 4000 mV)
<wrn> bt_hci_core: opcode 0x2013 status 0x3a

After closing the Epic Games app or affected internet browser, the UHK80 settles down and displays the following error in Agent:

Scan module initialized
NusClient: NUS Client module initialized

I'm assuming this might be related to #1169.

@pcooke9
Copy link
Copy Markdown

pcooke9 commented Apr 10, 2026

FW v16.2.1-2cbc849 does appear to resolve #1406 via dongle with Fast Startup enabled. But I can't be sure if it resolves it when resuming from S3 or hibernation states, since I was never able to reproduce it that way.

@benedekkupper
Copy link
Copy Markdown
Contributor Author

@pcooke9 these crashes are on me, can you retry them with the new build?

@pcooke9
Copy link
Copy Markdown

pcooke9 commented Apr 10, 2026

@pcooke9 these crashes are on me, can you retry them with the new build?

Ok, FW v16.2.1-6bd914a resolves the error when booting the PC, and the crash loop.😎

The udc: Failed to allocate net_buf 1026 and udc: Failed to allocate net_buf 2050 messages mentioned in #1169 are still present when interacting with the Epic Games app/site, but I don't see any negative effects otherwise.

@benedekkupper
Copy link
Copy Markdown
Contributor Author

The udc: Failed to allocate net_buf 1026 and udc: Failed to allocate net_buf 2050 messages mentioned in #1169 are still present when interacting with the Epic Games app/site, but I don't see any negative effects otherwise.

This is expected (error log printing without any negative effect), the good news is that zephyr is migrating to a different allocation strategy in its upcoming release, which will eliminate this issue.

@benedekkupper
Copy link
Copy Markdown
Contributor Author

I tested with Windows 11, mac and Android, they work fine for me at least for a 5 minute test each. From your logs I could reconstruct the problem of freezing BLE input, I pushed the fix here, feel free to test again.

@kareltucek
Copy link
Copy Markdown
Collaborator

Thanks! You are the best!

Will test on monday. (I am away from my uhks now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants