mirror of
https://github.com/zsa/qmk_firmware.git
synced 2026-01-09 15:12:33 +00:00
feat: wip navigator trackpad support
This commit is contained in:
@@ -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 navigator_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)
|
||||
@@ -159,7 +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
|
||||
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
|
||||
|
||||
@@ -42,6 +42,20 @@ void i2c_init(void);
|
||||
*/
|
||||
i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
|
||||
|
||||
/**
|
||||
* \brief Send and receive multiple bytes to the selected I2C device.
|
||||
*
|
||||
* \param address The 7-bit I2C address of the device.
|
||||
* \param tx_data A pointer to the data to transmit.
|
||||
* \param tx_length The number of bytes to write. Take care not to overrun the length of `tx_data`.
|
||||
* \param rx_data A pointer to a buffer to read into.
|
||||
* \param rx_length The number of bytes to read. Take care not to overrun the length of `rx_data`.
|
||||
* \param timeout The time in milliseconds to wait for a response from the target device.
|
||||
*
|
||||
* \return `I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
|
||||
*/
|
||||
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__)
|
||||
/**
|
||||
* \brief Send multiple bytes from PROGMEM to the selected I2C device.
|
||||
|
||||
483
drivers/sensors/navigator_trackpad.c
Normal file
483
drivers/sensors/navigator_trackpad.c
Normal file
@@ -0,0 +1,483 @@
|
||||
// Copyright 2025 ZSA Technology Labs, Inc <contact@zsa.io>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// THIS IS A WORK IN PROGRESS, AS THE TRACKPAD IC's FIRMWARE IS STILL IN DEVELOPMENT
|
||||
// DO NOT USE THIS CODE IN PRODUCTION
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <math.h>
|
||||
#include "navigator_trackpad.h"
|
||||
#include "i2c_master.h"
|
||||
#include "quantum.h"
|
||||
#include "timer.h"
|
||||
|
||||
|
||||
#ifdef PROTOCOL_LUFA
|
||||
# error "LUFA is not supported yet"
|
||||
#endif
|
||||
|
||||
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)
|
||||
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 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();
|
||||
|
||||
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();
|
||||
in_motion = false;
|
||||
} else if (!ptp_report.tip) { // End of a motion
|
||||
prev_ptp_flag = false;
|
||||
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
|
||||
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
|
||||
}
|
||||
prev_tap_clear = true;
|
||||
}
|
||||
set_scrolling = false;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
in_motion = true;
|
||||
}
|
||||
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();
|
||||
};
|
||||
132
drivers/sensors/navigator_trackpad.h
Normal file
132
drivers/sensors/navigator_trackpad.h
Normal file
@@ -0,0 +1,132 @@
|
||||
// Copyright 2025 ZSA Technology Labs, Inc <contact@zsa.io>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "report.h"
|
||||
#include "pointing_device.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 100
|
||||
#define NAVIGATOR_TRACKPAD_TAP_DEBOUNCE 100
|
||||
|
||||
#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 17
|
||||
#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
|
||||
|
||||
#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);
|
||||
@@ -317,14 +317,12 @@ 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;
|
||||
}
|
||||
|
||||
bool dynamic_macro_record_end_kb(int8_t direction) {
|
||||
is_dynamic_recording = false;
|
||||
layer_state_set_user(layer_state);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
# include "defaults.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};
|
||||
|
||||
@@ -14,9 +14,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#endif // COMMUNITY_MODULE_ORYX_ENABLE
|
||||
#ifdef COMMUNITY_MODULE_DEFAULTS_ENABLE
|
||||
# include "defaults.h"
|
||||
#endif // COMMUNITY_MODULE_ORYX_ENABLE
|
||||
#endif
|
||||
|
||||
keyboard_config_t keyboard_config;
|
||||
|
||||
|
||||
6
keyboards/zsa/voyager/keymaps/default/keymap.json
Normal file
6
keyboards/zsa/voyager/keymaps/default/keymap.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"modules": [
|
||||
"zsa/oryx",
|
||||
"zsa/defaults"
|
||||
]
|
||||
}
|
||||
@@ -8,8 +8,8 @@
|
||||
# include "oryx.h"
|
||||
#endif // COMMUNITY_MODULE_ORYX_ENABLE
|
||||
#ifdef COMMUNITY_MODULE_DEFAULTS_ENABLE
|
||||
# include "defaults.h"
|
||||
#endif // COMMUNITY_MODULE_ORYX_ENABLE
|
||||
# include "defaults.h"
|
||||
#endif
|
||||
|
||||
keyboard_config_t keyboard_config;
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ typedef union {
|
||||
uint32_t raw;
|
||||
struct {
|
||||
bool disable_layer_led : 1;
|
||||
uint8_t navigator_cpi : 3;
|
||||
bool led_level : 1;
|
||||
uint8_t led_level_res : 2; // DO NOT REMOVE
|
||||
uint8_t navigator_cpi : 3;
|
||||
};
|
||||
} keyboard_config_t;
|
||||
|
||||
|
||||
@@ -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, 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);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
@@ -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
|
||||
#endif
|
||||
|
||||
@@ -78,6 +78,10 @@ typedef struct {
|
||||
# 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);
|
||||
|
||||
Reference in New Issue
Block a user