Skip to content

Uhk60 c2usb integration#1482

Draft
benedekkupper wants to merge 11 commits intomasterfrom
uhk60-c2usb-integration
Draft

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

Conversation

@benedekkupper
Copy link
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
Member

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

@benedekkupper benedekkupper force-pushed the uhk60-c2usb-integration branch 4 times, most recently from 670d8ad to c094435 Compare February 8, 2026 21:48
* 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
@benedekkupper benedekkupper force-pushed the uhk60-c2usb-integration branch from c094435 to f2f5ac6 Compare February 8, 2026 22:12
Copy link
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
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
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
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
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
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
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
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
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
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
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
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
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
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
Collaborator

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

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.

3 participants

Comments