From 0d5c1d809b718cf4d5e82a0715717caa2a39a5f1 Mon Sep 17 00:00:00 2001 From: ReFil <31960031+ReFil@users.noreply.github.com> Date: Thu, 10 Aug 2023 12:08:20 +0100 Subject: [PATCH] Time to break things --- app/Kconfig | 54 +++- app/boards/arm/bt60/bt60_defconfig | 2 + app/drivers/sensor/gen4/gen4.c | 84 +---- app/drivers/sensor/gen4/gen4.h | 10 +- .../dts/bindings/sensor/cirque,gen4.yaml | 4 - app/include/drivers/sensor/gen4.h | 26 +- app/include/zmk/hid.h | 292 +++++++++++++++++- app/include/zmk/trackpad.h | 19 ++ app/src/hid.c | 66 ++++ app/src/hog.c | 97 +++++- app/src/trackpad.c | 56 +++- 11 files changed, 602 insertions(+), 108 deletions(-) create mode 100644 app/include/zmk/trackpad.h diff --git a/app/Kconfig b/app/Kconfig index a6d5d4b1105..fef0e410171 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -301,13 +301,59 @@ config ZMK_BACKLIGHT_AUTO_OFF_USB #ZMK_BACKLIGHT endif -config ZMK_TRACKPAD - bool "Enable the trackpad HID reporting and processing" - default n - #Display/LED Options endmenu +menuconfig ZMK_TRACKPAD + bool "Enable ZMK trackpad emulation" + default n + +config ZMK_TRACKPAD_TICK_DURATION + int "Trackpad tick duration in ms" + default 8 + +config ZMK_TRACKPAD_MAX_FINGERS + int "Maximum number of fingers reported in PTP" + range 3 5 + default 5 + +config ZMK_TRACKPAD_PHYSICAL_X + int "Maximum X size of trackpad in 0.1cm increments" + default 600 + +config ZMK_TRACKPAD_PHYSICAL_Y + int "Maximum Y size of trackpad in 0.1cm increments" + default 600 + + +if ZMK_TRACKPAD + +choice ZMK_TRACKPAD_WORK_QUEUE + prompt "Work queue selection for trackpad events" + default ZMK_TRACKPAD_WORK_QUEUE_DEDICATED + +config ZMK_TRACKPAD_WORK_QUEUE_SYSTEM + bool "Use default system work queue for trackpad events" + +config ZMK_TRACKPAD_WORK_QUEUE_DEDICATED + bool "Use dedicated work queue for trackpad events" + +endchoice + +if ZMK_TRACKPAD_WORK_QUEUE_DEDICATED + +config ZMK_TRACKPAD_DEDICATED_THREAD_STACK_SIZE + int "Stack size for dedicated trackpad thread/queue" + default 2048 + +config ZMK_TRACKPAD_DEDICATED_THREAD_PRIORITY + int "Thread priority for dedicated trackpad thread/queue" + default 3 + +endif # ZMK_TRACKPAD_WORK_QUEUE_DEDICATED + +endif + menu "Power Management" config ZMK_IDLE_TIMEOUT diff --git a/app/boards/arm/bt60/bt60_defconfig b/app/boards/arm/bt60/bt60_defconfig index 60ded8eb5a2..97cf87c3a7b 100644 --- a/app/boards/arm/bt60/bt60_defconfig +++ b/app/boards/arm/bt60/bt60_defconfig @@ -15,6 +15,8 @@ CONFIG_PINCTRL=y CONFIG_ZMK_USB_LOGGING=y CONFIG_ZMK_TRACKPAD=y +CONFIG_ZMK_TRACKPAD_PHYSICAL_X=650 +CONFIG_ZMK_TRACKPAD_PHYSICAL_Y=1065 CONFIG_I2C=y CONFIG_GEN4=y CONFIG_GEN4_TRIGGER_GLOBAL_THREAD=y diff --git a/app/drivers/sensor/gen4/gen4.c b/app/drivers/sensor/gen4/gen4.c index 2dfa0f54378..72f048b89e2 100644 --- a/app/drivers/sensor/gen4/gen4.c +++ b/app/drivers/sensor/gen4/gen4.c @@ -38,68 +38,20 @@ static int gen4_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { const struct gen4_data *data = dev->data; switch ((enum sensor_channel_gen4)chan) { - case SENSOR_CHAN_FINGERS: + case SENSOR_CHAN_CONTACTS: val->val1 = data->contacts; break; - case SENSOR_CHAN_X_0: - val->val1 = data->fingers[0].x; + case SENSOR_CHAN_X: + val->val1 = data->finger.x; break; - case SENSOR_CHAN_X_1: - val->val1 = data->fingers[1].x; + case SENSOR_CHAN_Y: + val->val1 = data->finger.y; break; - case SENSOR_CHAN_X_2: - val->val1 = data->fingers[2].x; + case SENSOR_CHAN_CONFIDENCE_TIP: + val->val1 = data->finger.confidence_tip; break; - case SENSOR_CHAN_X_3: - val->val1 = data->fingers[3].x; - break; - case SENSOR_CHAN_X_4: - val->val1 = data->fingers[4].x; - break; - case SENSOR_CHAN_Y_0: - val->val1 = data->fingers[0].y; - break; - case SENSOR_CHAN_Y_1: - val->val1 = data->fingers[1].y; - break; - case SENSOR_CHAN_Y_2: - val->val1 = data->fingers[2].y; - break; - case SENSOR_CHAN_Y_3: - val->val1 = data->fingers[3].y; - break; - case SENSOR_CHAN_Y_4: - val->val1 = data->fingers[4].y; - break; - case SENSOR_CHAN_PRESENT_0: - val->val1 = data->fingers[0].present; - break; - case SENSOR_CHAN_PRESENT_1: - val->val1 = data->fingers[1].present; - break; - case SENSOR_CHAN_PRESENT_2: - val->val1 = data->fingers[2].present; - break; - case SENSOR_CHAN_PRESENT_3: - val->val1 = data->fingers[3].present; - break; - case SENSOR_CHAN_PRESENT_4: - val->val1 = data->fingers[4].present; - break; - case SENSOR_CHAN_PALM_0: - val->val1 = data->fingers[0].palm; - break; - case SENSOR_CHAN_PALM_1: - val->val1 = data->fingers[1].palm; - break; - case SENSOR_CHAN_PALM_2: - val->val1 = data->fingers[2].palm; - break; - case SENSOR_CHAN_PALM_3: - val->val1 = data->fingers[3].palm; - break; - case SENSOR_CHAN_PALM_4: - val->val1 = data->fingers[4].palm; + case SENSOR_CHAN_FINGER: + val->val1 = data->finger_id; break; case SENSOR_CHAN_BUTTONS: val->val1 = data->btns; @@ -134,18 +86,16 @@ static int gen4_sample_fetch(const struct device *dev, enum sensor_channel) { data->btns = packet[12]; } - uint8_t finger_id = (packet[3] & 0xFC) >> 2; - LOG_DBG("FINGER ID: %d", finger_id); + data->finger_id = (packet[3] & 0xFC) >> 2; + LOG_DBG("FINGER ID: %d", data->finger_id); // Finger data - data->fingers[finger_id].present = (packet[3] & 0x02) >> 1; - data->fingers[finger_id].palm = packet[3] & 0x01; - data->fingers[finger_id].x = (uint16_t)packet[4] | (uint16_t)(packet[5] << 8); - data->fingers[finger_id].y = (uint16_t)packet[6] | (uint16_t)(packet[7] << 8); + data->finger.confidence_tip = (packet[3] & 0x03); + data->finger.x = (uint16_t)packet[4] | (uint16_t)(packet[5] << 8); + data->finger.y = (uint16_t)packet[6] | (uint16_t)(packet[7] << 8); - LOG_DBG("Finger detected: %d", data->fingers[finger_id].present); - LOG_DBG("Finger palm: %d", data->fingers[finger_id].palm); - LOG_DBG("Finger x: %d", data->fingers[finger_id].x); - LOG_DBG("Finger y: %d", data->fingers[finger_id].y); + LOG_DBG("Finger palm/detected: %h", data->finger.confidence_tip); + LOG_DBG("Finger x: %d", data->finger.x); + LOG_DBG("Finger y: %d", data->finger.y); return 0; } diff --git a/app/drivers/sensor/gen4/gen4.h b/app/drivers/sensor/gen4/gen4.h index 2f4d86f6153..43dc7b55e33 100644 --- a/app/drivers/sensor/gen4/gen4.h +++ b/app/drivers/sensor/gen4/gen4.h @@ -14,15 +14,13 @@ #define GEN4_ADDRESS 0x2C struct gen4_finger_data { - bool present; - bool palm; + uint8_t confidence_tip; uint16_t x, y; }; struct gen4_data { - uint8_t contacts; - uint8_t btns; - struct gen4_finger_data fingers[5]; + uint8_t contacts, btns, finger_id; + struct gen4_finger_data finger; bool in_int; #ifdef CONFIG_GEN4_TRIGGER const struct device *dev; @@ -43,7 +41,7 @@ struct gen4_config { #if DT_INST_ON_BUS(0, i2c) const struct i2c_dt_spec bus; #endif - bool rotate_90, sleep_en, no_taps; + bool rotate_90; #ifdef CONFIG_GEN4_TRIGGER const struct gpio_dt_spec dr; #endif diff --git a/app/drivers/zephyr/dts/bindings/sensor/cirque,gen4.yaml b/app/drivers/zephyr/dts/bindings/sensor/cirque,gen4.yaml index 64496cd5525..47cff96255f 100644 --- a/app/drivers/zephyr/dts/bindings/sensor/cirque,gen4.yaml +++ b/app/drivers/zephyr/dts/bindings/sensor/cirque,gen4.yaml @@ -11,7 +11,3 @@ properties: description: Data ready pin for the trackpad rotate-90: type: boolean - sleep: - type: boolean - no-taps: - type: boolean diff --git a/app/include/drivers/sensor/gen4.h b/app/include/drivers/sensor/gen4.h index 19e9d814f1a..7d9c9a6fbe0 100644 --- a/app/include/drivers/sensor/gen4.h +++ b/app/include/drivers/sensor/gen4.h @@ -8,27 +8,11 @@ extern "C" { #include enum sensor_channel_gen4 { - SENSOR_CHAN_FINGERS = SENSOR_CHAN_PRIV_START, - SENSOR_CHAN_X_0, - SENSOR_CHAN_X_1, - SENSOR_CHAN_X_2, - SENSOR_CHAN_X_3, - SENSOR_CHAN_X_4, - SENSOR_CHAN_Y_0, - SENSOR_CHAN_Y_1, - SENSOR_CHAN_Y_2, - SENSOR_CHAN_Y_3, - SENSOR_CHAN_Y_4, - SENSOR_CHAN_PRESENT_0, - SENSOR_CHAN_PRESENT_1, - SENSOR_CHAN_PRESENT_2, - SENSOR_CHAN_PRESENT_3, - SENSOR_CHAN_PRESENT_4, - SENSOR_CHAN_PALM_0, - SENSOR_CHAN_PALM_1, - SENSOR_CHAN_PALM_2, - SENSOR_CHAN_PALM_3, - SENSOR_CHAN_PALM_4, + SENSOR_CHAN_FINGER = SENSOR_CHAN_PRIV_START, + SENSOR_CHAN_X, + SENSOR_CHAN_Y, + SENSOR_CHAN_CONFIDENCE_TIP, + SENSOR_CHAN_CONTACTS, SENSOR_CHAN_BUTTONS, }; diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index ab42adaa13e..a5e4fc19a26 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -17,11 +17,20 @@ #define COLLECTION_REPORT 0x03 +#define ZMK_REPORT_ID_KEYBOARD 0x01 +#define ZMK_REPORT_ID_CONSUMER 0x02 + +#define ZMK_REPORT_ID_TRACKPAD 0x05 +#define ZMK_REPORT_ID_FEATURE_PTP_CAPABILITIES 0x06 +#define ZMK_REPORT_ID_FEATURE_PTPHQA 0x07 +#define ZMK_REPORT_ID_FEATURE_PTP_CONFIGURATION 0x08 +#define ZMK_REPORT_ID_FEATURE_PTP_SELECTIVE 0x09 + static const uint8_t zmk_hid_report_desc[] = { HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP), HID_USAGE(HID_USAGE_GD_KEYBOARD), HID_COLLECTION(HID_COLLECTION_APPLICATION), - HID_REPORT_ID(0x01), + HID_REPORT_ID(ZMK_REPORT_ID_KEYBOARD), HID_USAGE_PAGE(HID_USAGE_KEY), HID_USAGE_MIN8(HID_USAGE_KEY_KEYBOARD_LEFTCONTROL), HID_USAGE_MAX8(HID_USAGE_KEY_KEYBOARD_RIGHT_GUI), @@ -67,7 +76,7 @@ static const uint8_t zmk_hid_report_desc[] = { HID_USAGE_PAGE(HID_USAGE_CONSUMER), HID_USAGE(HID_USAGE_CONSUMER_CONSUMER_CONTROL), HID_COLLECTION(HID_COLLECTION_APPLICATION), - HID_REPORT_ID(0x02), + HID_REPORT_ID(ZMK_REPORT_ID_CONSUMER), HID_USAGE_PAGE(HID_USAGE_CONSUMER), #if IS_ENABLED(CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC) @@ -89,6 +98,221 @@ static const uint8_t zmk_hid_report_desc[] = { /* INPUT (Data,Ary,Abs) */ HID_INPUT(0x00), HID_END_COLLECTION, +#if IS_ENABLED(CONFIG_ZMK_TRACKPAD) + // PTP Touchpad HID from osmakari + /* USAGE_PAGE (Digitizers) */ + HID_USAGE_PAGE(HID_USAGE_DIGITIZERS), + /* USAGE (Touch Pad) */ + HID_USAGE(HID_USAGE_DIGITIZERS_TOUCH_PAD), + /* COLLECTION (Application) */ + HID_COLLECTION(HID_COLLECTION_APPLICATION), + + /* Windows Precision Touchpad Input Reports */ + + /* REPORT_ID (0x06) */ + HID_REPORT_ID(ZMK_REPORT_ID_TRACKPAD), + /* USAGE (Finger) */ + HID_USAGE(HID_USAGE_DIGITIZERS_FINGER), + /* COLLECTION (Logical) */ + HID_COLLECTION(0x02), + /* LOGICAL_MINIMUM (0) */ + HID_LOGICAL_MIN8(0), + /* LOGICAL_MAXIMUM (1) */ + HID_LOGICAL_MAX8(1), + /* USAGE (Confidence) */ + HID_USAGE(0x47), + /* USAGE (Tip switch) */ + HID_USAGE(0x42), + /* REPORT_COUNT (2) */ + HID_REPORT_COUNT(2), + /* REPORT_SIZE (1) */ + HID_REPORT_SIZE(1), + /* INPUT (Data, Var, Abs) */ + HID_INPUT(0x02), + /* REPORT_COUNT (1) */ + HID_REPORT_COUNT(1), + /* REPORT_SIZE (2) */ + HID_REPORT_SIZE(2), + /* LOGICAL_MAXIMUM (2) */ + HID_LOGICAL_MAX8(2), + /* USAGE (Contact Identifier) */ + HID_USAGE(HID_USAGE_DIGITIZERS_CONTACT_IDENTIFIER), + /* INPUT (Data, Var, Abs) */ + HID_INPUT(0x02), + /* REPORT_SIZE (1) */ + HID_REPORT_SIZE(1), + /* REPORT_COUNT (4) */ + HID_REPORT_COUNT(4), + /* INPUT (Cnst,Var,Abs) */ + HID_INPUT(0x03), + /* USAGE_PAGE(Generic Desktop) */ + HID_USAGE_PAGE(HID_USAGE_GD), + /* LOGICAL_MINIMUM (0) */ + HID_LOGICAL_MIN8(0), + /* LOGICAL_MAXIMUM (4095) */ + HID_LOGICAL_MAX16(0xFF, 0x0F), + /* REPORT_SIZE (16) */ + HID_REPORT_SIZE(16), + /* UNIT_EXPONENT (-2) */ + 0x55, + 0x0e, + /* UNIT (CM, EngLinear) */ + 0x65, + 0x11, + /* USAGE (X) */ + HID_USAGE(HID_USAGE_GD_X), + /* PHYSICAL_MINIMUM (0) */ + 0x35, + 0x00, + /* PHYSICAL_MAXIMUM (defined in config) */ + 0x46, + (CONFIG_ZMK_TRACKPAD_PHYSICAL_X & 0xFF), + ((CONFIG_ZMK_TRACKPAD_PHYSICAL_X >> 8) & 0xFF), + /* REPORT_COUNT (1) */ + HID_REPORT_COUNT(1), + /* INPUT (Data, Var, Abs) */ + HID_INPUT(0x02), + /* PHYSICAL_MAXIMUM (Defined in config) */ + 0x46, + (CONFIG_ZMK_TRACKPAD_PHYSICAL_Y & 0xFF), + ((CONFIG_ZMK_TRACKPAD_PHYSICAL_Y >> 8) & 0xFF), + /* USAGE (Y) */ + HID_USAGE(HID_USAGE_GD_Y), + /* INPUT (Data, Var, Abs) */ + HID_INPUT(0x02), + /* END_COLLECTION */ + HID_END_COLLECTION, + /* INPUT (Data, Var, Abs) */ + HID_INPUT(0x02), + /* USAGE_PAGE (Digitizers) */ + HID_USAGE_PAGE(HID_USAGE_DIGITIZERS), + /* USAGE (Contact count) */ + HID_USAGE(HID_USAGE_DIGITIZERS_CONTACT_COUNT), + /* LOGICAL_MAXIMUM (127) */ + HID_LOGICAL_MAX8(0x7F), + /* REPORT_COUNT (1) */ + HID_REPORT_COUNT(1), + /* REPORT_SIZE (8) */ + HID_REPORT_SIZE(8), + /* INPUT(Data, Var, Abs) */ + HID_INPUT(0x02), + /* USAGE_PAGE (Button) */ + HID_USAGE_PAGE(HID_USAGE_BUTTON), + /* USAGE (Button 1) */ + HID_USAGE(0x01), + /* LOGICAL_MAXIMUM (1) */ + HID_LOGICAL_MAX8(1), + /* REPORT_SIZE (1) */ + HID_REPORT_SIZE(1), + /* REPORT_COUNT (1) */ + HID_REPORT_COUNT(1), + /* INPUT (Data, Var, Abs) */ + HID_INPUT(0x02), + /* REPORT_COUNT (7) */ + HID_REPORT_COUNT(7), + /* INPUT (Cnst, Var, Abs) */ + HID_INPUT(0x03), + + /* Device Capabilities Feature Report */ + + /* USAGE_PAGE (Digitizer) */ + HID_USAGE_PAGE(HID_USAGE_DIGITIZERS), + /* REPORT_ID (0x07) */ + HID_REPORT_ID(ZMK_REPORT_ID_FEATURE_PTP_CAPABILITIES), + /* USAGE (Contact Count Maximum) */ + HID_USAGE(HID_USAGE_DIGITIZERS_CONTACT_COUNT_MAXIMUM), + /* USAGE (Pad Type) */ + HID_USAGE(HID_USAGE_DIGITIZERS_PAD_TYPE), + /* REPORT_SIZE (4) */ + HID_REPORT_SIZE(4), + /* REPORT_COUNT (2) */ + HID_REPORT_COUNT(2), + /* LOGICAL_MAXIMUM (15) */ + HID_LOGICAL_MAX8(0x0F), + /* FEATURE (Data, Var, Abs) */ + HID_FEATURE(0x02), + + /* PTPHQA Blob: Necessary for < Windows 10 */ + + /* USAGE_PAGE (Vendor Defined) */ + 0x06, + 0x00, + 0xFF, + /* REPORT_ID (0x08) */ + HID_REPORT_ID(ZMK_REPORT_ID_FEATURE_PTPHQA), + /* HID_USAGE (Vendor Usage 0xC5) */ + HID_USAGE(0xC5), + /* LOGICAL_MINIMUM (0) */ + HID_LOGICAL_MIN8(0), + /* LOGICAL_MAXIMUM (0xFF) */ + HID_LOGICAL_MAX16(0xFF, 0x00), + /* REPORT_SIZE (8) */ + HID_REPORT_SIZE(8), + /* REPORT_COUNT (256) */ + 0x96, + 0x00, + 0x01, + /* FEATURE (Data, Var, Abs) */ + HID_FEATURE(0x02), + /* END_COLLECTION */ + HID_END_COLLECTION, + + // TLC + /* USAGE_PAGE (Digitizer) */ + HID_USAGE_PAGE(HID_USAGE_DIGITIZERS), + /* USAGE (Configuration) */ + HID_USAGE(0x0E), + /* HID_COLLECTION */ + HID_COLLECTION(HID_COLLECTION_APPLICATION), + /* REPORT_ID (Feature 0x09) */ + HID_REPORT_ID(ZMK_REPORT_ID_FEATURE_CONFIGURATION), + /* USAGE (Finger) */ + HID_USAGE(HID_USAGE_DIGITIZERS_FINGER), + /* COLLECTION (Logical) */ + HID_COLLECTION(0x02), + /* USAGE (Input Mode) */ + HID_USAGE(0x52), + /* LOGICAL_MINIMUM (0) */ + HID_LOGICAL_MIN8(0), + /* LOGICAL_MAXIMUM (10) */ + HID_LOGICAL_MAX8(10), + /* REPORT_SIZE (8) */ + HID_REPORT_SIZE(8), + /* REPORT_COUNT (1) */ + HID_REPORT_COUNT(1), + /* FEATURE (Data, Var, Abs) */ + HID_FEATURE(0x02), + /* END_COLLECTION */ + HID_END_COLLECTION, + + /* USAGE (Finger) */ + HID_USAGE(HID_USAGE_DIGITIZERS_FINGER), + /* COLLECTION (Physical) */ + HID_COLLECTION(HID_COLLECTION_PHYSICAL), + /* REPORT_ID (Feature, 0x0A) */ + HID_REPORT_ID(ZMK_REPORT_ID_FEATURE_PTP_SELECTIVE), + /* USAGE (Surface switch) */ + HID_USAGE(HID_USAGE_DIGITIZERS_SURFACE_SWITCH), + /* USAGE (Button switch) */ + HID_USAGE(HID_USAGE_DIGITIZERS_BUTTON_SWITCH), + /* REPORT_SIZE (1) */ + HID_REPORT_SIZE(1), + /* REPORT_COUNT (2) */ + HID_REPORT_COUNT(2), + /* LOGICAL_MAXIMUM (1) */ + HID_LOGICAL_MAX8(1), + /* FEATURE (Data, Var, Abs) */ + HID_FEATURE(0x02), + /* REPORT_COUNT (6) */ + HID_REPORT_COUNT(6), + /* FEATURE (Cnst, Var, Abs) */ + HID_FEATURE(0x03), + /* END_COLLECTION */ + HID_END_COLLECTION, + /* END_COLLECTION */ + HID_END_COLLECTION, +#endif + }; // struct zmk_hid_boot_report @@ -126,6 +350,62 @@ struct zmk_hid_consumer_report { struct zmk_hid_consumer_report_body body; } __packed; +#ifdef IS_ENABLED(CONFIG_ZMK_TRACKPAD) +// Reporting structure from osmakari +// Report for single finger +struct zmk_ptp_finger { + // Confidence (bit 0) and tip switch (bit 1) + uint8_t confidence_tip; + // Contact ID + uint8_t contact_id; + // X + uint16_t x; + // Y + uint16_t y; +} __packed; + +// Report containing finger data +struct zmk_ptp_report { + // 0x05 + uint8_t report_id; + // Finger reporting + struct zmk_ptp_finger fingers[CONFIG_ZMK_TRACKPAD_MAX_FINGERS]; + // Contact count + uint8_t contact_count; + // Buttons + uint8_t buttons; +} __packed; + +// Feature report for configuration +struct zmk_ptp_feature_configuration { + uint8_t report_id; + // 0 for Mouse collection, 3 for Windows Precision Touchpad Collection + uint8_t input_mode; + // Selective reporting: Surface switch (bit 0), Button switch (bit 1) + uint8_t selective_reporting; +} __packed; + +// Feature report for certification +struct zmk_ptp_feature_certification { + uint8_t[256] ptphqa_blob; +} __packed; + +#define PTP_PAD_TYPE_DEPRESSIBLE 0x00 +#define PTP_PAD_TYPE_PRESSURE 0x01 +#define PTP_PAD_TYPE_NON_CLICKABLE 0x02 + +// Feature report for device capabilities +struct zmk_ptp_feature_capabilities { + uint8_t report_id; + // Max touches (L 4bit) and pad type (H 4bit): + // Max touches: number 3-5 + // Pad type: 0 for Depressible, 1 for Non-depressible, 2 for Non-clickable + uint8_t max_touches_pad_type; + +} __packed; + +#endif + zmk_mod_flags_t zmk_hid_get_explicit_mods(); int zmk_hid_register_mod(zmk_mod_t modifier); int zmk_hid_unregister_mod(zmk_mod_t modifier); @@ -152,5 +432,13 @@ int zmk_hid_press(uint32_t usage); int zmk_hid_release(uint32_t usage); bool zmk_hid_is_pressed(uint32_t usage); +#if IS_ENABLED(CONFIG_ZMK_TRACKPAD) +void zmk_hid_ptp_set(struct zmk_ptp_finger fingers[CONFIG_ZMK_TRACKPAD_MAX_FINGERS], + uint8_t contact_count, uint8_t buttons); +#endif + struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report(); struct zmk_hid_consumer_report *zmk_hid_get_consumer_report(); +#if IS_ENABLED(CONFIG_ZMK_TRACKPAD) +struct zmk_hid_ptp_report *zmk_hid_get_ptp_report(); +#endif diff --git a/app/include/zmk/trackpad.h b/app/include/zmk/trackpad.h new file mode 100644 index 00000000000..4b639fe98b2 --- /dev/null +++ b/app/include/zmk/trackpad.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +typedef uint8_t zmk_trackpad_finger_contacts_t; + +struct zmk_trackpad_finger_data_t { + bool present; + bool palm; + uint16_t x, y; +}; + +struct k_work_q *zmk_trackpad_work_q(); diff --git a/app/src/hid.c b/app/src/hid.c index 2a6b5d39da2..93594cec5f0 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -16,6 +16,57 @@ static struct zmk_hid_keyboard_report keyboard_report = { static struct zmk_hid_consumer_report consumer_report = {.report_id = 2, .body = {.keys = {0}}}; +#if IS_ENABLED(CONFIG_ZMK_TRACKPAD) +const uint8_t PTPHQA_BLOB[] = { + 0xfc, 0x28, 0xfe, 0x84, 0x40, 0xcb, 0x9a, 0x87, 0x0d, 0xbe, 0x57, 0x3c, 0xb6, 0x70, 0x09, 0x88, + 0x07, 0x97, 0x2d, 0x2b, 0xe3, 0x38, 0x34, 0xb6, 0x6c, 0xed, 0xb0, 0xf7, 0xe5, 0x9c, 0xf6, 0xc2, + 0x2e, 0x84, 0x1b, 0xe8, 0xb4, 0x51, 0x78, 0x43, 0x1f, 0x28, 0x4b, 0x7c, 0x2d, 0x53, 0xaf, 0xfc, + 0x47, 0x70, 0x1b, 0x59, 0x6f, 0x74, 0x43, 0xc4, 0xf3, 0x47, 0x18, 0x53, 0x1a, 0xa2, 0xa1, 0x71, + 0xc7, 0x95, 0x0e, 0x31, 0x55, 0x21, 0xd3, 0xb5, 0x1e, 0xe9, 0x0c, 0xba, 0xec, 0xb8, 0x89, 0x19, + 0x3e, 0xb3, 0xaf, 0x75, 0x81, 0x9d, 0x53, 0xb9, 0x41, 0x57, 0xf4, 0x6d, 0x39, 0x25, 0x29, 0x7c, + 0x87, 0xd9, 0xb4, 0x98, 0x45, 0x7d, 0xa7, 0x26, 0x9c, 0x65, 0x3b, 0x85, 0x68, 0x89, 0xd7, 0x3b, + 0xbd, 0xff, 0x14, 0x67, 0xf2, 0x2b, 0xf0, 0x2a, 0x41, 0x54, 0xf0, 0xfd, 0x2c, 0x66, 0x7c, 0xf8, + 0xc0, 0x8f, 0x33, 0x13, 0x03, 0xf1, 0xd3, 0xc1, 0x0b, 0x89, 0xd9, 0x1b, 0x62, 0xcd, 0x51, 0xb7, + 0x80, 0xb8, 0xaf, 0x3a, 0x10, 0xc1, 0x8a, 0x5b, 0xe8, 0x8a, 0x56, 0xf0, 0x8c, 0xaa, 0xfa, 0x35, + 0xe9, 0x42, 0xc4, 0xd8, 0x55, 0xc3, 0x38, 0xcc, 0x2b, 0x53, 0x5c, 0x69, 0x52, 0xd5, 0xc8, 0x73, + 0x02, 0x38, 0x7c, 0x73, 0xb6, 0x41, 0xe7, 0xff, 0x05, 0xd8, 0x2b, 0x79, 0x9a, 0xe2, 0x34, 0x60, + 0x8f, 0xa3, 0x32, 0x1f, 0x09, 0x78, 0x62, 0xbc, 0x80, 0xe3, 0x0f, 0xbd, 0x65, 0x20, 0x08, 0x13, + 0xc1, 0xe2, 0xee, 0x53, 0x2d, 0x86, 0x7e, 0xa7, 0x5a, 0xc5, 0xd3, 0x7d, 0x98, 0xbe, 0x31, 0x48, + 0x1f, 0xfb, 0xda, 0xaf, 0xa2, 0xa8, 0x6a, 0x89, 0xd6, 0xbf, 0xf2, 0xd3, 0x32, 0x2a, 0x9a, 0xe4, + 0xcf, 0x17, 0xb7, 0xb8, 0xf4, 0xe1, 0x33, 0x08, 0x24, 0x8b, 0xc4, 0x43, 0xa5, 0xe5, 0x24, 0xc2}; + +// Report containing finger data +struct zmk_hid_ptp_report ptp_report = { + .report_id = ZMK_REPORT_ID_TOUCHPAD, + .fingers = {{.confidence_tip = 0, .contact_id = 0, .x = 0, .y = 0}, + {.confidence_tip = 0, .contact_id = 0, .x = 0, .y = 0}, + {.confidence_tip = 0, .contact_id = 0, .x = 0, .y = 0} +#if (CONFIG_ZMK_TRACKPAD_MAX_FINGERS > 3) + , + {.confidence_tip = 0, .contact_id = 0, .x = 0, .y = 0} +#endif +#if (CONFIG_ZMK_TRACKPAD_MAX_FINGERS > 4) + , + {.confidence_tip = 0, .contact_id = 0, .x = 0, .y = 0} +#endif }, + .scan_time = 0, + .contact_count = 0, + .buttons = 0}; + +// Feature report for configuration +struct zmk_ptp_feature_configuration ptp_feature_configuration = { + .report_id = ZMK_REPORT_ID_FEATURE_PTP_CONFIGURATION, + .input_mode = 0, + .selective_reporting = 0}; + +// Feature report for ptphqa +struct zmk_ptp_feature_certification ptp_feature_certification = {.ptphqa_blob = PTPHQA_BLOB}; + +// Feature report for device capabilities +struct zmk_ptp_feature_capabilities ptp_feature_capabilities = { + .max_touches_pad_type = CONFIG_ZMK_TRACKPAD_MAX_FINGERS | (PTP_PAD_TYPE_NON_CLICKABLE << 4)}; +#endif + // Keep track of how often a modifier was pressed. // Only release the modifier if the count is 0. static int explicit_modifier_counts[8] = {0, 0, 0, 0, 0, 0, 0, 0}; @@ -263,6 +314,15 @@ bool zmk_hid_is_pressed(uint32_t usage) { } return false; } +#if IS_ENABLED(CONFIG_ZMK_TRACKPAD) +void zmk_hid_ptp_set(struct zmk_ptp_finger fingers[CONFIG_ZMK_TRACKPAD_MAX_FINGERS], + uint8_t contact_count, uint8_t buttons) { + memcpy(ptp_report.body.fingers, fingers, + sizeof(struct zmk_ptp_finger) * CONFIG_ZMK_TRACKPAD_MAX_FINGERS); + ptp_report.body.contact_count = contact_count; + ptp_report.body.buttons = buttons; +} +#endif struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report() { return &keyboard_report; @@ -271,3 +331,9 @@ struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report() { struct zmk_hid_consumer_report *zmk_hid_get_consumer_report() { return &consumer_report; } + +#if IS_ENABLED(CONFIG_ZMK_TRACKPAD) +struct zmk_hid_ptp_report *zmk_hid_get_ptp_report() { + return &ptp_report; +} +#endif diff --git a/app/src/hog.c b/app/src/hog.c index 930714b092a..b69cb840615 100644 --- a/app/src/hog.c +++ b/app/src/hog.c @@ -47,15 +47,40 @@ enum { }; static struct hids_report input = { - .id = 0x01, + .id = ZMK_REPORT_ID_KEYBOARD, .type = HIDS_INPUT, }; static struct hids_report consumer_input = { - .id = 0x02, + .id = ZMK_REPORT_ID_CONSUMER, .type = HIDS_INPUT, }; +static struct hids_report trackpad_report = { + .id = ZMK_REPORT_ID_TOUCHPAD, + .type = HIDS_INPUT, +}; + +static struct hids_report trackpad_capabilities = { + .id = ZMK_REPORT_ID_FEATURE_PTP_CAPABILITIES, + .type = HIDS_FEATURE, +}; + +static struct hids_report trackpad_capabilities = { + .id = ZMK_REPORT_ID_FEATURE_PTPHQA, + .type = HIDS_FEATURE, +}; + +static struct hids_report trackpad_config = { + .id = ZMK_REPORT_ID_FEATURE_PTP_CONFIGURATION, + .type = HIDS_FEATURE, +}; + +static struct hids_report trackpad_selective = { + .id = ZMK_REPORT_ID_FEATURE_PTP_SELECTIVE, + .type = HIDS_FEATURE, +}; + static bool host_requests_notification = false; static uint8_t ctrl_point; // static uint8_t proto_mode; @@ -93,6 +118,49 @@ static ssize_t read_hids_consumer_input_report(struct bt_conn *conn, sizeof(struct zmk_hid_consumer_report_body)); } +static ssize_t read_hids_trackpad_input_report(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) { + struct zmk_hid_trackpad_report_body *report_body = &zmk_hid_get_trackpad_report()->body; + return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body, + sizeof(struct zmk_hid_consumer_report_body)); +} +// TODO +static ssize_t read_hids_trackpad_capabilities_input_report(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + void *buf, uint16_t len, + uint16_t offset) { + struct zmk_hid_consumer_report_body *report_body = &zmk_hid_get_consumer_report()->body; + return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body, + sizeof(struct zmk_hid_consumer_report_body)); +} + +static ssize_t read_hids_consumer_input_report(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) { + struct zmk_hid_consumer_report_body *report_body = &zmk_hid_get_consumer_report()->body; + return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body, + sizeof(struct zmk_hid_consumer_report_body)); +} + +static ssize_t read_hids_consumer_input_report(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) { + struct zmk_hid_consumer_report_body *report_body = &zmk_hid_get_consumer_report()->body; + return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body, + sizeof(struct zmk_hid_consumer_report_body)); +} + +static ssize_t read_hids_consumer_input_report(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) { + struct zmk_hid_consumer_report_body *report_body = &zmk_hid_get_consumer_report()->body; + return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body, + sizeof(struct zmk_hid_consumer_report_body)); +} + +// ENDTODO + // static ssize_t write_proto_mode(struct bt_conn *conn, // const struct bt_gatt_attr *attr, // const void *buf, uint16_t len, uint16_t offset, @@ -137,6 +205,31 @@ BT_GATT_SERVICE_DEFINE( BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT, read_hids_consumer_input_report, NULL, NULL), BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, + NULL, &consumer_input), + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, read_hids_consumer_input_report, NULL, NULL), + BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, + NULL, &consumer_input), + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, read_hids_consumer_input_report, NULL, NULL), + BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, + NULL, &consumer_input), + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, read_hids_consumer_input_report, NULL, NULL), + BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, + NULL, &consumer_input), + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, read_hids_consumer_input_report, NULL, NULL), + BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, + NULL, &consumer_input), + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, read_hids_consumer_input_report, NULL, NULL), + BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref, NULL, &consumer_input), BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_CTRL_POINT, BT_GATT_CHRC_WRITE_WITHOUT_RESP, diff --git a/app/src/trackpad.c b/app/src/trackpad.c index 45d2e7e8715..9b20801083c 100644 --- a/app/src/trackpad.c +++ b/app/src/trackpad.c @@ -1,14 +1,36 @@ #include #include +#include +#include "zmk/trackpad.h" #include "zmk/hid.h" #include "zmk/endpoints.h" #include "drivers/sensor/gen4.h" -LOG_MODULE_REGISTER(trackpad, CONFIG_SENSOR_LOG_LEVEL); +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); const struct device *trackpad = DEVICE_DT_GET(DT_INST(0, cirque_gen4)); +static zmk_trackpad_finger_contacts_t present_contacts = 0; +static zmk_trackpad_finger_contacts_t old_contacts = 0; +static zmk_trackpad_finger_contacts_t changed_contacts = 0; +static zmk_trackpad_finger_contacts_t contacts_to_read = 0; + +static struct zmk_ptp_finger fingers[CONFIG_ZMK_TRACKPAD_MAX_FINGERS]; + +#if IS_ENABLED(CONFIG_ZMK_TRACKPAD_WORK_QUEUE_DEDICATED) +K_THREAD_STACK_DEFINE(trackpad_work_stack_area, CONFIG_ZMK_TRACKPAD_DEDICATED_THREAD_STACK_SIZE); +static struct k_work_q trackpad_work_q; +#endif + +struct k_work_q *zmk_trackpad_work_q() { +#if IS_ENABLED(CONFIG_ZMK_TRACKPAD_WORK_QUEUE_DEDICATED) + return &trackpad_work_q; +#else + return &k_sys_work_q; +#endif +} + static void handle_trackpad(const struct device *dev, const struct sensor_trigger *trig) { static uint8_t last_pressed = 0; int ret = sensor_sample_fetch(dev); @@ -17,18 +39,48 @@ static void handle_trackpad(const struct device *dev, const struct sensor_trigge return; } LOG_DBG("Trackpad handler trigd %d", 0); + // Is there a better way to do this? + struct sensor_value contacts, confidence_tip, id, x, y; + sensor_channel_get(dev, SENSOR_CHAN_CONTACTS, &contacts); + // expects bitmap format + present_contacts = contacts.val1; + // released Fingers + sensor_channel_get(dev, SENSOR_CHAN_X, &x); + sensor_channel_get(dev, SENSOR_CHAN_Y, &y); + sensor_channel_get(dev, SENSOR_CHAN_CONFIDENCE_TIP, &confidence_tip); + sensor_channel_get(dev, SENSOR_CHAN_FINGER, &id); + // If finger has changed + fingers[id.val1].confidence_tip = confidence_tip.val1; + fingers[id.val1].contact_id = id.val1; + fingers[id.val1].x = x.val1; + fingers[id.val1].y = y.val1; + k_work_submit_to_queue(&zmk_trackpad_work_q, &trackpad_work); } +static void zmk_trackpad_tick(struct k_work *work) {} + +K_WORK_DEFINE(trackpad_work, zmk_trackpad_tick); + +static void zmk_trackpad_tick_handler(struct k_timer *timer) { + k_work_submit_to_queue(&zmk_trackpad_work_q, &trackpad_work); +} + +K_TIMER_DEFINE(trackpad_tick, zmk_trackpad_tick_handler, NULL); + static int trackpad_init() { struct sensor_trigger trigger = { .type = SENSOR_TRIG_DATA_READY, .chan = SENSOR_CHAN_ALL, }; - printk("trackpad"); if (sensor_trigger_set(trackpad, &trigger, handle_trackpad) < 0) { LOG_ERR("can't set trigger"); return -EIO; }; +#if IS_ENABLED(CONFIG_ZMK_TRACKPAD_WORK_QUEUE_DEDICATED) + k_work_q_start(&trackpad_work_q, trackpad_work_stack_area, + K_THREAD_STACK_SIZEOF(trackpad_work_stack_area), + CONFIG_ZMK_TRACKPAD_DEDICATED_THREAD_PRIORITY); +#endif return 0; }