Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b5765d5
Add hunting harness.
kareltucek Jul 2, 2026
c1873a8
Provide c2usb diagnostic dump.
kareltucek Jul 3, 2026
11d7a1b
Merge branch 'usb_diagnose' into stuck_hunt
kareltucek Jul 3, 2026
10f15d2
Hook an ISR-handled recovery key.
kareltucek Jul 7, 2026
692e431
Protect logger against reentrancy explicitly.
kareltucek Jul 7, 2026
7beacee
Parametrize the key life logs.
kareltucek Jul 7, 2026
40a452a
Don't spam timer interrupts on uhk606.
kareltucek Jul 7, 2026
2330e02
Add command to decode event vector.
kareltucek Jul 7, 2026
8668f0a
Minimize trace {} spam on uhk60
kareltucek Jul 7, 2026
de3b605
Adjust log buffer length.
kareltucek Jul 8, 2026
9e67138
Logging amends.
kareltucek Jul 9, 2026
5bee2dd
Extend the diagnostic harness.
kareltucek Jul 9, 2026
b9e6507
Merge branch 'master' into stuck_hunt
kareltucek Jul 9, 2026
eb8826a
Merge branch 'master' into stuck_hunt
kareltucek Jul 9, 2026
42a9d87
Refactor key life log to last seen mechanics.
kareltucek Jul 9, 2026
3464c8b
Bulletproof event scheduler event vector updates.
kareltucek Jul 9, 2026
31cacfb
Add more debugging harness.
kareltucek Jul 14, 2026
25b2e71
Apply new c2usb diagnostics branch.
kareltucek Jul 11, 2026
4d15b53
Merge branch 'stuck_hunt_b2' into stuck_hunt
kareltucek Jul 14, 2026
91eb6f4
Merge branch 'master' into stuck_hunt
kareltucek Jul 14, 2026
a84a16a
Fix the stack canary.
kareltucek Jul 14, 2026
bb59d27
Fix module compilation.
kareltucek Jul 14, 2026
3408734
Fix usb log buffer position writes.
kareltucek Jul 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions device/src/keyboard/key_scanner.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "power_mode.h"
#include "keyboard/leds.h"
#include "test_suite/test_hooks.h"
#include "macros/debug_commands.h"

// Thread definitions

Expand Down Expand Up @@ -281,6 +282,9 @@ static void scanAllKeys() {
}

if (DEVICE_IS_UHK80_RIGHT) {
if (targetKeyId == Cfg.RecoveryKey && keyStateBuffer[sourceIndex] && !KeyStates[CURRENT_SLOT_ID][targetKeyId].hardwareSwitchState) {
Macros_RecoverDiagnostics();
}
KeyStates[CURRENT_SLOT_ID][targetKeyId].hardwareSwitchState = keyStateBuffer[sourceIndex];
}

Expand Down
2 changes: 1 addition & 1 deletion device/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ int main(void) {
mode = StateWormhole.restartPowerMode;
StateWormhole.restartPowerMode = PowerMode_Awake;
}
if (WormCfg->devMode) {
if (WormCfg->devMode || StateWormhole.persistStatusBuffer) {
MacroStatusBuffer_InitFromWormhole();
} else {
MacroStatusBuffer_InitNormal();
Expand Down
23 changes: 23 additions & 0 deletions device/src/shell/shell_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "utils.h"
#include "postponer.h"
#include "jitter_test.h"
#include "event_scheduler.h"
#include <zephyr/irq.h>
#include <zephyr/arch/cpu.h>
#include <string.h>
Expand Down Expand Up @@ -366,6 +367,17 @@ static int cmd_uhk_mouseMultipliers(const struct shell *shell, size_t argc, char
return 0;
}

static int cmd_uhk_reportEventVector(const struct shell *shell, size_t argc, char *argv[]) {
int err = 0;
uint32_t mask = shell_strtoul(argv[1], 0, &err);
if (err) {
shell_error(shell, "invalid EventVector value: %s", argv[1]);
return -EINVAL;
}
EventVector_ReportMask("EventVector: ", mask);
return 0;
}

static int cmd_uhk_logPriority(const struct shell *shell, size_t argc, char *argv[])
{

Expand Down Expand Up @@ -487,6 +499,15 @@ static int cmd_uhk_listActiveKeys(const struct shell *shell, size_t argc, char *
return 0;
}

// provided by the patched c2usb (usb/df/mac_diag.hpp)
extern void c2usb_diag_dump(void);

static int cmd_uhk_usbDiag(const struct shell *shell, size_t argc, char *argv[])
{
c2usb_diag_dump();
return 0;
}

static int cmd_uhk_jitterTest(const struct shell *shell, size_t argc, char *argv[])
{
if (argc == 1) {
Expand Down Expand Up @@ -556,6 +577,8 @@ void InitShellCommands(void)
SHELL_CMD_ARG(testSuite, NULL, "run test suite [module] [test]", cmd_uhk_testSuite, 1, 2),
SHELL_CMD_ARG(jitterTest, NULL, "get/set mouse jitter test mode", cmd_uhk_jitterTest, 1, 1),
SHELL_CMD_ARG(listActiveKeys, NULL, "list currently pressed keys", cmd_uhk_listActiveKeys, 1, 0),
SHELL_CMD_ARG(usbDiag, NULL, "dump c2usb state and anomaly log", cmd_uhk_usbDiag, 1, 0),
SHELL_CMD_ARG(reportEventVector, NULL, "decode an EventVector mask value", cmd_uhk_reportEventVector, 2, 0),
SHELL_SUBCMD_SET_END);

SHELL_CMD_REGISTER(uhk, &uhk_cmds, "UHK commands", NULL);
Expand Down
4 changes: 3 additions & 1 deletion doc-dev/reference-manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,13 +307,14 @@ COMMAND = statsActiveMacros
COMMAND = statsRecordKeyTiming
COMMAND = statsVariables
COMMAND = statsBattery
COMMAND = diagnose
COMMAND = diagnose { usb | logic }
COMMAND = panic
COMMAND = freeze
COMMAND = trace
COMMAND = setStatus STRING
COMMAND = clearStatus
COMMAND = set emergencyKey KEYID
COMMAND = set recoveryKey KEYID
COMMAND = validateMacros
COMMAND = resetConfiguration
COMMAND = set leds.alwaysOn BOOL
Expand Down Expand Up @@ -468,6 +469,7 @@ COMMAND = setEmergencyKey KEYID
- `statsRecordKeyTiming` will write timing information of pressed and released keys into status buffer until invoked again.
- `diagnose` will deactivate all keys and macros and print diagnostic information into the status buffer.
- `set emergencyKey KEYID` will make the one key be ignored by postponing mechanisms. `diagnose` command on such key can be used to recover keyboard from conditions like infinite postponing loop...
- `set recoveryKey KEYID` designates a key that is handled directly in the right half's key scanner. When pressed, it dumps USB diagnostics and reboots the keyboard, so it works even when the main event loop is stuck. The key has to be bound in the right half; 255 (default) disables it.

### Delays

Expand Down

This file was deleted.

4 changes: 2 additions & 2 deletions right/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ mcux_add_source(SOURCES ../lib/bootloader/src/bootloader/src/wormhole.c)
mcux_add_include(INCLUDES ../lib/bootloader/src)

mcux_add_linker_symbol(SYMBOLS
__heap_size__=0x2000
__stack_size__=0x0400
__heap_size__=0x400
__stack_size__=0x1000
__bl_app_vector_table_address__=${BL_APP_VECTOR_TABLE_ADDRESS}
)
mcux_add_armgcc_linker_script(LINKER src/link/MK22FN512xxx12_flash.ld)
Expand Down
1 change: 1 addition & 0 deletions right/src/config_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ const config_t DefaultCfg = (config_t){
.Bt_DirectedAdvertisingAllowed = false,
.DevMode = false,
.EmergencyKey = NULL,
.RecoveryKey = 255,
.UiStyle = UiStyle_Classic,
.DeviceName = { .offset = 0, .len = 0 },
.KeyActionColors = {
Expand Down
1 change: 1 addition & 0 deletions right/src/config_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
uint16_t AutoShiftDelay;
uint8_t ChordingDelay;
key_state_t* EmergencyKey;
uint8_t RecoveryKey;

// bluetooth
bool Bt_AllowUnsecuredConnections;
Expand Down
59 changes: 59 additions & 0 deletions right/src/debug.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#include <string.h>
#include "debug.h"
#include "trace.h"
#include "logger.h"
#include "macros/status_buffer.h"

#ifdef __ZEPHYR__
#include "logger.h"
Expand All @@ -9,6 +12,62 @@
#include "segment_display.h"
#endif

#ifndef __ZEPHYR__

// SOFT_ASSERT reporter (see shared/atomicity.h): prints only the first failure,
// as soft asserts may fire from hot ISR paths.
void SoftAssertFailed(const char* file, int line)
{
LogS("!SOFT_ASSERT:%s:%d!\n", file, line);
}

// Main/MSP stack canary. main + every ISR share the 1 KB MSP (__StackLimit ..
// __StackTop). At boot we fill it - and the unused gap below it, down to
// __HeapLimit - with a pattern; the lowest word the stack ever clobbered is
// then its all-time low-water mark. Filling below __StackLimit means an
// overflow is measured, not just detected (it lands in the gap, which is
// otherwise unused; only past __HeapLimit does it corrupt the heap).

extern uint32_t __StackLimit[];
extern uint32_t __StackTop[];
extern uint32_t __HeapLimit[];

#define STACK_CANARY_PATTERN 0xC0DEBA5Eu

void Debug_InitStackCanary(void) {
uint32_t sp;
__asm volatile ("mov %0, sp" : "=r" (sp));
uint32_t* end = (uint32_t*)((sp - 32) & ~3u);
for (uint32_t* p = __HeapLimit; p < end && p < __StackTop; p++) {
*p = STACK_CANARY_PATTERN;
}
}

static uint32_t* stackLowWaterMark(void) {
uint32_t* p = __HeapLimit;
while (p < __StackTop && *p == STACK_CANARY_PATTERN) {
p++;
}
return p;
}

uint32_t Debug_StackSize(void) {
return (uint8_t*)__StackTop - (uint8_t*)__StackLimit;
}

uint32_t Debug_StackUsed(void) {
return (uint8_t*)__StackTop - (uint8_t*)stackLowWaterMark();
}

// Bytes still unused below the deepest the stack ever went. Negative means the
// stack grew past __StackLimit by that many bytes (into the unused gap; if it
// reaches -HEADROOM_GAP it has eaten into the heap).
int32_t Debug_StackHeadroom(void) {
return (uint8_t*)stackLowWaterMark() - (uint8_t*)__StackLimit;
}

#endif

#ifdef WATCHES

#include "timer.h"
Expand Down
Loading
Loading