Skip to content
Merged

Jitter #1564

Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions device/prj.conf.overlays/nrf_shared.conf
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ CONFIG_BT_SMP=y

CONFIG_BT_FILTER_ACCEPT_LIST=y

# Shrink the SoftDevice controller's per-event reservation and
# central ACL event spacing so a 7.5ms connection interval has scheduling
# headroom (default 7500us leaves none). Trades NUS bulk throughput for lower
# mouse latency/jitter.
#
# Without this, dongle operates on 11ms instead of 7.5ms interval.
CONFIG_BT_CTLR_SDC_MAX_CONN_EVENT_LEN_DEFAULT=2500
CONFIG_BT_CTLR_SDC_CENTRAL_ACL_EVENT_SPACING_DEFAULT=2500

# increase these to make multiple connections more reliable
# this is a generic ai advice.
CONFIG_BT_ATT_TX_COUNT=10
Expand Down
18 changes: 18 additions & 0 deletions device/src/bt_advertise.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,19 @@ static const struct bt_data sdHid[] = {SD_HID_DATA("UHK 80 BLE")};
#define BY_SIDE(LEFT, RIGHT) LEFT
#endif

// Fast advertisement makes mouse key movement jittery as it makes us miss transports
static void applyAdvInterval(struct bt_le_adv_param* param) {
bool fast = BtConn_UnusedPeripheralConnectionCount() == ACTUAL_PERIPHERAL_CONNECTION_COUNT
|| SelectedHostConnectionId != ConnectionId_Invalid;
if (fast) {
param->interval_min = BT_GAP_ADV_FAST_INT_MIN_1;
param->interval_max = BT_GAP_ADV_FAST_INT_MAX_1;
} else {
param->interval_min = BT_GAP_ADV_SLOW_INT_MIN;
param->interval_max = BT_GAP_ADV_SLOW_INT_MAX;
}
}

#define BT_LE_ADV_START(PARAM, AD, SD) bt_le_adv_start(PARAM, AD, ARRAY_SIZE(AD), SD, ARRAY_SIZE(SD));

static const char * advertisingString(uint8_t advType) {
Expand Down Expand Up @@ -144,6 +157,7 @@ uint8_t BtAdvertise_Start(adv_config_t advConfig)
LOG_DBG("Adv: advertise nus+hid.");
/* our devices don't check service uuids, so hid advertisement effectively advertises nus too */
advParam = *BT_LE_ADV_CONN_ONE_TIME;
applyAdvInterval(&advParam);
err = BT_LE_ADV_START(&advParam, adHid, sdHid);

break;
Expand All @@ -155,10 +169,12 @@ uint8_t BtAdvertise_Start(adv_config_t advConfig)
advParam = *BT_LE_ADV_CONN_ONE_TIME;
advParam.options = BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME | BT_LE_ADV_OPT_FILTER_CONN | BT_LE_ADV_OPT_USE_IDENTITY;

applyAdvInterval(&advParam);
err = BT_LE_ADV_START(&advParam, BY_SIDE(adNusLeft, adNusRight), sdNus);
} else {
LOG_DBG("Adv: advertise nus, without allow list.");
advParam = *BT_LE_ADV_CONN_ONE_TIME;
applyAdvInterval(&advParam);
err = BT_LE_ADV_START(&advParam, BY_SIDE(adNusLeft, adNusRight), sdNus);
}
break;
Expand All @@ -170,10 +186,12 @@ uint8_t BtAdvertise_Start(adv_config_t advConfig)
advParam = *BT_LE_ADV_CONN_ONE_TIME;
advParam.options = BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME | BT_LE_ADV_OPT_FILTER_CONN | BT_LE_ADV_OPT_USE_IDENTITY;

applyAdvInterval(&advParam);
err = BT_LE_ADV_START(&advParam, BY_SIDE(adNusLeft, adNusRight), sdNus);
} else {
LOG_DBG("Adv: direct advertise nus, without allow list.");
advParam = *BT_LE_ADV_CONN_ONE_TIME;
applyAdvInterval(&advParam);
err = BT_LE_ADV_START(&advParam, BY_SIDE(adNusLeft, adNusRight), sdNus);
}

Expand Down
12 changes: 12 additions & 0 deletions device/src/shell/shell_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "slave_drivers/kboot_driver.h"
#include "i2c_addresses.h"
#include "test_suite/test_suite.h"
#include "jitter_test.h"
#include <zephyr/irq.h>
#include <zephyr/arch/cpu.h>
#include <string.h>
Expand Down Expand Up @@ -422,6 +423,16 @@ static int cmd_uhk_testSuite(const struct shell *shell, size_t argc, char *argv[
return 0;
}

static int cmd_uhk_jitterTest(const struct shell *shell, size_t argc, char *argv[])
{
if (argc == 1) {
shell_fprintf(shell, SHELL_NORMAL, "%i\n", JitterTest_Active ? 1 : 0);
} else {
JitterTest_SetActive(argv[1][0] == '1');
}
return 0;
}

void InitShellCommands(void)
{

Expand Down Expand Up @@ -472,6 +483,7 @@ void InitShellCommands(void)
SHELL_CMD_ARG(shells, NULL, "list available shell backends", cmd_uhk_shells, 1, 0),
SHELL_CMD_ARG(irqs, NULL, "list enabled IRQs and their priorities", cmd_uhk_irqs, 1, 0),
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_SUBCMD_SET_END);

SHELL_CMD_REGISTER(uhk, &uhk_cmds, "UHK commands", NULL);
Expand Down
1 change: 1 addition & 0 deletions right/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ target_sources(${PROJECT_NAME} PRIVATE
host_connection.c
i2c.c
i2c_error_logger.c
jitter_test.c
$<$<BOOL:${IS_MCUX_SDK}>:${CMAKE_CURRENT_SOURCE_DIR}/i2c_watchdog.c>
$<$<BOOL:${IS_MCUX_SDK}>:${CMAKE_CURRENT_SOURCE_DIR}/init_clock.c>
$<$<BOOL:${IS_MCUX_SDK}>:${CMAKE_CURRENT_SOURCE_DIR}/init_peripherals.c>
Expand Down
4 changes: 4 additions & 0 deletions right/src/hid/transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ extern "C" {
#include "trace.h"
#include "usb_report_updater.h"
#include "led_display.h"
#include "jitter_test.h"
}
#include "command_app.hpp"
#include "controls_app.hpp"
Expand Down Expand Up @@ -233,6 +234,9 @@ extern "C" errno_t Hid_SendMouseReport(const hid_mouse_report_t *report)
break;
}
Trace_Printf("z22,%d", err);
if (err == 0) {
JitterTest_RecordMouseX(report->x);
}
return err;
}

Expand Down
77 changes: 77 additions & 0 deletions right/src/jitter_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include "jitter_test.h"
#include "timer.h"
#ifdef __ZEPHYR__
#include <zephyr/kernel.h>
#endif

#define JITTER_TEST_SAMPLE_COUNT 20
#define JITTER_TEST_WINDOW_MS 1000

bool JitterTest_Active = false;

typedef struct {
uint8_t dt;
uint8_t x;
} jitter_sample_t;

static jitter_sample_t samples[JITTER_TEST_SAMPLE_COUNT];
static uint16_t count;
static uint32_t lastSampleTime;
static uint32_t windowStart;
static uint32_t nextWindowStart;
static bool waiting;

void JitterTest_SetActive(bool active)
{
JitterTest_Active = active;
count = 0;
waiting = false;
nextWindowStart = 0;
}

static void startWindow(uint32_t now)
{
waiting = false;
count = 0;
windowStart = now;
lastSampleTime = now;
}

static void dumpSamples(void)
{
#ifdef __ZEPHYR__
printk("-----\n");
for (uint32_t i = 0; i < count; i++) {
printk("%u %d\n", samples[i].dt, samples[i].x);
}
#endif
}

void JitterTest_RecordMouseX(int16_t x)
{
if (!JitterTest_Active) {
return;
}

uint32_t now = Timer_GetCurrentTime();

if (waiting) {
if (now < nextWindowStart) {
return;
}
startWindow(now);
} else if (count == 0) {
startWindow(now);
}

samples[count].dt = now - lastSampleTime;
samples[count].x = x;
lastSampleTime = now;
count++;

if (count >= JITTER_TEST_SAMPLE_COUNT) {
dumpSamples();
waiting = true;
nextWindowStart = windowStart + JITTER_TEST_WINDOW_MS;
}
}
12 changes: 12 additions & 0 deletions right/src/jitter_test.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef __JITTER_TEST_H__
#define __JITTER_TEST_H__

#include <stdbool.h>
#include <stdint.h>

extern bool JitterTest_Active;

void JitterTest_SetActive(bool active);
void JitterTest_RecordMouseX(int16_t x);

#endif
Loading