From f2f1de4d97231e294850ffedf77ef660f7452730 Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Thu, 5 Jun 2025 16:03:35 +0700 Subject: [PATCH 01/14] chore: move zsa/oryx module to a git submodule --- .gitmodules | 3 + modules/zsa | 1 + modules/zsa/oryx/config.h | 10 - modules/zsa/oryx/introspection.h | 6 - modules/zsa/oryx/keycode_aliases.h | 7 - modules/zsa/oryx/oryx.c | 334 ------------------------- modules/zsa/oryx/oryx.h | 93 ------- modules/zsa/oryx/post_config.h | 10 - modules/zsa/oryx/qmk_module.json | 8 - modules/zsa/oryx/rgb_matrix_module.inc | 21 -- modules/zsa/oryx/rules.mk | 1 - 11 files changed, 4 insertions(+), 490 deletions(-) create mode 160000 modules/zsa delete mode 100644 modules/zsa/oryx/config.h delete mode 100644 modules/zsa/oryx/introspection.h delete mode 100644 modules/zsa/oryx/keycode_aliases.h delete mode 100644 modules/zsa/oryx/oryx.c delete mode 100644 modules/zsa/oryx/oryx.h delete mode 100644 modules/zsa/oryx/post_config.h delete mode 100644 modules/zsa/oryx/qmk_module.json delete mode 100644 modules/zsa/oryx/rgb_matrix_module.inc delete mode 100644 modules/zsa/oryx/rules.mk diff --git a/.gitmodules b/.gitmodules index 7d8dbcb4ed..d0b9b65ae3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,3 +25,6 @@ path = lib/lvgl url = https://github.com/qmk/lvgl.git branch = release/v8.2 +[submodule "modules/zsa"] + path = modules/zsa + url = git@github.com:zsa/qmk_modules.git diff --git a/modules/zsa b/modules/zsa new file mode 160000 index 0000000000..480298e201 --- /dev/null +++ b/modules/zsa @@ -0,0 +1 @@ +Subproject commit 480298e2018302120fa5f4a6eea6d4ecc88da99c diff --git a/modules/zsa/oryx/config.h b/modules/zsa/oryx/config.h deleted file mode 100644 index b9f61ea84e..0000000000 --- a/modules/zsa/oryx/config.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2024 ZSA Technology Labs, Inc <@zsa> -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#define RAW_USAGE_PAGE 0xFF60 -#define RAW_USAGE_ID 0x61 - -#define ORYX_ENABLE -#define ORYX_CONFIGURATOR diff --git a/modules/zsa/oryx/introspection.h b/modules/zsa/oryx/introspection.h deleted file mode 100644 index f8426d4dfc..0000000000 --- a/modules/zsa/oryx/introspection.h +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2024 ZSA Technology Labs, Inc <@zsa> -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "oryx.h" diff --git a/modules/zsa/oryx/keycode_aliases.h b/modules/zsa/oryx/keycode_aliases.h deleted file mode 100644 index 295a3d5f4c..0000000000 --- a/modules/zsa/oryx/keycode_aliases.h +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2024 ZSA Technology Labs, Inc <@zsa> -// SPDX-License-Identifier: GPL-2.0-or-later -// -// As QMK evolves, some keycodes are renamed. This file provides a way to map old keycodes to new ones. - -// Changed from fw23 to fw24 -#define QK_MAGIC_TOGGLE_NKRO MAGIC_TOGGLE_NKRO diff --git a/modules/zsa/oryx/oryx.c b/modules/zsa/oryx/oryx.c deleted file mode 100644 index 5131a18665..0000000000 --- a/modules/zsa/oryx/oryx.c +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright 2024 ZSA Technology Labs, Inc <@zsa> -// SPDX-License-Identifier: GPL-2.0-or-later - -#include QMK_KEYBOARD_H -#include -#include "oryx.h" -#include "action_util.h" - -ASSERT_COMMUNITY_MODULES_MIN_API_VERSION(1, 1, 1); - -uint8_t current_layer = 0; - -rawhid_state_t rawhid_state = { - .paired = false, - .rgb_control = false, - .status_led_control = false, -}; - -#if defined(PROTOCOL_LUFA) -bool send_report(uint8_t endpoint, void *report, size_t size); -# include "usb_descriptor.h" -# define RAW_EP_NAME RAW_IN_EPNUM -#elif defined(PROTOCOL_CHIBIOS) -# include "usb_endpoints.h" -# define RAW_EP_NAME USB_ENDPOINT_IN_RAW -bool send_report(usb_endpoint_in_lut_t endpoint, void *report, size_t size); -#endif - -#ifdef RGB_MATRIX_ENABLE -RGB webhid_leds[RGB_MATRIX_LED_COUNT]; -#endif - -void raw_hid_send_oryx(uint8_t *data, uint8_t length) { - if (length != RAW_EPSIZE) { - return; - } - if (!send_report(RAW_EP_NAME, data, length)) { -#if !defined(PROTOCOL_LUFA) - rawhid_state.paired = false; -#endif - } -} - -void oryx_error(uint8_t code) { - uint8_t event[RAW_EPSIZE]; - event[0] = ORYX_EVT_ERROR; - event[1] = code; - raw_hid_send_oryx(event, RAW_EPSIZE); -} - -void oryx_layer_event(void) { - uint8_t layer; - uint8_t event[RAW_EPSIZE]; - layer = get_highest_layer(layer_state | default_layer_state); - event[0] = ORYX_EVT_LAYER; - event[1] = layer; - event[2] = ORYX_STOP_BIT; - raw_hid_send_oryx(event, sizeof(event)); -} - -void pairing_failed_event(void) { - rawhid_state.paired = false; - uint8_t event[RAW_EPSIZE]; - event[0] = ORYX_EVT_PAIRING_FAILED; - event[1] = ORYX_STOP_BIT; - raw_hid_send_oryx(event, sizeof(event)); -} - -void pairing_success_event(void) { - rawhid_state.paired = true; - uint8_t event[RAW_EPSIZE]; - event[0] = ORYX_EVT_PAIRING_SUCCESS; - event[1] = ORYX_STOP_BIT; - raw_hid_send_oryx(event, sizeof(event)); - oryx_layer_event(); -} - -void toggle_smart_layer(void) { - uint8_t event[RAW_EPSIZE]; - event[0] = ORYX_EVT_TOGGLE_SMART_LAYER; - event[1] = ORYX_STOP_BIT; - raw_hid_send_oryx(event, sizeof(event)); -} - -void trigger_smart_layer(void) { - uint8_t event[RAW_EPSIZE]; - event[0] = ORYX_EVT_TRIGGER_SMART_LAYER; - event[1] = ORYX_STOP_BIT; - raw_hid_send_oryx(event, sizeof(event)); -} - -void set_webhid_effect(void) { -#if defined(RGB_MATRIX_ENABLE) && !defined(PROTOCOL_LUFA) && defined(RGB_MATRIX_CUSTOM_KB) - rgb_matrix_mode_noeeprom(RGB_MATRIX_CUSTOM_oryx_webhid_effect); - rawhid_state.rgb_control = true; -#endif -} - -void clear_webhid_effect(void) { -#if defined(RGB_MATRIX_ENABLE) && !defined(PROTOCOL_LUFA) - // Clear the pattern - for (uint8_t i = 0; i < RGB_MATRIX_LED_COUNT; i++) { - webhid_leds[i] = (RGB){.r = 0, .g = 0, .b = 0}; - } - rgb_matrix_reload_from_eeprom(); - rawhid_state.rgb_control = false; -#endif -} - -void raw_hid_receive(uint8_t *data, uint8_t length) { - uint8_t command = data[0]; - uint8_t *param = &data[1]; - - switch (command) { - case ORYX_CMD_GET_FW_VERSION: { - uint8_t event[RAW_EPSIZE]; - uint8_t fw_version_size = sizeof(SERIAL_NUMBER); - uint8_t stop[1]; - - event[0] = ORYX_EVT_GET_FW_VERSION; - stop[0] = ORYX_STOP_BIT; - - memcpy(event + 1, SERIAL_NUMBER, fw_version_size); - memcpy(event + fw_version_size, stop, 1); - - raw_hid_send_oryx(event, RAW_EPSIZE); - break; - } - - case ORYX_GET_PROTOCOL_VERSION: { - uint8_t event[RAW_EPSIZE]; - event[0] = ORYX_EVT_GET_PROTOCOL_VERSION; - event[1] = ORYX_PROTOCOL_VERSION; - event[2] = ORYX_STOP_BIT; - - raw_hid_send_oryx(event, RAW_EPSIZE); - break; - } - - case ORYX_CMD_PAIRING_INIT: - pairing_success_event(); - - case ORYX_CMD_PAIRING_VALIDATE: - break; // Keeping this for backwards compatibility with older versions of Wally / Keymapp - - case ORYX_SET_LAYER: - // The first param's byte is on / off - // The second param's byte is the layer number - if (rawhid_state.paired == true) { - if (param[0] == 0) { - layer_off(param[1]); - } else { - layer_move(param[1]); - } - } - break; - - case ORYX_RGB_CONTROL: -#if defined(RGB_MATRIX_ENABLE) && !defined(PROTOCOL_LUFA) - if (param[0] == 0) { - clear_webhid_effect(); - } else { - set_webhid_effect(); - } - uint8_t event[RAW_EPSIZE]; - event[0] = ORYX_EVT_RGB_CONTROL; - event[1] = rawhid_state.rgb_control; - raw_hid_send_oryx(event, RAW_EPSIZE); -#else - oryx_error(ORYX_ERR_RGB_MATRIX_NOT_ENABLED); -#endif - break; - - case ORYX_SET_RGB_LED: -#if defined(RGB_MATRIX_ENABLE) && !defined(PROTOCOL_LUFA) - webhid_leds[param[0]] = (RGB){.r = param[1], .g = param[2], .b = param[3]}; - if (rawhid_state.rgb_control == false) { - set_webhid_effect(); - } -#else - oryx_error(ORYX_ERR_RGB_MATRIX_NOT_ENABLED); -#endif - break; - case ORYX_SET_RGB_LED_ALL: -#if defined(RGB_MATRIX_ENABLE) && !defined(PROTOCOL_LUFA) - for (uint8_t i = 0; i < RGB_MATRIX_LED_COUNT; i++) { - webhid_leds[i] = (RGB){.r = param[0], .g = param[1], .b = param[2]}; - } - if (rawhid_state.rgb_control == false) { - set_webhid_effect(); - } -#else - oryx_error(ORYX_ERR_RGB_MATRIX_NOT_ENABLED); -#endif - break; - case ORYX_SET_STATUS_LED: - rawhid_state.status_led_control = true; // Eagerly take control of the status LEDs - switch (param[0]) { - case 0: -#ifdef STATUS_LED_1 - STATUS_LED_1(param[1]); -#else - oryx_error(ORYX_ERR_STATUS_LED_OUT_OF_RANGE); -#endif - break; - case 1: -#ifdef STATUS_LED_2 - STATUS_LED_2(param[1]); -#else - oryx_error(ORYX_ERR_STATUS_LED_OUT_OF_RANGE); -#endif - break; - case 2: -#ifdef STATUS_LED_3 - STATUS_LED_3(param[1]); -#else - oryx_error(ORYX_ERR_STATUS_LED_OUT_OF_RANGE); -#endif - break; - case 3: -#ifdef STATUS_LED_4 - STATUS_LED_4(param[1]); -#else - oryx_error(ORYX_ERR_STATUS_LED_OUT_OF_RANGE); -#endif - break; - case 4: -#ifdef STATUS_LED_5 - STATUS_LED_5(param[1]); -#else - oryx_error(ORYX_ERR_STATUS_LED_OUT_OF_RANGE); -#endif - break; - case 5: -#ifdef STATUS_LED_6 - STATUS_LED_6(param[1]); -#else - oryx_error(ORYX_ERR_STATUS_LED_OUT_OF_RANGE); -#endif - break; - - default: - oryx_error(ORYX_ERR_STATUS_LED_OUT_OF_RANGE); - break; - } - break; - case ORYX_UPDATE_BRIGHTNESS: { -#if defined(RGB_MATRIX_ENABLE) && !defined(PROTOCOL_LUFA) - if (param[0]) { - rgb_matrix_increase_val_noeeprom(); - } else { - rgb_matrix_decrease_val_noeeprom(); - } -#else - oryx_error(ORYX_ERR_RGB_MATRIX_NOT_ENABLED); -#endif - break; - } - case ORYX_STATUS_LED_CONTROL: { - rawhid_state.status_led_control = param[0]; - if (!param[0]) { -#ifdef STATUS_LED_1 - STATUS_LED_1(0); -#endif -#ifdef STATUS_LED_2 - STATUS_LED_2(0); -#endif -#ifdef STATUS_LED_3 - STATUS_LED_3(0); -#endif -#ifdef STATUS_LED_4 - STATUS_LED_4(0); -#endif -#ifdef STATUS_LED_5 - STATUS_LED_5(0); -#endif -#ifdef STATUS_LED_6 - STATUS_LED_6(0); -#endif - } - uint8_t event[RAW_EPSIZE]; - event[0] = ORYX_EVT_STATUS_LED_CONTROL; - event[1] = rawhid_state.status_led_control; - raw_hid_send_oryx(event, RAW_EPSIZE); - break; - } - default: - oryx_error(ORYX_ERR_UNKNOWN_COMMAND); - } -} - -bool pre_process_record_oryx(uint16_t keycode, keyrecord_t *record) { - if (!pre_process_record_oryx_kb(keycode, record)) { - return true; - } - // While paired, the keyboard sends keystrokes positions to the host - if (rawhid_state.paired == true) { - uint8_t event[RAW_EPSIZE]; - event[0] = record->event.pressed ? ORYX_EVT_KEYDOWN : ORYX_EVT_KEYUP; - event[1] = record->event.key.col; - event[2] = record->event.key.row; - event[3] = ORYX_STOP_BIT; - raw_hid_send_oryx(event, sizeof(event)); - } - return true; -} - -layer_state_t layer_state_set_oryx(layer_state_t state) { - state = layer_state_set_oryx_kb(state); - if (rawhid_state.paired) { - uint8_t layer = get_highest_layer(state | default_layer_state); - // Some layer actions (OSL) trigger the layer state change thrice, - // so we need to check if the layer has actually changed - if (current_layer == layer) { - return state; - } - current_layer = layer; -#if defined(PROTOCOL_LUFA) - // Required for Atmel Boards - wait_ms(10); -#endif - uint8_t event[RAW_EPSIZE]; - event[0] = ORYX_EVT_LAYER; - event[1] = current_layer; - event[2] = ORYX_STOP_BIT; - raw_hid_send_oryx(event, sizeof(event)); - } - return state; -} - -layer_state_t default_layer_state_set_oryx(layer_state_t state) { - layer_state_set_oryx(state | layer_state); - return default_layer_state_set_oryx_kb(state); -} diff --git a/modules/zsa/oryx/oryx.h b/modules/zsa/oryx/oryx.h deleted file mode 100644 index 4f3011cfbf..0000000000 --- a/modules/zsa/oryx/oryx.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2024 ZSA Technology Labs, Inc <@zsa> -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once -/* -The Oryx Webhid protocol - -Each HID packet is a series of bytes. The first byte is the packet type is the command. The rest of the bytes are the -params. - -Before sending a packet, the host needs to be paired or should request a pairing code. - -The pairing code is a sequence of key positions derived from Oryx's firmware version code stored in the FIRMWARE_VERSION -define. - -Once the host has paired, it can freely use the commands define in the Oryx_Command_Code enum for which the board will -always respond with a Oryx_Event_Code or a Oryx_Error_Code. -*/ - -#include "quantum.h" -#include "raw_hid.h" - -#ifndef RAW_EPSIZE -# define RAW_EPSIZE 32 -#endif - -#define ORYX_PROTOCOL_VERSION 0x04 -#define ORYX_STOP_BIT -2 - -enum Oryx_Command_Code { - ORYX_CMD_GET_FW_VERSION, - ORYX_CMD_PAIRING_INIT, - ORYX_CMD_PAIRING_VALIDATE, - ORYX_CMD_DISCONNECT, - ORYX_SET_LAYER, - ORYX_RGB_CONTROL, - ORYX_SET_RGB_LED, - ORYX_SET_STATUS_LED, - ORYX_UPDATE_BRIGHTNESS, - ORYX_SET_RGB_LED_ALL, - ORYX_STATUS_LED_CONTROL, - ORYX_GET_PROTOCOL_VERSION = 0xFE, -}; - -enum Oryx_Event_Code { - ORYX_EVT_GET_FW_VERSION, - ORYX_EVT_PAIRING_INPUT, - ORYX_EVT_PAIRING_KEY_INPUT, - ORYX_EVT_PAIRING_FAILED, - ORYX_EVT_PAIRING_SUCCESS, - ORYX_EVT_LAYER, - ORYX_EVT_KEYDOWN, - ORYX_EVT_KEYUP, - ORYX_EVT_RGB_CONTROL, - ORYX_EVT_TOGGLE_SMART_LAYER, - ORYX_EVT_TRIGGER_SMART_LAYER, - ORYX_EVT_STATUS_LED_CONTROL, - ORYX_EVT_GET_PROTOCOL_VERSION = 0XFE, - ORYX_EVT_ERROR = 0xFF, -}; - -enum Oryx_Error_Code { - ORYX_ERR_PAIRING_INIT_FAILED, - ORYX_ERR_PAIRING_INPUT_FAILED, - ORYX_ERR_PAIRING_KEY_INPUT_FAILED, - ORYX_ERR_PAIRING_FAILED, - ORYX_ERR_RGB_MATRIX_NOT_ENABLED, - ORYX_ERR_STATUS_LED_OUT_OF_RANGE, - ORYX_ERR_UNKNOWN_COMMAND = 0xFF, -}; - -extern bool oryx_state_live_training_enabled; - -typedef struct { - bool paired; - bool rgb_control; - bool status_led_control; -} rawhid_state_t; - -extern rawhid_state_t rawhid_state; - -void oryx_error(uint8_t code); -void pairing_failed_event(void); -void pairing_succesful_event(void); -void toggle_smart_layer(void); -void trigger_smart_layer(void); -void set_webhid_effect(void); - -void oryx_layer_event(void); - -#if defined(RGB_MATRIX_ENABLE) && !defined(KEYBOARD_ergodox_ez_glow) -extern RGB webhid_leds[RGB_MATRIX_LED_COUNT]; -#endif diff --git a/modules/zsa/oryx/post_config.h b/modules/zsa/oryx/post_config.h deleted file mode 100644 index 3681f019e7..0000000000 --- a/modules/zsa/oryx/post_config.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2024 ZSA Technology Labs, Inc <@zsa> -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "keycode_aliases.h" - -#ifndef SERIAL_NUMBER -# define SERIAL_NUMBER "default/latest" -#endif // SERIAL_NUMBER diff --git a/modules/zsa/oryx/qmk_module.json b/modules/zsa/oryx/qmk_module.json deleted file mode 100644 index 962cfd2f9f..0000000000 --- a/modules/zsa/oryx/qmk_module.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "maintainer": "ZSA", - "module_name": "oryx", - "features": { - "raw": true, - "via": false - } -} diff --git a/modules/zsa/oryx/rgb_matrix_module.inc b/modules/zsa/oryx/rgb_matrix_module.inc deleted file mode 100644 index 1613215565..0000000000 --- a/modules/zsa/oryx/rgb_matrix_module.inc +++ /dev/null @@ -1,21 +0,0 @@ -#ifdef RGB_MATRIX_ENABLE -RGB_MATRIX_EFFECT(oryx_webhid_effect) -# ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS - -extern RGB webhid_leds[RGB_MATRIX_LED_COUNT]; - -static bool oryx_webhid_effect_run(effect_params_t* params) { - RGB_MATRIX_USE_LIMITS(led_min, led_max); - float f = (float)rgb_matrix_config.hsv.v / UINT8_MAX; - for (uint8_t i = led_min; i < led_max; ++i) { - rgb_matrix_set_color(i, webhid_leds[i].r * f, webhid_leds[i].g * f, webhid_leds[i].b * f); - } - return rgb_matrix_check_finished_leds(led_max); -} - -static bool oryx_webhid_effect(effect_params_t* params) { - return oryx_webhid_effect_run(params); -} - -# endif -#endif diff --git a/modules/zsa/oryx/rules.mk b/modules/zsa/oryx/rules.mk deleted file mode 100644 index bd86c2e08d..0000000000 --- a/modules/zsa/oryx/rules.mk +++ /dev/null @@ -1 +0,0 @@ -POST_CONFIG_H += keyboards/zsa/common/keycode_aliases.h From dbe50d2a662fcb4bd825387704bbb36c70420748 Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Thu, 5 Jun 2025 17:59:59 +0700 Subject: [PATCH 02/14] feat: port navigators to qmk25 --- builddefs/common_features.mk | 6 +- drivers/sensors/navigator_trackball.c | 264 ++++++++++++ drivers/sensors/navigator_trackball.h | 67 +++ drivers/sensors/navigator_trackpad.c | 477 ++++++++++++++++++++++ drivers/sensors/navigator_trackpad.h | 134 ++++++ keyboards/zsa/ergodox_ez/ergodox_ez.c | 3 + keyboards/zsa/ergodox_ez/ergodox_ez.h | 7 +- keyboards/zsa/moonlander/moonlander.c | 5 + keyboards/zsa/moonlander/moonlander.h | 24 +- keyboards/zsa/planck_ez/planck_ez.c | 4 + keyboards/zsa/planck_ez/planck_ez.h | 6 - keyboards/zsa/voyager/voyager.c | 5 + keyboards/zsa/voyager/voyager.h | 6 +- modules/zsa | 2 +- quantum/pointing_device/pointing_device.h | 6 + 15 files changed, 982 insertions(+), 34 deletions(-) create mode 100644 drivers/sensors/navigator_trackball.c create mode 100644 drivers/sensors/navigator_trackball.h create mode 100644 drivers/sensors/navigator_trackpad.c create mode 100644 drivers/sensors/navigator_trackpad.h diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index 56eed80ae0..52b49277e4 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -123,7 +123,7 @@ ifeq ($(strip $(MOUSEKEY_ENABLE)), yes) MOUSE_ENABLE := yes endif -VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick azoteq_iqs5xx cirque_pinnacle_i2c cirque_pinnacle_spi paw3204 pmw3320 pmw3360 pmw3389 pimoroni_trackball custom +VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick azoteq_iqs5xx cirque_pinnacle_i2c cirque_pinnacle_spi paw3204 pmw3320 pmw3360 pmw3389 pimoroni_trackball navigator_trackball navigator_trackpad custom ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes) ifeq ($(filter $(POINTING_DEVICE_DRIVER),$(VALID_POINTING_DEVICE_DRIVER_TYPES)),) $(call CATASTROPHIC_ERROR,Invalid POINTING_DEVICE_DRIVER,POINTING_DEVICE_DRIVER="$(POINTING_DEVICE_DRIVER)" is not a valid pointing device type) @@ -157,6 +157,10 @@ ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes) SRC += $(QUANTUM_DIR)/pointing_device/pointing_device_gestures.c else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), pimoroni_trackball) I2C_DRIVER_REQUIRED = yes + else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), navigator_trackball) + I2C_DRIVER_REQUIRED = yes + else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), navigator_trackpad) + I2C_DRIVER_REQUIRED = yes else ifneq ($(filter $(strip $(POINTING_DEVICE_DRIVER)),pmw3360 pmw3389),) SPI_DRIVER_REQUIRED = yes SRC += drivers/sensors/pmw33xx_common.c diff --git a/drivers/sensors/navigator_trackball.c b/drivers/sensors/navigator_trackball.c new file mode 100644 index 0000000000..071a4c1333 --- /dev/null +++ b/drivers/sensors/navigator_trackball.c @@ -0,0 +1,264 @@ +#include "i2c_master.h" +#include "pointing_device.h" +#include "navigator_trackball.h" +#include +#include +#include "quantum.h" + +const pointing_device_driver_t navigator_trackball_pointing_device_driver = { + .init = navigator_trackball_device_init, + .get_report = navigator_trackball_get_report, + .get_cpi = navigator_trackball_get_cpi, + .set_cpi = navigator_trackball_set_cpi +}; + +uint8_t current_cpi = DEFAULT_CPI_TICK; + +uint8_t has_motion = 0; + +uint8_t trackball_init = 0; + +deferred_token callback_token = 0; + +paw3805ek_reg_seq_t paw3805ek_configure_seq[] = { + {0x06, 0x80}, // Software reset + {0x00, 0x00}, // Request the sensor ID + {0x09 | WRITE_REG_BIT, 0x5A}, // Disable the write protection +#ifdef MOUSE_EXTENDED_REPORT + {0x19 | WRITE_REG_BIT, 0x30}, // Set the sensor orientation, set motion data length to 16 bits +#else + {0x19 | WRITE_REG_BIT, 0x34}, // Set the sensor orientation, set motion data length to 8 bits +#endif + //{0x26 | WRITE_REG_BIT, 0x10}, // Enable burst mode + {0x09 | WRITE_REG_BIT, 0x00}, // Enable the write protection +}; + +i2c_status_t sci18is606_write(uint8_t *data, uint8_t length) { + return i2c_transmit(NAVIGATOR_TRACKBALL_ADDRESS, data, length, NAVIGATOR_TRACKBALL_TIMEOUT); +} + +i2c_status_t sci18is606_read(uint8_t *data, uint8_t length) { + return i2c_receive(NAVIGATOR_TRACKBALL_ADDRESS, data, length, NAVIGATOR_TRACKBALL_TIMEOUT); +} + +i2c_status_t sci18is606_spi_tx(uint8_t *data, uint8_t length, bool read) { + i2c_status_t status = sci18is606_write(data, length); + wait_us(length * 15); + // Read the SPI response if the command expects it + if (read) { + status = sci18is606_read(data, length); + } + if (status != I2C_STATUS_SUCCESS) { + trackball_init = 0; + } + return status; +} + +i2c_status_t sci18is606_configure(void) { + uint8_t spi_conf[2] = {SCI18IS606_CONF_SPI, SCI18IS606_CONF}; + i2c_status_t status = sci18is606_write(spi_conf, 2); + wait_ms(10); + if (status != I2C_STATUS_SUCCESS) { + trackball_init = 0; + } + return status; +} + +bool paw3805ek_set_cpi(void) { + uint8_t next_cpi_x = 0; + uint8_t next_cpi_y = 0; + // traverse the sequence by compairing the cpi_x value with the current cpi_x value + // set the cpi to the next value in the sequence + switch (current_cpi) { + case 1: { + next_cpi_x = CPI_X_800; + next_cpi_y = CPI_Y_800; + break; + } + case 2: { + next_cpi_x = CPI_X_1000; + next_cpi_y = CPI_Y_1000; + break; + } + case 3: { + next_cpi_x = CPI_X_1200; + next_cpi_y = CPI_Y_1200; + break; + } + case 4: { + next_cpi_x = CPI_X_1600; + next_cpi_y = CPI_Y_1600; + break; + } + case 5: { + next_cpi_x = CPI_X_2000; + next_cpi_y = CPI_Y_2000; + break; + } + case 6: { + next_cpi_x = CPI_X_2400; + next_cpi_y = CPI_Y_2400; + break; + } + case 7: { + next_cpi_x = CPI_X_3000; + next_cpi_y = CPI_Y_3000; + break; + } + default: { + current_cpi = DEFAULT_CPI_TICK; + next_cpi_x = CPI_X_800; + next_cpi_y = CPI_Y_800; + break; + } + } + + paw3805ek_reg_seq_t cpi_reg_seq[] = { + {0x09 | WRITE_REG_BIT, 0x5A}, // Disable write protection + {0x0D | WRITE_REG_BIT, next_cpi_x}, + {0x0E | WRITE_REG_BIT, next_cpi_y}, + {0x09 | WRITE_REG_BIT, 0x00}, // Enable the write protection + }; + + for (uint8_t i = 0; i < sizeof(cpi_reg_seq) / sizeof(paw3805ek_reg_seq_t); i++) { + uint8_t buf[3]; + buf[0] = NCS_PIN; + buf[1] = cpi_reg_seq[i].reg; + buf[2] = cpi_reg_seq[i].data; + if (sci18is606_spi_tx(buf, 3, true) != I2C_STATUS_SUCCESS) { + return false; + } + } + + return true; +} + +bool paw3805ek_configure(void) { + for (uint8_t i = 0; i < sizeof(paw3805ek_configure_seq) / sizeof(paw3805ek_reg_seq_t); i++) { + uint8_t buf[3]; + buf[0] = NCS_PIN; + buf[1] = paw3805ek_configure_seq[i].reg; + buf[2] = paw3805ek_configure_seq[i].data; + if (sci18is606_spi_tx(buf, 3, true) != I2C_STATUS_SUCCESS) { + return false; + } + // Wait for the sensor to restart after the software reset cmd + wait_ms(1); + + // Check the sensor ID to validate the spi link after the reset + if (i == 1 && buf[1] != PAW3805EK_ID) { + return false; + } + } + + return true; +} + +bool paw3805ek_has_motion(void) { + uint8_t motion[3] = {0x01, 0x02, 0x00}; + if (sci18is606_spi_tx(motion, 3, true) != I2C_STATUS_SUCCESS) { + return false; + } + return motion[1] & 0x80; +} + +void paw3804ek_read_motion(report_mouse_t *mouse_report) { +#ifdef MOUSE_EXTENDED_REPORT + uint8_t delta_x_l[2] = {0x01, 0x03}; + if (sci18is606_spi_tx(delta_x_l, 3, true) != I2C_STATUS_SUCCESS) { + return; + } + + uint8_t delta_y_l[2] = {0x01, 0x04}; + if (sci18is606_spi_tx(delta_y_l, 3, true) != I2C_STATUS_SUCCESS) { + return; + } + + uint8_t delta_x_h[2] = {0x01, 0x11}; + if (sci18is606_spi_tx(delta_x_h, 3, true) != I2C_STATUS_SUCCESS) { + return; + } + + uint8_t delta_y_h[2] = {0x01, 0x12}; + if (sci18is606_spi_tx(delta_y_h, 3, true) != I2C_STATUS_SUCCESS) { + return; + } + + mouse_report->x = (int16_t)((delta_x_h[1] << 8) | delta_x_l[1]); + mouse_report->y = (int16_t)((delta_y_h[1] << 8) | delta_y_l[1]); +#else + uint8_t delta_x[2] = {0x01, 0x03}; + if (sci18is606_spi_tx(delta_x, 3, true) != I2C_STATUS_SUCCESS) { + return; + } + + uint8_t delta_y[2] = {0x01, 0x04}; + if (sci18is606_spi_tx(delta_y, 3, true) != I2C_STATUS_SUCCESS) { + return; + } + + mouse_report->x = delta_x[1]; + mouse_report->y = delta_y[1]; +#endif +} + +uint32_t sci18is606_read_callback(uint32_t trigger_time, void *cb_arg) { + if (!trackball_init) { + navigator_trackball_device_init(); + return NAVIGATOR_TRACKBALL_PROBE; + } + if (paw3805ek_has_motion()) { + has_motion = 1; + } + return NAVIGATOR_TRACKBALL_READ; +} + +void navigator_trackball_device_init(void) { + i2c_init(); + if (sci18is606_configure() == I2C_STATUS_SUCCESS) { + paw3805ek_configure(); + } else { + return; + } + + trackball_init = 1; + if (!callback_token) { + // Register the callback to read the trackball motion + callback_token = defer_exec(NAVIGATOR_TRACKBALL_READ, sci18is606_read_callback, NULL); + } +} + +report_mouse_t navigator_trackball_get_report(report_mouse_t mouse_report) { + if (!trackball_init) { + return mouse_report; + } + + if (has_motion) { + has_motion = 0; + paw3804ek_read_motion(&mouse_report); + } + return mouse_report; +} + +uint16_t navigator_trackball_get_cpi(void) { + return current_cpi; +} + +void restore_cpi(uint8_t cpi) { + current_cpi = cpi; + paw3805ek_set_cpi(); +} + +void navigator_trackball_set_cpi(uint16_t cpi) { + if (cpi == 0) { // Decrease one tick + if (current_cpi > 1) { + current_cpi--; + paw3805ek_set_cpi(); + } + } else { + if (current_cpi < CPI_TICKS) { + current_cpi++; + paw3805ek_set_cpi(); + } + } +}; diff --git a/drivers/sensors/navigator_trackball.h b/drivers/sensors/navigator_trackball.h new file mode 100644 index 0000000000..6e4aa72349 --- /dev/null +++ b/drivers/sensors/navigator_trackball.h @@ -0,0 +1,67 @@ +#pragma once +#include +#include + +#ifndef NAVIGATOR_TRACKBALL_ADDRESS +# define NAVIGATOR_TRACKBALL_ADDRESS 0x50 +#endif + +#ifndef NAVIGATOR_TRACKBALL_TIMEOUT +# define NAVIGATOR_TRACKBALL_TIMEOUT 100 +#endif + +#define NAVIGATOR_TRACKBALL_READ 7 +#define NAVIGATOR_TRACKBALL_PROBE 1000 + +#define NCS_PIN 0x01 +#define PAW3805EK_ID 0x31 + +#define SCI18IS606_CONF 0xDC //00001110b // MSB first, Mode 3, 155kHz + +#define SCI18IS606_RW_SPI 0x00 +#define SCI18IS606_CONF_SPI 0xF0 +#define SCI18IS606_CLR_INT 0xF1 +#define SCI18IS606_GET_ID 0xFE + +#define WRITE_REG_BIT 0x80 + +/* +The PAW3805EK datasheet suggests the following CPI values for the X and Y axes: +CPI X-axis Y-axis +800 0x1F 0x22 +1000 0x26 0x2A +1200 0x2E 0x32 +1600 0x3C 0x43 +2000 0x4C 0x54 +2400 0x5B 0x64 +3000 0x70 0x7B +*/ +#define CPI_TICKS 7 +#define DEFAULT_CPI_TICK 1 +#define CPI_X_800 0x1F +#define CPI_Y_800 0x22 +#define CPI_X_1000 0x26 +#define CPI_Y_1000 0x2A +#define CPI_X_1200 0x2E +#define CPI_Y_1200 0x32 +#define CPI_X_1600 0x3C +#define CPI_Y_1600 0x43 +#define CPI_X_2000 0x4C +#define CPI_Y_2000 0x54 +#define CPI_X_2400 0x5B +#define CPI_Y_2400 0x64 +#define CPI_X_3000 0x70 +#define CPI_Y_3000 0x7B + +typedef struct { + uint8_t reg; + uint8_t data; +} paw3805ek_reg_seq_t; + +const pointing_device_driver_t navigator_trackball_pointing_device_driver; + +void navigator_trackball_device_init(void); +report_mouse_t navigator_trackball_get_report(report_mouse_t mouse_report); +uint16_t navigator_trackball_get_cpi(void); +void navigator_trackball_set_cpi(uint16_t cpi); +void restore_cpi(uint8_t cpi); diff --git a/drivers/sensors/navigator_trackpad.c b/drivers/sensors/navigator_trackpad.c new file mode 100644 index 0000000000..e39d95648f --- /dev/null +++ b/drivers/sensors/navigator_trackpad.c @@ -0,0 +1,477 @@ +#include +#include +#include "navigator_trackpad.h" +#include "i2c_master.h" +#include "quantum.h" +#include "timer.h" + +const pointing_device_driver_t navigator_trackpad_pointing_device_driver = { + .init = navigator_trackpad_device_init, + .get_report = navigator_trackpad_get_report, + .get_cpi = navigator_trackpad_get_cpi, + .set_cpi = navigator_trackpad_set_cpi +}; + +uint16_t current_cpi = DEFAULT_CPI_TICK; +uint32_t gpio_offset_addr; +uint8_t has_motion = 0; +uint8_t scroll_debounce = 0; + +bool touchpad_init; + +#if defined(NAVIGATOR_TRACKPAD_PTP_MODE) +cgen6_report_t ptp_report; +bool prev_ptp_flag, prev_tap_clear = false; +uint8_t last_contact_count = 0; +uint16_t prev_ptp_x, prev_ptp_y; +uint16_t tap_timer = 0; +int16_t ptp_delta_x, ptp_delta_y; +#endif + +i2c_status_t cirque_gen6_read_report(uint8_t *data, uint16_t cnt) { + i2c_status_t res = i2c_receive(NAVIGATOR_TRACKPAD_ADDRESS, data, cnt, NAVIGATOR_TRACKPAD_TIMEOUT); + wait_us(cnt * 15); + return res; +} + +void cirque_gen6_clear(void) { + uint8_t buf[CGEN6_MAX_PACKET_SIZE]; + for (uint8_t i = 0; i < 5; i++) { + wait_ms(1); + if (cirque_gen6_read_report(buf, CGEN6_MAX_PACKET_SIZE) != I2C_STATUS_SUCCESS) { + break; + } + } +} + +uint8_t cirque_gen6_read_memory(uint32_t addr, uint8_t *data, uint16_t cnt) { + uint8_t cksum = 0; + uint8_t res = CGEN6_SUCCESS; + uint8_t len[2]; + uint16_t read = 0; + + uint8_t preamble[8] = {0x01, 0x09, (uint8_t)(addr & (uint32_t)0x000000FF), (uint8_t)((addr & 0x0000FF00) >> 8), (uint8_t)((addr & 0x00FF0000) >> 16), (uint8_t)((addr & 0xFF000000) >> 24), (uint8_t)(cnt & 0x00FF), (uint8_t)((cnt & 0xFF00) >> 8)}; + + // Read the length of the data + 3 bytes (first 2 bytes for the length and the last byte for the checksum) + // Create a buffer to store the data + uint8_t buf[cnt + 3]; + if (i2c_transmit_and_receive(NAVIGATOR_TRACKPAD_ADDRESS, preamble, 8, buf, cnt + 3, NAVIGATOR_TRACKPAD_TIMEOUT) != I2C_STATUS_SUCCESS) { + res |= CGEN6_I2C_FAILED; + } + + // Read the data length + for (uint8_t i = 0; i < 2; i++) { + cksum += len[i] = buf[i]; + read++; + } + + // Populate the data buffer + for (uint16_t i = 2; i < cnt + 2; i++) { + cksum += data[i - 2] = buf[i]; + read++; + } + + // Check the checksum + if (cksum != buf[read]) { + res |= CGEN6_CKSUM_FAILED; + } + + // Check the length (incremented first to account for the checksum) + if (++read != (len[0] | (len[1] << 8))) { + res |= CGEN6_LEN_MISMATCH; + } + + wait_ms(1); + + return res; +} + +uint8_t cirque_gen6_write_memory(uint32_t addr, uint8_t *data, uint16_t cnt) { + uint8_t res = CGEN6_SUCCESS; + uint8_t cksum = 0, i = 0; + uint8_t preamble[8] = {0x00, 0x09, (uint8_t)(addr & 0x000000FF), (uint8_t)((addr & 0x0000FF00) >> 8), (uint8_t)((addr & 0x00FF0000) >> 16), (uint8_t)((addr & 0xFF000000) >> 24), (uint8_t)(cnt & 0x00FF), (uint8_t)((cnt & 0xFF00) >> 8)}; + + uint8_t buf[cnt + 9]; + // Calculate the checksum + for (; i < 8; i++) { + cksum += buf[i] = preamble[i]; + } + + for (i = 0; i < cnt; i++) { + cksum += buf[i + 8] = data[i]; + } + + buf[cnt + 8] = cksum; + + if (i2c_transmit(NAVIGATOR_TRACKPAD_ADDRESS, buf, cnt + 9, NAVIGATOR_TRACKPAD_TIMEOUT) != I2C_STATUS_SUCCESS) { + res |= CGEN6_I2C_FAILED; + } + + wait_ms(1); + + return res; +} + +uint8_t cirque_gen6_read_reg(uint32_t addr) { + uint8_t data; + uint8_t res = cirque_gen6_read_memory(addr, &data, 1); + if (res != CGEN6_SUCCESS) { + printf("Failed to read 8bits from register at address 0x%08X with error 0x%02X\n", (u_int)addr, res); + return 0; + } + return data; +} + +uint16_t cirque_gen6_read_reg_16(uint32_t addr) { + uint8_t buf[2]; + uint8_t res = cirque_gen6_read_memory(addr, buf, 2); + if (res != CGEN6_SUCCESS) { + printf("Failed to read 16bits from register at address 0x%08X with error 0x%02X\n", (u_int)addr, res); + return 0; + } + return (buf[1] << 8) | buf[0]; +} + +uint32_t cirque_gen6_read_reg_32(uint32_t addr) { + uint8_t buf[4]; + uint8_t res = cirque_gen6_read_memory(addr, buf, 4); + if (res != CGEN6_SUCCESS) { + printf("Failed to read 32bits from register at address 0x%08X with error 0x%02X\n", (u_int)addr, res); + return 0; + } + return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; +} + +uint8_t cirque_gen6_write_reg(uint32_t addr, uint8_t data) { + return cirque_gen6_write_memory(addr, &data, 1); +} + +uint8_t cirque_gen6_write_reg_16(uint32_t addr, uint16_t data) { + uint8_t buf[2] = {data & 0xFF, (data >> 8) & 0xFF}; + return cirque_gen6_write_memory(addr, buf, 2); +} + +uint8_t cirque_gen6_write_reg_32(uint32_t addr, uint32_t data) { + uint8_t buf[4] = {data & 0xFF, (data >> 8) & 0xFF, (data >> 16) & 0xFF, (data >> 24) & 0xFF}; + return cirque_gen6_write_memory(addr, buf, 4); +} + +uint8_t cirque_gen6_set_relative_mode(void) { + uint8_t feed_config4 = cirque_gen6_read_reg(CGEN6_FEED_CONFIG4); + feed_config4 &= 0xF3; + return cirque_gen6_write_reg(CGEN6_FEED_CONFIG4, feed_config4); +} + +uint8_t cirque_gen6_set_ptp_mode(void) { + uint8_t feed_config4 = cirque_gen6_read_reg(CGEN6_FEED_CONFIG4); + feed_config4 &= 0xF7; + feed_config4 |= 0x04; + return cirque_gen6_write_reg(CGEN6_FEED_CONFIG4, feed_config4); +} + +uint8_t cirque_gen6_swap_xy(bool set) { + uint8_t xy_config = cirque_gen6_read_reg(CGEN6_XY_CONFIG); + if (set) { + xy_config |= 0x04; + } else { + xy_config &= ~0x04; + } + return cirque_gen6_write_reg(CGEN6_XY_CONFIG, xy_config); +} + +uint8_t cirque_gen6_invert_y(bool set) { + uint8_t xy_config = cirque_gen6_read_reg(CGEN6_XY_CONFIG); + if (set) { + xy_config |= 0x02; + } else { + xy_config &= ~0x02; + } + return cirque_gen6_write_reg(CGEN6_XY_CONFIG, xy_config); +} + +uint8_t cirque_gen6_invert_x(bool set) { + uint8_t xy_config = cirque_gen6_read_reg(CGEN6_XY_CONFIG); + if (set) { + xy_config |= 0x01; + } else { + xy_config &= ~0x01; + } + return cirque_gen6_write_reg(CGEN6_XY_CONFIG, xy_config); +} + +uint8_t cirque_gen6_enable_logical_scaling(bool set) { + uint8_t xy_config = cirque_gen6_read_reg(CGEN6_XY_CONFIG); + if (set) { + xy_config &= ~0x08; + } else { + xy_config |= ~0x08; + } + return cirque_gen6_write_reg(CGEN6_XY_CONFIG, xy_config); +} + +bool cirque_gen6_get_gpio_state(uint8_t num) { + uint32_t gpio_states = cirque_gen6_read_reg_32(0x43000000 + gpio_offset_addr + 0x0004); + return ((gpio_states >> num) & 0x000000001); +} + +uint32_t cirque_gen_6_read_callback(uint32_t trigger_time, void *cb_arg) { + if (has_motion) { + return NAVIGATOR_TRACKPAD_READ; + } + uint8_t packet[CGEN6_MAX_PACKET_SIZE]; + if (cirque_gen6_read_report(packet, CGEN6_MAX_PACKET_SIZE) != I2C_STATUS_SUCCESS) { + return false; + } + + uint8_t report_id = packet[2]; +#if defined(NAVIGATOR_TRACKPAD_PTP_MODE) + if (report_id == CGEN6_PTP_REPORT_ID) { + ptp_report.confidence = packet[3] & 0x01; + ptp_report.tip = (packet[3] & 0x02) >> 1; + ptp_report.id = (packet[3] & 0xFC) >> 2; + ptp_report.x = packet[5] << 8 | packet[4]; + ptp_report.y = packet[7] << 8 | packet[6]; + ptp_report.ts = packet[9] << 8 | packet[10]; + ptp_report.contact_count = packet[11]; + ptp_report.buttons = packet[12]; + + has_motion = 1; + } +#endif +#if defined(NAVIGATOR_TRACKPAD_RELATIVE_MODE) + if (report_id == CGEN6_MOUSE_REPORT_ID) { + ptp_report.buttons = packet[3]; + ptp_report.xDelta = packet[4]; + ptp_report.yDelta = packet[5]; + amree ptp_report.scrollDelta = packet[6]; + ptp_report.panDelta = packet[7]; + + has_motion = 1; + } +#endif + return NAVIGATOR_TRACKPAD_READ; +} + +void navigator_trackpad_device_init(void) { + i2c_init(); + + i2c_status_t status = i2c_ping_address(NAVIGATOR_TRACKPAD_ADDRESS, NAVIGATOR_TRACKPAD_TIMEOUT); + + if (status != I2C_STATUS_SUCCESS) { + printf("Failed to ping touchpad\n"); + touchpad_init = false; + return; + } + + cirque_gen6_clear(); + + wait_ms(50); + + uint8_t resSize = cirque_gen6_write_reg(0x2001080C, 16); + resSize = cirque_gen6_write_reg(0x2001080D, 16); + + if (resSize != CGEN6_SUCCESS) { + printf("Failed to set touchpad size\n"); + } + + uint8_t sizeX = cirque_gen6_read_reg(0x2001080C); + uint8_t sizeY = cirque_gen6_read_reg(0x2001080D); + + printf("Touchpad size: %d x %d\n", sizeX, sizeY); + +#if defined(NAVIGATOR_TRACKPAD_DEBUG) + uint8_t hardwareId = cirque_gen6_read_reg(CGEN6_HARDWARE_ID); + uint8_t firmwareId = cirque_gen6_read_reg(CGEN6_FIRMWARE_ID); + uint16_t vendorId = cirque_gen6_read_reg_16(CGEN6_VENDOR_ID); + uint16_t productId = cirque_gen6_read_reg_16(CGEN6_PRODUCT_ID); + uint16_t versionId = cirque_gen6_read_reg_16(CGEN6_FIRMWARE_REV); + uint32_t firmwareRev = cirque_gen6_read_reg_32(CGEN6_FIRMWARE_REV); + + printf("Touchpad Hardware ID: 0x%02X\n", hardwareId); + printf("Touchpad Firmware ID: 0x%02X\n", firmwareId); + printf("Touchpad Vendor ID: 0x%04X\n", vendorId); + printf("Touchpad Product ID: 0x%04X\n", productId); + printf("Touchpad Version ID: 0x%04X\n", versionId); + + uint32_t revision = firmwareRev & 0x00ffffff; + bool uncommittedVersion = firmwareRev & 0x80000000; + bool branchVersion = firmwareRev & 0x40000000; + uint8_t developerId = firmwareRev & 0x3f000000; + + printf("Touchpad Firmware Revision: 0x%08X\n", (u_int)revision); + printf("Touchpad Uncommitted Version: %s\n", uncommittedVersion ? "true" : "false"); + printf("Touchpad Branch Version: %s\n", branchVersion ? "true" : "false"); + printf("Touchpad Developer ID: %d\n", developerId); +#endif + +#if defined(NAVIGATOR_TRACKPAD_PTP_MODE) + uint8_t res = cirque_gen6_set_ptp_mode(); +#endif +#if defined(NAVIGATOR_TRACKPAD_RELATIVE_MODE) + uint8_t res = cirque_gen6_set_relative_mode(); +#endif + + if (res != CGEN6_SUCCESS) { + return; + } + + // Reset to the default alignment + cirque_gen6_swap_xy(false); + cirque_gen6_invert_x(false); + cirque_gen6_invert_y(false); + cirque_gen6_swap_xy(true); + cirque_gen6_invert_x(true); + cirque_gen6_invert_y(true); + cirque_gen6_enable_logical_scaling(true); + + touchpad_init = true; + defer_exec(NAVIGATOR_TRACKPAD_READ, cirque_gen_6_read_callback, NULL); +} + +report_mouse_t navigator_trackpad_get_report(report_mouse_t mouse_report) { + if (!has_motion || !touchpad_init) { + if (prev_tap_clear) { + prev_tap_clear = false; + mouse_report.buttons = 0; + } + return mouse_report; + } + +#if defined(NAVIGATOR_TRACKPAD_RELATIVE_MODE) + mouse_report.x = ptp_report.xDelta; + mouse_report.y = ptp_report.yDelta; + mouse_report.v = ptp_report.scrollDelta; + mouse_report.h = ptp_report.panDelta; + mouse_report.buttons = ptp_report.buttons; +#endif +#if defined(NAVIGATOR_TRACKPAD_PTP_MODE) + if (!prev_ptp_flag && ptp_report.tip) { // Beginning of a motion + prev_ptp_x = ptp_report.x; + prev_ptp_y = ptp_report.y; + prev_ptp_flag = true; + tap_timer = timer_read(); + scroll_debounce = 1; + } else if (!ptp_report.tip) { // End of a motion + prev_ptp_flag = false; + if (timer_elapsed(tap_timer) < NAVIGATOR_TRACKPAD_TAPPING_TERM) { // Register a tap or double tap + if (last_contact_count > 0) { +# ifdef NAVIGATOR_TRACKPAD_ENABLE_DOUBLE_TAP + mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON2); +# endif + } else { +# ifdef NAVIGATOR_TRACKPAD_ENABLE_TAP + mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON1); +# endif + } + prev_tap_clear = true; + } + } else { + if (timer_elapsed(tap_timer) >= NAVIGATOR_TRACKPAD_TAP_DEBOUNCE) { + ptp_delta_x = ptp_report.x - prev_ptp_x; + ptp_delta_y = ptp_report.y - prev_ptp_y; + if (ptp_report.contact_count > 0) { // More than one finger, return scroll motions + if (scroll_debounce == 0) { + scroll_debounce = 1; + if (ptp_delta_y && abs(ptp_delta_y) > abs(ptp_delta_x)) { + uint8_t scroll_v; + if (ptp_delta_y > 0) { + scroll_v = 1; + } else { + scroll_v = -1; + } +# ifdef NAVIGATOR_SCROLL_INVERT + mouse_report.v = (int8_t)(scroll_v); +# else + mouse_report.v = (int8_t)(-scroll_v); +# endif + } + if (ptp_delta_x && abs(ptp_delta_x) > abs(ptp_delta_y)) { + if (ptp_delta_x > 0) { + mouse_report.h = 1; + } else { + mouse_report.h = -1; + } + } + mouse_report.x = 0; + mouse_report.y = 0; + } else { + scroll_debounce++; + if (scroll_debounce > NAVIGATOR_TRACKPAD_SCROLL_DEBOUNCE) { + scroll_debounce = 0; + } + } + } else { + mouse_report.x = ptp_delta_x; + mouse_report.y = ptp_delta_y; + } + + prev_ptp_x = ptp_report.x; + prev_ptp_y = ptp_report.y; + } + last_contact_count = ptp_report.contact_count; + } +#endif + has_motion = 0; + return mouse_report; +} + +void set_cirque_cpi(void) { + // traverse the sequence by compairing the cpi_x value with the current cpi_x value + // set the cpi to the next value in the sequence + switch (current_cpi) { + case CPI_1: { + current_cpi = CPI_2; + break; + } + case CPI_2: { + current_cpi = CPI_3; + break; + } + case CPI_3: { + current_cpi = CPI_4; + break; + } + case CPI_4: { + current_cpi = CPI_5; + break; + } + case CPI_5: { + current_cpi = CPI_6; + break; + } + case CPI_6: { + current_cpi = CPI_7; + break; + } + case CPI_7: { + current_cpi = CPI_1; + break; + } + default: { + current_cpi = CPI_4; + break; + } + } +} + +uint16_t navigator_trackpad_get_cpi(void) { + return current_cpi; +} + +void restore_cpi(uint8_t cpi) { + current_cpi = cpi; + set_cirque_cpi(); +} + +void navigator_trackpad_set_cpi(uint16_t cpi) { + if (cpi == 0) { // Decrease one tick + if (current_cpi > 1) { + current_cpi--; + } + } else { + if (current_cpi < CPI_TICKS) { + current_cpi++; + } + } + set_cirque_cpi(); +}; diff --git a/drivers/sensors/navigator_trackpad.h b/drivers/sensors/navigator_trackpad.h new file mode 100644 index 0000000000..bf0a3dffb0 --- /dev/null +++ b/drivers/sensors/navigator_trackpad.h @@ -0,0 +1,134 @@ +#pragma once +#include +#include +#include "report.h" + +# ifndef CIRQUE_PINNACLE_X_LOWER +# define CIRQUE_PINNACLE_X_LOWER 127 // min "reachable" X value +# endif +# ifndef CIRQUE_PINNACLE_X_UPPER +# define CIRQUE_PINNACLE_X_UPPER 1919 // max "reachable" X value +# endif +# ifndef CIRQUE_PINNACLE_Y_LOWER +# define CIRQUE_PINNACLE_Y_LOWER 63 // min "reachable" Y value +# endif +# ifndef CIRQUE_PINNACLE_Y_UPPER +# define CIRQUE_PINNACLE_Y_UPPER 1471 // max "reachable" Y value +# endif +# ifndef CIRQUE_PINNACLE_X_RANGE +# define CIRQUE_PINNACLE_X_RANGE (CIRQUE_PINNACLE_X_UPPER - CIRQUE_PINNACLE_X_LOWER) +# endif +# ifndef CIRQUE_PINNACLE_Y_RANGE +# define CIRQUE_PINNACLE_Y_RANGE (CIRQUE_PINNACLE_Y_UPPER - CIRQUE_PINNACLE_Y_LOWER) +# endif + +#define NAVIGATOR_TRACKPAD_READ 7 +#define NAVIGATOR_TRACKPAD_TAPPING_TERM 200 +#define NAVIGATOR_TRACKPAD_TAP_DEBOUNCE 100 +#ifndef NAVIGATOR_TRACKPAD_SCROLL_DEBOUNCE +// The scroll debounce is the number of read cycles it takes to register a scroll event. Each read cycle is set to #NAVIGATOR_TRACKPAD_READ +#define NAVIGATOR_TRACKPAD_SCROLL_DEBOUNCE 3 +#endif + +#ifndef NAVIGATOR_TRACKPAD_ADDRESS +# define NAVIGATOR_TRACKPAD_ADDRESS 0x58 +#endif + +#ifndef NAVIGATOR_TRACKPAD_TIMEOUT +# define NAVIGATOR_TRACKPAD_TIMEOUT 100 +#endif + +#define NAVIGATOR_TRACKPAD_PTP_MODE +#if !defined(NAVIGATOR_TRACKPAD_RELATIVE_MODE) && !defined(NAVIGATOR_TRACKPAD_PTP_MODE) +# define NAVIGATOR_TRACKPAD_PTP_MODE +#endif + +#define CGEN6_MAX_PACKET_SIZE 53 +#define CGEN6_PTP_REPORT_ID 0x01 +#define CGEN6_MOUSE_REPORT_ID 0x06 +#define CGEN6_ABSOLUTE_REPORT_ID 0x09 + +// C3 error codes when reading memory +#define CGEN6_SUCCESS 0x00 +#define CGEN6_CKSUM_FAILED 0x01 +#define CGEN6_LEN_MISMATCH 0x02 +#define CGEN6_I2C_FAILED 0x03 + +// C3 register addresses +#define CGEN6_REG_BASE 0x20000800 +#define CGEN6_HARDWARE_ID CGEN6_REG_BASE + 0x08 +#define CGEN6_FIRMWARE_ID CGEN6_REG_BASE + 0x09 +#define CGEN6_FIRMWARE_REV CGEN6_REG_BASE + 0x10 +#define CGEN6_VENDOR_ID CGEN6_REG_BASE + 0x0A +#define CGEN6_PRODUCT_ID CGEN6_REG_BASE + 0x0C +#define CGEN6_VERSION_ID CGEN6_REG_BASE + 0x0E +#define CGEN6_FEED_CONFIG4 0x200E000B +#define CGEN6_FEED_CONFIG3 0x200E000A +#define CGEN6_SYS_CONFIG1 0x20000008 +#define CGEN6_XY_CONFIG 0x20080018 +#define CGEN6_SFR_BASE 0x40000008 +#define CGEN6_GPIO_BASE 0x00052000 + +#define CPI_TICKS 7 +#define DEFAULT_CPI_TICK 4 +#define CPI_1 200 +#define CPI_2 400 +#define CPI_3 800 +#define CPI_4 1024 +#define CPI_5 1400 +#define CPI_6 1800 +#define CPI_7 2048 + +#define CONSTRAIN_HID_XY(amt) ((amt) < XY_REPORT_MIN ? XY_REPORT_MIN : ((amt) > XY_REPORT_MAX ? XY_REPORT_MAX : (amt))) + +#ifndef NAVIGATOR_TRACKPAD_SCROLL_DIVIDER +# define NAVIGATOR_TRACKPAD_SCROLL_DIVIDER 10 +#endif + +#if defined(NAVIGATOR_TRACKPAD_PTP_MODE) +# ifndef MOUSE_EXTENDED_REPORT +# define MOUSE_EXTENDED_REPORT +# endif +typedef struct { + uint16_t x; + uint16_t y; + uint16_t ts; + uint8_t id; + uint8_t confidence; + uint8_t tip; + uint8_t contact_count; + uint8_t buttons; +} cgen6_report_t; +#endif + +#if defined(NAVIGATOR_TRACKPAD_ABSOLUTE_MODE) +typedef struct { + uint16_t x; + uint16_t y; + uint8_t palm; + uint8_t z; +} finger_data_t; + +typedef struct { + finger_data_t fingers[3]; // Cirque support 5 fingers, we only need 3 for our application + uint8_t contact_flags; + uint8_t buttons; +} cgen6_report_t; +#endif + +#if defined(NAVIGATOR_TRACKPAD_RELATIVE_MODE) +typedef struct { + uint8_t buttons; + int8_t xDelta; + int8_t yDelta; + int8_t scrollDelta; + int8_t panDelta; +} cgen6_report_t; +#endif + +const pointing_device_driver_t navigator_trackpad_pointing_device_driver; +void navigator_trackpad_device_init(void); +report_mouse_t navigator_trackpad_get_report(report_mouse_t mouse_report); +uint16_t navigator_trackpad_get_cpi(void); +void navigator_trackpad_set_cpi(uint16_t cpi); +void restore_cpi(uint8_t cpi); diff --git a/keyboards/zsa/ergodox_ez/ergodox_ez.c b/keyboards/zsa/ergodox_ez/ergodox_ez.c index 9e0aedc28a..214861620a 100644 --- a/keyboards/zsa/ergodox_ez/ergodox_ez.c +++ b/keyboards/zsa/ergodox_ez/ergodox_ez.c @@ -25,6 +25,9 @@ along with this program. If not, see . #ifdef COMMUNITY_MODULE_ORYX_ENABLE # include "oryx.h" #endif // COMMUNITY_MODULE_ORYX_ENABLE +#ifdef COMMUNITY_MODULE_DEFAULTS_ENABLE +# include "defaults.h" +#endif keyboard_config_t keyboard_config; diff --git a/keyboards/zsa/ergodox_ez/ergodox_ez.h b/keyboards/zsa/ergodox_ez/ergodox_ez.h index cc3e1c6cb4..cf29bdf646 100644 --- a/keyboards/zsa/ergodox_ez/ergodox_ez.h +++ b/keyboards/zsa/ergodox_ez/ergodox_ez.h @@ -63,17 +63,12 @@ void ergodox_led_all_set(uint8_t n); # define LED_BRIGHTNESS_HI 255 #endif -enum ergodox_ez_keycodes { - LED_LEVEL = QK_KB, - TOGGLE_LAYER_COLOR, - EZ_SAFE_RANGE -}; - typedef union { uint32_t raw; struct { uint8_t led_level : 3; bool disable_layer_led : 1; + uint8_t navigator_cpi : 3; bool placeholder : 1; }; } keyboard_config_t; diff --git a/keyboards/zsa/moonlander/moonlander.c b/keyboards/zsa/moonlander/moonlander.c index fa76895b83..9ecd0109e4 100644 --- a/keyboards/zsa/moonlander/moonlander.c +++ b/keyboards/zsa/moonlander/moonlander.c @@ -22,6 +22,10 @@ # include "oryx.h" #endif // COMMUNITY_MODULE_ORYX_ENABLE +#ifdef COMMUNITY_MODULE_DEFAULTS_ENABLE +# include "defaults.h" +#endif + keyboard_config_t keyboard_config; bool mcp23018_leds[3] = {0, 0, 0}; @@ -463,6 +467,7 @@ void eeconfig_init_kb(void) { // EEPROM is getting reset! keyboard_config.rgb_matrix_enable = true; keyboard_config.led_level = true; keyboard_config.led_level_res = 0b11; + keyboard_config.navigator_cpi = 3; eeconfig_update_kb(keyboard_config.raw); eeconfig_init_user(); } diff --git a/keyboards/zsa/moonlander/moonlander.h b/keyboards/zsa/moonlander/moonlander.h index 136e07fc72..27838cc0a3 100644 --- a/keyboards/zsa/moonlander/moonlander.h +++ b/keyboards/zsa/moonlander/moonlander.h @@ -14,9 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -*/ - - + */ #pragma once @@ -34,23 +32,19 @@ extern bool mcp23018_leds[]; #define STATUS_LED_5(status) mcp23018_leds[1] = (bool)status #define STATUS_LED_6(status) mcp23018_leds[2] = (bool)status -enum planck_ez_keycodes { - TOGGLE_LAYER_COLOR = QK_KB_0, - LED_LEVEL, -}; - #ifndef WEBUSB_ENABLE # define WEBUSB_PAIR KC_NO #endif typedef union { - uint32_t raw; - struct { - bool disable_layer_led :1; - bool rgb_matrix_enable :1; - bool led_level :1; - uint8_t led_level_res :2; // DO NOT REMOVE - }; + uint32_t raw; + struct { + bool disable_layer_led : 1; + bool rgb_matrix_enable : 1; + bool led_level : 1; + uint8_t led_level_res : 2; // DO NOT REMOVE + uint8_t navigator_cpi : 3; + }; } keyboard_config_t; extern keyboard_config_t keyboard_config; diff --git a/keyboards/zsa/planck_ez/planck_ez.c b/keyboards/zsa/planck_ez/planck_ez.c index 73fa45d1fd..b960d08696 100644 --- a/keyboards/zsa/planck_ez/planck_ez.c +++ b/keyboards/zsa/planck_ez/planck_ez.c @@ -23,6 +23,10 @@ #ifdef COMMUNITY_MODULE_ORYX_ENABLE # include "oryx.h" #endif // COMMUNITY_MODULE_ORYX_ENABLE + // +#ifdef COMMUNITY_MODULE_DEFAULTS_ENABLE +# include "defaults.h" +#endif keyboard_config_t keyboard_config; diff --git a/keyboards/zsa/planck_ez/planck_ez.h b/keyboards/zsa/planck_ez/planck_ez.h index 3beb349625..1d9dc3c762 100644 --- a/keyboards/zsa/planck_ez/planck_ez.h +++ b/keyboards/zsa/planck_ez/planck_ez.h @@ -26,12 +26,6 @@ void planck_ez_left_led_on(void); void planck_ez_left_led_off(void); void planck_ez_left_led_level(uint8_t level); -enum planck_ez_keycodes { - LED_LEVEL = QK_KB_0, - TOGGLE_LAYER_COLOR, - EZ_SAFE_RANGE -}; - #ifndef WEBUSB_ENABLE # define WEBUSB_PAIR KC_NO #endif diff --git a/keyboards/zsa/voyager/voyager.c b/keyboards/zsa/voyager/voyager.c index 24f05ea690..84d3eb095d 100644 --- a/keyboards/zsa/voyager/voyager.c +++ b/keyboards/zsa/voyager/voyager.c @@ -7,6 +7,10 @@ #ifdef COMMUNITY_MODULE_ORYX_ENABLE # include "oryx.h" #endif // COMMUNITY_MODULE_ORYX_ENABLE + // +#ifdef COMMUNITY_MODULE_DEFAULTS_ENABLE +# include "defaults.h" +#endif keyboard_config_t keyboard_config; @@ -296,6 +300,7 @@ void eeconfig_init_kb(void) { // EEPROM is getting reset! keyboard_config.raw = 0; keyboard_config.led_level = true; keyboard_config.led_level_res = 0b11; + keyboard_config.navigator_cpi = 3; eeconfig_update_kb(keyboard_config.raw); eeconfig_init_user(); } diff --git a/keyboards/zsa/voyager/voyager.h b/keyboards/zsa/voyager/voyager.h index a00cc995c6..5cb3f0cbc7 100644 --- a/keyboards/zsa/voyager/voyager.h +++ b/keyboards/zsa/voyager/voyager.h @@ -15,11 +15,6 @@ extern bool mcp23018_leds[]; #define STATUS_LED_3(status) mcp23018_leds[0] = (bool)(status) #define STATUS_LED_4(status) mcp23018_leds[1] = (bool)(status) -enum voyager_keycodes { - TOGGLE_LAYER_COLOR = QK_KB, - LED_LEVEL, -}; - typedef union { uint32_t raw; struct { @@ -27,6 +22,7 @@ typedef union { bool placeholder : 1; bool led_level : 1; uint8_t led_level_res : 2; // DO NOT REMOVE + uint8_t navigator_cpi : 3; }; } keyboard_config_t; diff --git a/modules/zsa b/modules/zsa index 480298e201..fa831253a1 160000 --- a/modules/zsa +++ b/modules/zsa @@ -1 +1 @@ -Subproject commit 480298e2018302120fa5f4a6eea6d4ecc88da99c +Subproject commit fa831253a1a7ebd7d1f6221f17b88b40f666e9e0 diff --git a/quantum/pointing_device/pointing_device.h b/quantum/pointing_device/pointing_device.h index 1559645619..e1bf69f436 100644 --- a/quantum/pointing_device/pointing_device.h +++ b/quantum/pointing_device/pointing_device.h @@ -74,6 +74,12 @@ typedef struct { # include "spi_master.h" # include "drivers/sensors/pmw33xx_common.h" # define POINTING_DEVICE_MOTION_PIN_ACTIVE_LOW +#elif defined(POINTING_DEVICE_DRIVER_navigator_trackball) +# include "i2c_master.h" +# include "drivers/sensors/navigator_trackball.h" +#elif defined(POINTING_DEVICE_DRIVER_navigator_trackpad) +# include "i2c_master.h" +# include "drivers/sensors/navigator_trackpad.h" #else void pointing_device_driver_init(void); report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report); From d9f419845d74ba411210c0b4324971ccd353577c Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Thu, 5 Jun 2025 19:56:35 +0700 Subject: [PATCH 03/14] feat: adds a transmit and receive i2c method --- drivers/i2c_master.h | 2 ++ platforms/chibios/drivers/i2c_master.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/drivers/i2c_master.h b/drivers/i2c_master.h index dbe1cd42fa..b36b5ef0df 100644 --- a/drivers/i2c_master.h +++ b/drivers/i2c_master.h @@ -42,6 +42,8 @@ void i2c_init(void); */ i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); +i2c_status_t i2c_transmit_and_receive(uint8_t address, const uint8_t* tx_data, uint16_t tx_length, uint8_t* rx_data, uint8_t rx_length, uint16_t timeout); + #if defined(__AVR__) || defined(__DOXYGEN__) /** * \brief Send multiple bytes from PROGMEM to the selected I2C device. diff --git a/platforms/chibios/drivers/i2c_master.c b/platforms/chibios/drivers/i2c_master.c index 20850859b5..9f9f6f321e 100644 --- a/platforms/chibios/drivers/i2c_master.c +++ b/platforms/chibios/drivers/i2c_master.c @@ -154,6 +154,12 @@ i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, return i2c_epilogue(status); } +i2c_status_t i2c_transmit_and_receive(uint8_t address, const uint8_t* tx_data, uint16_t tx_length, uint8_t* rx_data, uint8_t rx_length, uint16_t timeout) { + i2cStart(&I2C_DRIVER, &i2cconfig); + msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (address >> 1), tx_data, tx_length, rx_data, rx_length, TIME_MS2I(timeout)); + return i2c_epilogue(status); +} + i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) { i2cStart(&I2C_DRIVER, &i2cconfig); msg_t status = i2cMasterReceiveTimeout(&I2C_DRIVER, (address >> 1), data, length, TIME_MS2I(timeout)); From 9c0d3c5eb5735f1e82ac9573de7ab162751d55ef Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Thu, 5 Jun 2025 19:58:15 +0700 Subject: [PATCH 04/14] fix: navigator trackpad compile issue --- drivers/sensors/navigator_trackball.c | 1 - drivers/sensors/navigator_trackball.h | 1 + drivers/sensors/navigator_trackpad.h | 3 +-- modules/zsa | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/sensors/navigator_trackball.c b/drivers/sensors/navigator_trackball.c index 071a4c1333..e1b58c8d7f 100644 --- a/drivers/sensors/navigator_trackball.c +++ b/drivers/sensors/navigator_trackball.c @@ -1,5 +1,4 @@ #include "i2c_master.h" -#include "pointing_device.h" #include "navigator_trackball.h" #include #include diff --git a/drivers/sensors/navigator_trackball.h b/drivers/sensors/navigator_trackball.h index 6e4aa72349..2638edc6da 100644 --- a/drivers/sensors/navigator_trackball.h +++ b/drivers/sensors/navigator_trackball.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include "pointing_device.h" #ifndef NAVIGATOR_TRACKBALL_ADDRESS # define NAVIGATOR_TRACKBALL_ADDRESS 0x50 diff --git a/drivers/sensors/navigator_trackpad.h b/drivers/sensors/navigator_trackpad.h index bf0a3dffb0..dd184aa7a0 100644 --- a/drivers/sensors/navigator_trackpad.h +++ b/drivers/sensors/navigator_trackpad.h @@ -2,6 +2,7 @@ #include #include #include "report.h" +#include "pointing_device.h" # ifndef CIRQUE_PINNACLE_X_LOWER # define CIRQUE_PINNACLE_X_LOWER 127 // min "reachable" X value @@ -79,8 +80,6 @@ #define CPI_6 1800 #define CPI_7 2048 -#define CONSTRAIN_HID_XY(amt) ((amt) < XY_REPORT_MIN ? XY_REPORT_MIN : ((amt) > XY_REPORT_MAX ? XY_REPORT_MAX : (amt))) - #ifndef NAVIGATOR_TRACKPAD_SCROLL_DIVIDER # define NAVIGATOR_TRACKPAD_SCROLL_DIVIDER 10 #endif diff --git a/modules/zsa b/modules/zsa index fa831253a1..4a697850c8 160000 --- a/modules/zsa +++ b/modules/zsa @@ -1 +1 @@ -Subproject commit fa831253a1a7ebd7d1f6221f17b88b40f666e9e0 +Subproject commit 4a697850c8f5b6b09d710d94afcda0aa265025e0 From 996cf81b59db5c96410d5b454748281ee4530ddf Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Tue, 10 Jun 2025 17:21:15 +0700 Subject: [PATCH 05/14] feat: improved trackpad scrolling, maybe? --- builddefs/common_features.mk | 2 + drivers/sensors/navigator.c | 27 +++++++++ drivers/sensors/navigator.h | 4 ++ drivers/sensors/navigator_trackpad.c | 67 +++++++---------------- keyboards/zsa/ergodox_ez/ergodox_ez.c | 6 +- keyboards/zsa/moonlander/moonlander.c | 3 +- quantum/pointing_device/pointing_device.c | 4 +- quantum/pointing_device/pointing_device.h | 2 + 8 files changed, 60 insertions(+), 55 deletions(-) create mode 100644 drivers/sensors/navigator.c create mode 100644 drivers/sensors/navigator.h diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index 52b49277e4..a9119d844e 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk @@ -159,8 +159,10 @@ ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes) I2C_DRIVER_REQUIRED = yes else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), navigator_trackball) I2C_DRIVER_REQUIRED = yes + SRC += drivers/sensors/navigator.c else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), navigator_trackpad) I2C_DRIVER_REQUIRED = yes + SRC += drivers/sensors/navigator.c else ifneq ($(filter $(strip $(POINTING_DEVICE_DRIVER)),pmw3360 pmw3389),) SPI_DRIVER_REQUIRED = yes SRC += drivers/sensors/pmw33xx_common.c diff --git a/drivers/sensors/navigator.c b/drivers/sensors/navigator.c new file mode 100644 index 0000000000..6b020c1f23 --- /dev/null +++ b/drivers/sensors/navigator.c @@ -0,0 +1,27 @@ +#include "quantum.h" +#include "navigator.h" + +float scroll_accumulated_h = 0; +float scroll_accumulated_v = 0; + +bool set_scrolling = false; + +report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { + if (set_scrolling) { + scroll_accumulated_h += (float)mouse_report.x / NAVIGATOR_SCROLL_DIVIDER; + scroll_accumulated_v += (float)mouse_report.y / NAVIGATOR_SCROLL_DIVIDER; + mouse_report.h = (int8_t)scroll_accumulated_h; +#ifdef NAVIGATOR_SCROLL_INVERT + mouse_report.v = (int8_t)-scroll_accumulated_v; +#else + mouse_report.v = (int8_t)scroll_accumulated_v; +#endif + + scroll_accumulated_h -= (int8_t)scroll_accumulated_h; + scroll_accumulated_v -= (int8_t)scroll_accumulated_v; + + mouse_report.x = 0; + mouse_report.y = 0; + } + return mouse_report; +} diff --git a/drivers/sensors/navigator.h b/drivers/sensors/navigator.h new file mode 100644 index 0000000000..cf8639156c --- /dev/null +++ b/drivers/sensors/navigator.h @@ -0,0 +1,4 @@ +#pragma once +#ifndef NAVIGATOR_SCROLL_DIVIDER +# define NAVIGATOR_SCROLL_DIVIDER 10 +#endif diff --git a/drivers/sensors/navigator_trackpad.c b/drivers/sensors/navigator_trackpad.c index e39d95648f..98932e5435 100644 --- a/drivers/sensors/navigator_trackpad.c +++ b/drivers/sensors/navigator_trackpad.c @@ -6,18 +6,17 @@ #include "timer.h" const pointing_device_driver_t navigator_trackpad_pointing_device_driver = { - .init = navigator_trackpad_device_init, + .init = navigator_trackpad_device_init, .get_report = navigator_trackpad_get_report, - .get_cpi = navigator_trackpad_get_cpi, - .set_cpi = navigator_trackpad_set_cpi + .get_cpi = navigator_trackpad_get_cpi, + .set_cpi = navigator_trackpad_set_cpi }; -uint16_t current_cpi = DEFAULT_CPI_TICK; -uint32_t gpio_offset_addr; -uint8_t has_motion = 0; -uint8_t scroll_debounce = 0; - -bool touchpad_init; +uint16_t current_cpi = DEFAULT_CPI_TICK; +uint32_t gpio_offset_addr; +uint8_t has_motion = 0; +extern bool set_scrolling; +bool touchpad_init; #if defined(NAVIGATOR_TRACKPAD_PTP_MODE) cgen6_report_t ptp_report; @@ -346,14 +345,13 @@ report_mouse_t navigator_trackpad_get_report(report_mouse_t mouse_report) { #endif #if defined(NAVIGATOR_TRACKPAD_PTP_MODE) if (!prev_ptp_flag && ptp_report.tip) { // Beginning of a motion - prev_ptp_x = ptp_report.x; - prev_ptp_y = ptp_report.y; - prev_ptp_flag = true; - tap_timer = timer_read(); - scroll_debounce = 1; + prev_ptp_x = ptp_report.x; + prev_ptp_y = ptp_report.y; + prev_ptp_flag = true; + tap_timer = timer_read(); } else if (!ptp_report.tip) { // End of a motion prev_ptp_flag = false; - if (timer_elapsed(tap_timer) < NAVIGATOR_TRACKPAD_TAPPING_TERM) { // Register a tap or double tap + if (timer_elapsed(tap_timer) < NAVIGATOR_TRACKPAD_TAPPING_TERM && set_scrolling == false) { // Register a tap or double tap if (last_contact_count > 0) { # ifdef NAVIGATOR_TRACKPAD_ENABLE_DOUBLE_TAP mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON2); @@ -365,46 +363,19 @@ report_mouse_t navigator_trackpad_get_report(report_mouse_t mouse_report) { } prev_tap_clear = true; } + set_scrolling = false; } else { if (timer_elapsed(tap_timer) >= NAVIGATOR_TRACKPAD_TAP_DEBOUNCE) { ptp_delta_x = ptp_report.x - prev_ptp_x; ptp_delta_y = ptp_report.y - prev_ptp_y; + if (ptp_report.contact_count > 0) { // More than one finger, return scroll motions - if (scroll_debounce == 0) { - scroll_debounce = 1; - if (ptp_delta_y && abs(ptp_delta_y) > abs(ptp_delta_x)) { - uint8_t scroll_v; - if (ptp_delta_y > 0) { - scroll_v = 1; - } else { - scroll_v = -1; - } -# ifdef NAVIGATOR_SCROLL_INVERT - mouse_report.v = (int8_t)(scroll_v); -# else - mouse_report.v = (int8_t)(-scroll_v); -# endif - } - if (ptp_delta_x && abs(ptp_delta_x) > abs(ptp_delta_y)) { - if (ptp_delta_x > 0) { - mouse_report.h = 1; - } else { - mouse_report.h = -1; - } - } - mouse_report.x = 0; - mouse_report.y = 0; - } else { - scroll_debounce++; - if (scroll_debounce > NAVIGATOR_TRACKPAD_SCROLL_DEBOUNCE) { - scroll_debounce = 0; - } - } - } else { - mouse_report.x = ptp_delta_x; - mouse_report.y = ptp_delta_y; + set_scrolling = true; } + mouse_report.x = ptp_delta_x; + mouse_report.y = ptp_delta_y; + prev_ptp_x = ptp_report.x; prev_ptp_y = ptp_report.y; } diff --git a/keyboards/zsa/ergodox_ez/ergodox_ez.c b/keyboards/zsa/ergodox_ez/ergodox_ez.c index 214861620a..1a25f2ac6d 100644 --- a/keyboards/zsa/ergodox_ez/ergodox_ez.c +++ b/keyboards/zsa/ergodox_ez/ergodox_ez.c @@ -311,15 +311,17 @@ void eeconfig_init_kb(void) { // EEPROM is getting reset! static bool is_dynamic_recording = false; static uint16_t dynamic_loop_timer; -void dynamic_macro_record_start_user(int8_t direction) { +bool dynamic_macro_record_start_kb(int8_t direction) { is_dynamic_recording = true; dynamic_loop_timer = timer_read(); ergodox_right_led_1_on(); + return true; } -void dynamic_macro_record_end_user(int8_t direction) { +bool dynamic_macro_record_end_kb(int8_t direction) { is_dynamic_recording = false; layer_state_set_user(layer_state); + return true; } #endif diff --git a/keyboards/zsa/moonlander/moonlander.c b/keyboards/zsa/moonlander/moonlander.c index 9ecd0109e4..e1918c1364 100644 --- a/keyboards/zsa/moonlander/moonlander.c +++ b/keyboards/zsa/moonlander/moonlander.c @@ -82,9 +82,8 @@ bool dynamic_macro_record_end_kb(int8_t direction) { if (cancel_deferred_exec(dynamic_macro_token)) { dynamic_macro_token = INVALID_DEFERRED_TOKEN; STATUS_LED_3(false); - (false); } - return false; + return true; } # endif diff --git a/quantum/pointing_device/pointing_device.c b/quantum/pointing_device/pointing_device.c index 44bb412b1a..ff099e9d57 100644 --- a/quantum/pointing_device/pointing_device.c +++ b/quantum/pointing_device/pointing_device.c @@ -325,8 +325,6 @@ __attribute__((weak)) bool pointing_device_task(void) { local_mouse_report = is_keyboard_left() ? pointing_device_task_combined(local_mouse_report, shared_mouse_report) : pointing_device_task_combined(shared_mouse_report, local_mouse_report); #else local_mouse_report = pointing_device_adjust_by_defines(local_mouse_report); - local_mouse_report = pointing_device_task_modules(local_mouse_report); - local_mouse_report = pointing_device_task_kb(local_mouse_report); #endif local_mouse_report = pointing_device_task_modules(local_mouse_report); local_mouse_report = pointing_device_task_kb(local_mouse_report); @@ -565,4 +563,4 @@ __attribute__((weak)) void pointing_device_keycode_handler(uint16_t keycode, boo uint16_t pointing_device_get_hires_scroll_resolution(void) { return hires_scroll_resolution; } -#endif \ No newline at end of file +#endif diff --git a/quantum/pointing_device/pointing_device.h b/quantum/pointing_device/pointing_device.h index e1bf69f436..a9e9146d26 100644 --- a/quantum/pointing_device/pointing_device.h +++ b/quantum/pointing_device/pointing_device.h @@ -77,9 +77,11 @@ typedef struct { #elif defined(POINTING_DEVICE_DRIVER_navigator_trackball) # include "i2c_master.h" # include "drivers/sensors/navigator_trackball.h" +# include "drivers/sensors/navigator.h" #elif defined(POINTING_DEVICE_DRIVER_navigator_trackpad) # include "i2c_master.h" # include "drivers/sensors/navigator_trackpad.h" +# include "drivers/sensors/navigator.h" #else void pointing_device_driver_init(void); report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report); From 39c17221b40d8410e5489f1388b1187ba741f0f5 Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Wed, 11 Jun 2025 08:20:27 +0700 Subject: [PATCH 06/14] experiment: slight acceleration curve, more aggressive tap debounce --- drivers/sensors/navigator_trackpad.c | 44 +++++++++++++++++++++------- drivers/sensors/navigator_trackpad.h | 6 +--- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/drivers/sensors/navigator_trackpad.c b/drivers/sensors/navigator_trackpad.c index 98932e5435..c28f4b0a6e 100644 --- a/drivers/sensors/navigator_trackpad.c +++ b/drivers/sensors/navigator_trackpad.c @@ -1,16 +1,13 @@ #include #include +#include #include "navigator_trackpad.h" #include "i2c_master.h" #include "quantum.h" #include "timer.h" -const pointing_device_driver_t navigator_trackpad_pointing_device_driver = { - .init = navigator_trackpad_device_init, - .get_report = navigator_trackpad_get_report, - .get_cpi = navigator_trackpad_get_cpi, - .set_cpi = navigator_trackpad_set_cpi -}; + +const pointing_device_driver_t navigator_trackpad_pointing_device_driver = {.init = navigator_trackpad_device_init, .get_report = navigator_trackpad_get_report, .get_cpi = navigator_trackpad_get_cpi, .set_cpi = navigator_trackpad_set_cpi}; uint16_t current_cpi = DEFAULT_CPI_TICK; uint32_t gpio_offset_addr; @@ -251,6 +248,20 @@ uint32_t cirque_gen_6_read_callback(uint32_t trigger_time, void *cb_arg) { return NAVIGATOR_TRACKPAD_READ; } +void dump_ptp_report(void) { +#if defined(NAVIGATOR_TRACKPAD_PTP_MODE) + printf("PTP Report:\n"); + printf(" X: %d\n", ptp_report.x); + printf(" Y: %d\n", ptp_report.y); + printf(" Timestamp: %d\n", ptp_report.ts); + printf(" ID: %d\n", ptp_report.id); + printf(" Confidence: %d\n", ptp_report.confidence); + printf(" Tip: %d\n", ptp_report.tip); + printf(" Contact Count: %d\n", ptp_report.contact_count); + printf(" Buttons: %d\n", ptp_report.buttons); +#endif +} + void navigator_trackpad_device_init(void) { i2c_init(); @@ -351,12 +362,15 @@ report_mouse_t navigator_trackpad_get_report(report_mouse_t mouse_report) { tap_timer = timer_read(); } else if (!ptp_report.tip) { // End of a motion prev_ptp_flag = false; + printf("Delta X: %d, Delta Y: %d\n", ptp_delta_x, ptp_delta_y); if (timer_elapsed(tap_timer) < NAVIGATOR_TRACKPAD_TAPPING_TERM && set_scrolling == false) { // Register a tap or double tap if (last_contact_count > 0) { + print("Double tap detected\n"); # ifdef NAVIGATOR_TRACKPAD_ENABLE_DOUBLE_TAP mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON2); # endif } else { + print("Single tap detected\n"); # ifdef NAVIGATOR_TRACKPAD_ENABLE_TAP mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON1); # endif @@ -365,16 +379,24 @@ report_mouse_t navigator_trackpad_get_report(report_mouse_t mouse_report) { } set_scrolling = false; } else { - if (timer_elapsed(tap_timer) >= NAVIGATOR_TRACKPAD_TAP_DEBOUNCE) { - ptp_delta_x = ptp_report.x - prev_ptp_x; - ptp_delta_y = ptp_report.y - prev_ptp_y; + ptp_delta_x = ptp_report.x - prev_ptp_x; + ptp_delta_y = ptp_report.y - prev_ptp_y; + if (timer_elapsed(tap_timer) >= NAVIGATOR_TRACKPAD_TAP_DEBOUNCE) { if (ptp_report.contact_count > 0) { // More than one finger, return scroll motions set_scrolling = true; } - mouse_report.x = ptp_delta_x; - mouse_report.y = ptp_delta_y; + if (ptp_delta_x < 0) { + mouse_report.x = -powf(-ptp_delta_x, 1.2); + } else { + mouse_report.x = powf(ptp_delta_x, 1.2); + } + if (ptp_delta_y < 0) { + mouse_report.y = -powf(-ptp_delta_y, 1.2); + } else { + mouse_report.y = powf(ptp_delta_y, 1.2); + } prev_ptp_x = ptp_report.x; prev_ptp_y = ptp_report.y; diff --git a/drivers/sensors/navigator_trackpad.h b/drivers/sensors/navigator_trackpad.h index dd184aa7a0..4093cc22ce 100644 --- a/drivers/sensors/navigator_trackpad.h +++ b/drivers/sensors/navigator_trackpad.h @@ -24,12 +24,8 @@ # endif #define NAVIGATOR_TRACKPAD_READ 7 -#define NAVIGATOR_TRACKPAD_TAPPING_TERM 200 +#define NAVIGATOR_TRACKPAD_TAPPING_TERM 100 #define NAVIGATOR_TRACKPAD_TAP_DEBOUNCE 100 -#ifndef NAVIGATOR_TRACKPAD_SCROLL_DEBOUNCE -// The scroll debounce is the number of read cycles it takes to register a scroll event. Each read cycle is set to #NAVIGATOR_TRACKPAD_READ -#define NAVIGATOR_TRACKPAD_SCROLL_DEBOUNCE 3 -#endif #ifndef NAVIGATOR_TRACKPAD_ADDRESS # define NAVIGATOR_TRACKPAD_ADDRESS 0x58 From f11ebc3a7140e9f579e5ddcb6d5504bae677b143 Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Wed, 11 Jun 2025 08:27:54 +0700 Subject: [PATCH 07/14] fix: a better way to debounce taps --- drivers/sensors/navigator_trackpad.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/sensors/navigator_trackpad.c b/drivers/sensors/navigator_trackpad.c index c28f4b0a6e..99dcef7c86 100644 --- a/drivers/sensors/navigator_trackpad.c +++ b/drivers/sensors/navigator_trackpad.c @@ -6,13 +6,13 @@ #include "quantum.h" #include "timer.h" - const pointing_device_driver_t navigator_trackpad_pointing_device_driver = {.init = navigator_trackpad_device_init, .get_report = navigator_trackpad_get_report, .get_cpi = navigator_trackpad_get_cpi, .set_cpi = navigator_trackpad_set_cpi}; uint16_t current_cpi = DEFAULT_CPI_TICK; uint32_t gpio_offset_addr; uint8_t has_motion = 0; extern bool set_scrolling; +bool in_motion; bool touchpad_init; #if defined(NAVIGATOR_TRACKPAD_PTP_MODE) @@ -360,10 +360,10 @@ report_mouse_t navigator_trackpad_get_report(report_mouse_t mouse_report) { prev_ptp_y = ptp_report.y; prev_ptp_flag = true; tap_timer = timer_read(); + in_motion = false; } else if (!ptp_report.tip) { // End of a motion prev_ptp_flag = false; - printf("Delta X: %d, Delta Y: %d\n", ptp_delta_x, ptp_delta_y); - if (timer_elapsed(tap_timer) < NAVIGATOR_TRACKPAD_TAPPING_TERM && set_scrolling == false) { // Register a tap or double tap + if (in_motion == false) { // Register a tap or double tap if (last_contact_count > 0) { print("Double tap detected\n"); # ifdef NAVIGATOR_TRACKPAD_ENABLE_DOUBLE_TAP @@ -400,6 +400,8 @@ report_mouse_t navigator_trackpad_get_report(report_mouse_t mouse_report) { prev_ptp_x = ptp_report.x; prev_ptp_y = ptp_report.y; + + in_motion = true; } last_contact_count = ptp_report.contact_count; } From 574b2798a47078d8317fc3561b867dbc85de68db Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Tue, 17 Jun 2025 18:21:06 +0700 Subject: [PATCH 08/14] feat: adds aim/turbo mode --- drivers/sensors/navigator.c | 14 ++++++++++++++ drivers/sensors/navigator.h | 5 ++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/sensors/navigator.c b/drivers/sensors/navigator.c index 6b020c1f23..d82fa980a4 100644 --- a/drivers/sensors/navigator.c +++ b/drivers/sensors/navigator.c @@ -5,8 +5,22 @@ float scroll_accumulated_h = 0; float scroll_accumulated_v = 0; bool set_scrolling = false; +bool navigator_turbo = false; +bool navigator_aim = false; report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { + // Turbo mode is used to increase the speed of the mouse cursor + // by multiplying the x and y values by a factor. + if (navigator_turbo) { + mouse_report.x *= NAVIGATOR_TURBO_MULTIPLIER; + mouse_report.y *= NAVIGATOR_TURBO_MULTIPLIER; + } + // Aim mode is used to slow down the mouse cursor + // by dividing the x and y values by a factor. + if (navigator_aim) { + mouse_report.x /= NAVIGATOR_AIM_DIVIDER; + mouse_report.y /= NAVIGATOR_AIM_DIVIDER; + } if (set_scrolling) { scroll_accumulated_h += (float)mouse_report.x / NAVIGATOR_SCROLL_DIVIDER; scroll_accumulated_v += (float)mouse_report.y / NAVIGATOR_SCROLL_DIVIDER; diff --git a/drivers/sensors/navigator.h b/drivers/sensors/navigator.h index cf8639156c..d1504fdac8 100644 --- a/drivers/sensors/navigator.h +++ b/drivers/sensors/navigator.h @@ -1,4 +1,7 @@ #pragma once #ifndef NAVIGATOR_SCROLL_DIVIDER -# define NAVIGATOR_SCROLL_DIVIDER 10 + #define NAVIGATOR_SCROLL_DIVIDER 10 #endif + +#define NAVIGATOR_TURBO_MULTIPLIER 3 +#define NAVIGATOR_AIM_DIVIDER 3 From b7d013245763b2010d1555758666fffc047336f8 Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Tue, 17 Jun 2025 18:47:55 +0700 Subject: [PATCH 09/14] chore: tweak turbo/aim for the trackpad --- drivers/sensors/navigator.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/sensors/navigator.h b/drivers/sensors/navigator.h index d1504fdac8..b1e0db17d0 100644 --- a/drivers/sensors/navigator.h +++ b/drivers/sensors/navigator.h @@ -3,5 +3,12 @@ #define NAVIGATOR_SCROLL_DIVIDER 10 #endif +#ifdef POINTING_DEVICE_DRIVER_navigator_trackball #define NAVIGATOR_TURBO_MULTIPLIER 3 #define NAVIGATOR_AIM_DIVIDER 3 +#endif + +#ifdef POINTING_DEVICE_DRIVER_navigator_trackpad +#define NAVIGATOR_TURBO_MULTIPLIER 2 +#define NAVIGATOR_AIM_DIVIDER 2 +#endif From 96c5b8e2d924eed8679ec9e52e1b106cc7acf184 Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Tue, 17 Jun 2025 18:51:02 +0700 Subject: [PATCH 10/14] chore: remove navigator keys --- modules/zsa | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/zsa b/modules/zsa index 4a697850c8..4645104081 160000 --- a/modules/zsa +++ b/modules/zsa @@ -1 +1 @@ -Subproject commit 4a697850c8f5b6b09d710d94afcda0aa265025e0 +Subproject commit 464510408106a718592eb43cb9cad167a6754b05 From 9601e77500767c32761232acb0852a339d733701 Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Wed, 6 Aug 2025 09:23:58 +0700 Subject: [PATCH 11/14] fix: #pragma once --- modules/zsa | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/zsa b/modules/zsa index e9e7563dec..92b9130e71 160000 --- a/modules/zsa +++ b/modules/zsa @@ -1 +1 @@ -Subproject commit e9e7563dec3be5e0144f1d6c08576a99a013230f +Subproject commit 92b9130e71e65d6c4ca9cdb69ac282f43f4fe32f From 3e055c27ba33e0d276ede008c1a913cd34274448 Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Tue, 12 Aug 2025 14:16:50 +0700 Subject: [PATCH 12/14] fix: address the i2c transmit and receive length on u16 --- drivers/i2c_master.h | 2 +- platforms/chibios/drivers/i2c_master.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c_master.h b/drivers/i2c_master.h index b36b5ef0df..65add8d9f5 100644 --- a/drivers/i2c_master.h +++ b/drivers/i2c_master.h @@ -42,7 +42,7 @@ void i2c_init(void); */ i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); -i2c_status_t i2c_transmit_and_receive(uint8_t address, const uint8_t* tx_data, uint16_t tx_length, uint8_t* rx_data, uint8_t rx_length, uint16_t timeout); +i2c_status_t i2c_transmit_and_receive(uint8_t address, const uint8_t* tx_data, uint16_t tx_length, uint8_t* rx_data, uint16_t rx_length, uint16_t timeout); #if defined(__AVR__) || defined(__DOXYGEN__) /** diff --git a/platforms/chibios/drivers/i2c_master.c b/platforms/chibios/drivers/i2c_master.c index 9f9f6f321e..cd6b913878 100644 --- a/platforms/chibios/drivers/i2c_master.c +++ b/platforms/chibios/drivers/i2c_master.c @@ -154,7 +154,7 @@ i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, return i2c_epilogue(status); } -i2c_status_t i2c_transmit_and_receive(uint8_t address, const uint8_t* tx_data, uint16_t tx_length, uint8_t* rx_data, uint8_t rx_length, uint16_t timeout) { +i2c_status_t i2c_transmit_and_receive(uint8_t address, const uint8_t* tx_data, uint16_t tx_length, uint8_t* rx_data, uint16_t rx_length, uint16_t timeout) { i2cStart(&I2C_DRIVER, &i2cconfig); msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (address >> 1), tx_data, tx_length, rx_data, rx_length, TIME_MS2I(timeout)); return i2c_epilogue(status); From 4ed023b39942afc805b31f978e3be43f1ef23d92 Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Tue, 12 Aug 2025 16:03:08 +0700 Subject: [PATCH 13/14] fix: change the packet size from 53 to 17 --- drivers/sensors/navigator_trackpad.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensors/navigator_trackpad.h b/drivers/sensors/navigator_trackpad.h index 4093cc22ce..4fd2a81212 100644 --- a/drivers/sensors/navigator_trackpad.h +++ b/drivers/sensors/navigator_trackpad.h @@ -40,7 +40,7 @@ # define NAVIGATOR_TRACKPAD_PTP_MODE #endif -#define CGEN6_MAX_PACKET_SIZE 53 +#define CGEN6_MAX_PACKET_SIZE 17 #define CGEN6_PTP_REPORT_ID 0x01 #define CGEN6_MOUSE_REPORT_ID 0x06 #define CGEN6_ABSOLUTE_REPORT_ID 0x09 From 63df8aaf50380d9ea5cd7462e35173554a638130 Mon Sep 17 00:00:00 2001 From: Florian Didron Date: Fri, 22 Aug 2025 12:27:10 +0700 Subject: [PATCH 14/14] chore: add more comments --- drivers/sensors/navigator.c | 3 +++ drivers/sensors/navigator.h | 3 +++ drivers/sensors/navigator_trackball.c | 18 ++++++++++++++++++ drivers/sensors/navigator_trackball.h | 4 +++- drivers/sensors/navigator_trackpad.c | 3 +++ drivers/sensors/navigator_trackpad.h | 3 +++ 6 files changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/sensors/navigator.c b/drivers/sensors/navigator.c index d82fa980a4..90ca16709a 100644 --- a/drivers/sensors/navigator.c +++ b/drivers/sensors/navigator.c @@ -1,3 +1,6 @@ +// Copyright 2025 ZSA Technology Labs, Inc +// SPDX-License-Identifier: GPL-2.0-or-later + #include "quantum.h" #include "navigator.h" diff --git a/drivers/sensors/navigator.h b/drivers/sensors/navigator.h index b1e0db17d0..73e809715b 100644 --- a/drivers/sensors/navigator.h +++ b/drivers/sensors/navigator.h @@ -1,3 +1,6 @@ +// Copyright 2025 ZSA Technology Labs, Inc +// SPDX-License-Identifier: GPL-2.0-or-later + #pragma once #ifndef NAVIGATOR_SCROLL_DIVIDER #define NAVIGATOR_SCROLL_DIVIDER 10 diff --git a/drivers/sensors/navigator_trackball.c b/drivers/sensors/navigator_trackball.c index e1b58c8d7f..b6114625e5 100644 --- a/drivers/sensors/navigator_trackball.c +++ b/drivers/sensors/navigator_trackball.c @@ -1,3 +1,11 @@ +// Copyright 2025 ZSA Technology Labs, Inc +// SPDX-License-Identifier: GPL-2.0-or-later + +// This is the QMK driver for the Navigator Trackball. It is comprised of two ICs: +// 1. The sci18is606 is a i2c to spi bridge that converts the i2c protocol to the spi protocol. It allows the trackball to +// be plugged using the TRRS jack used by ZSA keyboards or any other split keyboard. +// 2. The paw3805ek is a high-speed motion detection sensor. It is used to detect the motion of the trackball. + #include "i2c_master.h" #include "navigator_trackball.h" #include @@ -19,6 +27,7 @@ uint8_t trackball_init = 0; deferred_token callback_token = 0; +// The sequence of commands to configure and boot the paw3805ek sensor. paw3805ek_reg_seq_t paw3805ek_configure_seq[] = { {0x06, 0x80}, // Software reset {0x00, 0x00}, // Request the sensor ID @@ -32,14 +41,17 @@ paw3805ek_reg_seq_t paw3805ek_configure_seq[] = { {0x09 | WRITE_REG_BIT, 0x00}, // Enable the write protection }; +// A wrapper function for i2c_transmit that adds the address of the bridge chip to the data. i2c_status_t sci18is606_write(uint8_t *data, uint8_t length) { return i2c_transmit(NAVIGATOR_TRACKBALL_ADDRESS, data, length, NAVIGATOR_TRACKBALL_TIMEOUT); } +// A wrapper function for i2c_receive that adds the address of the bridge chip to the data. i2c_status_t sci18is606_read(uint8_t *data, uint8_t length) { return i2c_receive(NAVIGATOR_TRACKBALL_ADDRESS, data, length, NAVIGATOR_TRACKBALL_TIMEOUT); } +// A wrapper function that allows to write and optionally read from the bridge chip. i2c_status_t sci18is606_spi_tx(uint8_t *data, uint8_t length, bool read) { i2c_status_t status = sci18is606_write(data, length); wait_us(length * 15); @@ -53,6 +65,7 @@ i2c_status_t sci18is606_spi_tx(uint8_t *data, uint8_t length, bool read) { return status; } +// Configure the bridge chip to enable SPI mode. i2c_status_t sci18is606_configure(void) { uint8_t spi_conf[2] = {SCI18IS606_CONF_SPI, SCI18IS606_CONF}; i2c_status_t status = sci18is606_write(spi_conf, 2); @@ -119,6 +132,7 @@ bool paw3805ek_set_cpi(void) { {0x09 | WRITE_REG_BIT, 0x00}, // Enable the write protection }; + // Run the spi sequence to configure the cpi. for (uint8_t i = 0; i < sizeof(cpi_reg_seq) / sizeof(paw3805ek_reg_seq_t); i++) { uint8_t buf[3]; buf[0] = NCS_PIN; @@ -132,6 +146,7 @@ bool paw3805ek_set_cpi(void) { return true; } +// Run the paw3805ek configuration sequence. bool paw3805ek_configure(void) { for (uint8_t i = 0; i < sizeof(paw3805ek_configure_seq) / sizeof(paw3805ek_reg_seq_t); i++) { uint8_t buf[3]; @@ -153,6 +168,7 @@ bool paw3805ek_configure(void) { return true; } +// Assert the CS pin to read the motion register. bool paw3805ek_has_motion(void) { uint8_t motion[3] = {0x01, 0x02, 0x00}; if (sci18is606_spi_tx(motion, 3, true) != I2C_STATUS_SUCCESS) { @@ -161,6 +177,7 @@ bool paw3805ek_has_motion(void) { return motion[1] & 0x80; } +// Read the motion data from the paw3805ek sensor. void paw3804ek_read_motion(report_mouse_t *mouse_report) { #ifdef MOUSE_EXTENDED_REPORT uint8_t delta_x_l[2] = {0x01, 0x03}; @@ -201,6 +218,7 @@ void paw3804ek_read_motion(report_mouse_t *mouse_report) { #endif } +// Deffered execution callback that periodically checks for motion. uint32_t sci18is606_read_callback(uint32_t trigger_time, void *cb_arg) { if (!trackball_init) { navigator_trackball_device_init(); diff --git a/drivers/sensors/navigator_trackball.h b/drivers/sensors/navigator_trackball.h index 2638edc6da..f364c583aa 100644 --- a/drivers/sensors/navigator_trackball.h +++ b/drivers/sensors/navigator_trackball.h @@ -1,3 +1,6 @@ +// Copyright 2025 ZSA Technology Labs, Inc +// SPDX-License-Identifier: GPL-2.0-or-later + #pragma once #include #include @@ -25,7 +28,6 @@ #define SCI18IS606_GET_ID 0xFE #define WRITE_REG_BIT 0x80 - /* The PAW3805EK datasheet suggests the following CPI values for the X and Y axes: CPI X-axis Y-axis diff --git a/drivers/sensors/navigator_trackpad.c b/drivers/sensors/navigator_trackpad.c index 99dcef7c86..b9e0cebaad 100644 --- a/drivers/sensors/navigator_trackpad.c +++ b/drivers/sensors/navigator_trackpad.c @@ -1,3 +1,6 @@ +// Copyright 2025 ZSA Technology Labs, Inc +// SPDX-License-Identifier: GPL-2.0-or-later + #include #include #include diff --git a/drivers/sensors/navigator_trackpad.h b/drivers/sensors/navigator_trackpad.h index 4fd2a81212..0ca548ed77 100644 --- a/drivers/sensors/navigator_trackpad.h +++ b/drivers/sensors/navigator_trackpad.h @@ -1,3 +1,6 @@ +// Copyright 2025 ZSA Technology Labs, Inc +// SPDX-License-Identifier: GPL-2.0-or-later + #pragma once #include #include