diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index 96f3424ea4..a9119d844e 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 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 diff --git a/drivers/i2c_master.h b/drivers/i2c_master.h index dbe1cd42fa..d5cdeedd64 100644 --- a/drivers/i2c_master.h +++ b/drivers/i2c_master.h @@ -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. diff --git a/drivers/sensors/navigator_trackpad.c b/drivers/sensors/navigator_trackpad.c new file mode 100644 index 0000000000..9a970e1858 --- /dev/null +++ b/drivers/sensors/navigator_trackpad.c @@ -0,0 +1,483 @@ +// Copyright 2025 ZSA Technology Labs, Inc +// 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 +#include +#include +#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(); +}; diff --git a/drivers/sensors/navigator_trackpad.h b/drivers/sensors/navigator_trackpad.h new file mode 100644 index 0000000000..0ca548ed77 --- /dev/null +++ b/drivers/sensors/navigator_trackpad.h @@ -0,0 +1,132 @@ +// Copyright 2025 ZSA Technology Labs, Inc +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once +#include +#include +#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); diff --git a/keyboards/zsa/ergodox_ez/ergodox_ez.c b/keyboards/zsa/ergodox_ez/ergodox_ez.c index 5b3724362f..52f7eeed45 100644 --- a/keyboards/zsa/ergodox_ez/ergodox_ez.c +++ b/keyboards/zsa/ergodox_ez/ergodox_ez.c @@ -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 diff --git a/keyboards/zsa/moonlander/moonlander.c b/keyboards/zsa/moonlander/moonlander.c index 7d61a2face..58a3339115 100644 --- a/keyboards/zsa/moonlander/moonlander.c +++ b/keyboards/zsa/moonlander/moonlander.c @@ -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}; diff --git a/keyboards/zsa/moonlander/moonlander.h b/keyboards/zsa/moonlander/moonlander.h index 44e8bc83f7..21455fb035 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 diff --git a/keyboards/zsa/planck_ez/planck_ez.c b/keyboards/zsa/planck_ez/planck_ez.c index f3e88fcaa5..045db959da 100644 --- a/keyboards/zsa/planck_ez/planck_ez.c +++ b/keyboards/zsa/planck_ez/planck_ez.c @@ -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; diff --git a/keyboards/zsa/voyager/keymaps/default/keymap.json b/keyboards/zsa/voyager/keymaps/default/keymap.json new file mode 100644 index 0000000000..1c0aeaf99a --- /dev/null +++ b/keyboards/zsa/voyager/keymaps/default/keymap.json @@ -0,0 +1,6 @@ +{ + "modules": [ + "zsa/oryx", + "zsa/defaults" + ] +} diff --git a/keyboards/zsa/voyager/voyager.c b/keyboards/zsa/voyager/voyager.c index f31738ea88..098d5ec570 100644 --- a/keyboards/zsa/voyager/voyager.c +++ b/keyboards/zsa/voyager/voyager.c @@ -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; diff --git a/keyboards/zsa/voyager/voyager.h b/keyboards/zsa/voyager/voyager.h index 7ec3603b4c..6cd186e6ca 100644 --- a/keyboards/zsa/voyager/voyager.h +++ b/keyboards/zsa/voyager/voyager.h @@ -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; diff --git a/platforms/chibios/drivers/i2c_master.c b/platforms/chibios/drivers/i2c_master.c index 20850859b5..cd6b913878 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, 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)); 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 5ae7c1411b..a9e9146d26 100644 --- a/quantum/pointing_device/pointing_device.h +++ b/quantum/pointing_device/pointing_device.h @@ -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);