diff options
author | a-chol <a-chol@users.noreply.github.com> | 2021-08-17 20:52:44 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-18 04:52:44 +1000 |
commit | 75b49aff56436c57a424e622c91f6d80e1d0ecc2 (patch) | |
tree | 1968a4e939efef6aec0451d4bc991f4494292e22 /tmk_core | |
parent | 7794e97f32fb9dcb07e7fa928cde08691b257fbe (diff) |
Digitizer HID interface : absolute coordinates for mouse cursor (#12851)
* Add digitizer HID interface for setting the mouse cursor position at
absolute screen coordinates. Tested on Pro Micro, Proton C and
Blackpill.
* Update docs/feature_digitizer.md
Co-authored-by: Ryan <fauxpark@gmail.com>
* Update tmk_core/protocol/usb_descriptor.c
Co-authored-by: Ryan <fauxpark@gmail.com>
* Add missing copyrights
Add V-USB support
* Add support for digitizer dedicated endpoint for lufa and chibios.
Fix formatting issues
Move digitizer_task definition to the feature's base implementation file
* Run cformat on modified files
* Change digitizer report usage to Digitizer instead of Pen to avoid
pointer disappearing on Windows.
* Update tmk_core/protocol/vusb/vusb.c
Co-authored-by: Ryan <fauxpark@gmail.com>
* Run cformat from docker image
* Remove send_digitizer from host_driver_t and instead rely on the
declaration being the interface to the implementation in each
HW-specific usb implementation.
* Fix build : send_digitizer shouldn't be static in vusb and add
weak-linkage implementation for tests without usb implementation
* Change digitizer user interface to match pointing device's
* Update documentation with new API
Co-authored-by: a-chol <nothing@none.com>
Co-authored-by: Ryan <fauxpark@gmail.com>
Diffstat (limited to 'tmk_core')
-rw-r--r-- | tmk_core/common.mk | 13 | ||||
-rw-r--r-- | tmk_core/common/host.c | 19 | ||||
-rw-r--r-- | tmk_core/common/host_driver.h | 2 | ||||
-rw-r--r-- | tmk_core/common/keyboard.c | 7 | ||||
-rw-r--r-- | tmk_core/common/report.h | 14 | ||||
-rw-r--r-- | tmk_core/protocol/chibios/main.c | 1 | ||||
-rw-r--r-- | tmk_core/protocol/chibios/usb_main.c | 28 | ||||
-rw-r--r-- | tmk_core/protocol/lufa/lufa.c | 26 | ||||
-rw-r--r-- | tmk_core/protocol/usb_descriptor.c | 101 | ||||
-rw-r--r-- | tmk_core/protocol/usb_descriptor.h | 27 | ||||
-rw-r--r-- | tmk_core/protocol/vusb/vusb.c | 48 |
11 files changed, 280 insertions, 6 deletions
diff --git a/tmk_core/common.mk b/tmk_core/common.mk index 6c8cf69356..fa907b47b8 100644 --- a/tmk_core/common.mk +++ b/tmk_core/common.mk @@ -106,6 +106,19 @@ ifeq ($(strip $(NO_USB_STARTUP_CHECK)), yes) TMK_COMMON_DEFS += -DNO_USB_STARTUP_CHECK endif +ifeq ($(strip $(DIGITIZER_SHARED_EP)), yes) + TMK_COMMON_DEFS += -DDIGITIZER_SHARED_EP + SHARED_EP_ENABLE = yes +endif + +ifeq ($(strip $(DIGITIZER_ENABLE)), yes) + TMK_COMMON_DEFS += -DDIGITIZER_ENABLE + ifeq ($(strip $(SHARED_EP_ENABLE)), yes) + TMK_COMMON_DEFS += -DDIGITIZER_SHARED_EP + SHARED_EP_ENABLE = yes + endif +endif + ifeq ($(strip $(SHARED_EP_ENABLE)), yes) TMK_COMMON_DEFS += -DSHARED_EP_ENABLE endif diff --git a/tmk_core/common/host.c b/tmk_core/common/host.c index a8b391e893..f0c396b189 100644 --- a/tmk_core/common/host.c +++ b/tmk_core/common/host.c @@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "host.h" #include "util.h" #include "debug.h" +#include "digitizer.h" #ifdef NKRO_ENABLE # include "keycode_config.h" @@ -103,6 +104,24 @@ void host_consumer_send(uint16_t report) { (*driver->send_consumer)(report); } +void host_digitizer_send(digitizer_t *digitizer) { + if (!driver) return; + + report_digitizer_t report = { +#ifdef DIGITIZER_SHARED_EP + .report_id = REPORT_ID_DIGITIZER, +#endif + .tip = digitizer->tipswitch & 0x1, + .inrange = digitizer->inrange & 0x1, + .x = (uint16_t)(digitizer->x * 0x7FFF), + .y = (uint16_t)(digitizer->y * 0x7FFF), + }; + + send_digitizer(&report); +} + +__attribute__((weak)) void send_digitizer(report_digitizer_t *report) {} + uint16_t host_last_system_report(void) { return last_system_report; } uint16_t host_last_consumer_report(void) { return last_consumer_report; } diff --git a/tmk_core/common/host_driver.h b/tmk_core/common/host_driver.h index f34a220530..2aebca043d 100644 --- a/tmk_core/common/host_driver.h +++ b/tmk_core/common/host_driver.h @@ -30,3 +30,5 @@ typedef struct { void (*send_system)(uint16_t); void (*send_consumer)(uint16_t); } host_driver_t; + +void send_digitizer(report_digitizer_t *report);
\ No newline at end of file diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c index 28fa97bc8f..fcc51973fd 100644 --- a/tmk_core/common/keyboard.c +++ b/tmk_core/common/keyboard.c @@ -106,6 +106,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #if defined(CRC_ENABLE) # include "crc.h" #endif +#ifdef DIGITIZER_ENABLE +# include "digitizer.h" +#endif static uint32_t last_input_modification_time = 0; uint32_t last_input_activity_time(void) { return last_input_modification_time; } @@ -537,6 +540,10 @@ MATRIX_LOOP_END: joystick_task(); #endif +#ifdef DIGITIZER_ENABLE + digitizer_task(); +#endif + // update LED if (led_status != host_keyboard_leds()) { led_status = host_keyboard_leds(); diff --git a/tmk_core/common/report.h b/tmk_core/common/report.h index db6370657d..f2223e8063 100644 --- a/tmk_core/common/report.h +++ b/tmk_core/common/report.h @@ -30,7 +30,8 @@ enum hid_report_ids { REPORT_ID_SYSTEM, REPORT_ID_CONSUMER, REPORT_ID_NKRO, - REPORT_ID_JOYSTICK + REPORT_ID_JOYSTICK, + REPORT_ID_DIGITIZER }; /* Mouse buttons */ @@ -206,6 +207,17 @@ typedef struct { } __attribute__((packed)) report_mouse_t; typedef struct { +#ifdef DIGITIZER_SHARED_EP + uint8_t report_id; +#endif + uint8_t tip : 1; + uint8_t inrange : 1; + uint8_t pad2 : 6; + uint16_t x; + uint16_t y; +} __attribute__((packed)) report_digitizer_t; + +typedef struct { #if JOYSTICK_AXES_COUNT > 0 # if JOYSTICK_AXES_RESOLUTION > 8 int16_t axes[JOYSTICK_AXES_COUNT]; diff --git a/tmk_core/protocol/chibios/main.c b/tmk_core/protocol/chibios/main.c index 199741594a..e41d6ff195 100644 --- a/tmk_core/protocol/chibios/main.c +++ b/tmk_core/protocol/chibios/main.c @@ -65,6 +65,7 @@ void send_keyboard(report_keyboard_t *report); void send_mouse(report_mouse_t *report); void send_system(uint16_t data); void send_consumer(uint16_t data); +void send_digitizer(report_digitizer_t *report); /* host struct */ host_driver_t chibios_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer}; diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c index e5edd74dcb..cc282e6a9b 100644 --- a/tmk_core/protocol/chibios/usb_main.c +++ b/tmk_core/protocol/chibios/usb_main.c @@ -316,6 +316,9 @@ typedef struct { #ifdef JOYSTICK_ENABLE usb_driver_config_t joystick_driver; #endif +#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP) + usb_driver_config_t digitizer_driver; +#endif }; usb_driver_config_t array[0]; }; @@ -360,6 +363,14 @@ static usb_driver_configs_t drivers = { # define JOYSTICK_OUT_MODE USB_EP_MODE_TYPE_BULK .joystick_driver = QMK_USB_DRIVER_CONFIG(JOYSTICK, 0, false), #endif + +#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP) +# define DIGITIZER_IN_CAPACITY 4 +# define DIGITIZER_OUT_CAPACITY 4 +# define DIGITIZER_IN_MODE USB_EP_MODE_TYPE_BULK +# define DIGITIZER_OUT_MODE USB_EP_MODE_TYPE_BULK + .digitizer_driver = QMK_USB_DRIVER_CONFIG(DIGITIZER, 0, false), +#endif }; #define NUM_USB_DRIVERS (sizeof(drivers) / sizeof(usb_driver_config_t)) @@ -930,6 +941,23 @@ void send_consumer(uint16_t data) { #endif } +void send_digitizer(report_digitizer_t *report) { +#ifdef DIGITIZER_ENABLE +# ifdef DIGITIZER_SHARED_EP + osalSysLock(); + if (usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) { + osalSysUnlock(); + return; + } + + usbStartTransmitI(&USB_DRIVER, DIGITIZER_IN_EPNUM, (uint8_t *)report, sizeof(report_digitizer_t)); + osalSysUnlock(); +# else + chnWrite(&drivers.digitizer_driver.driver, (uint8_t *)report, sizeof(report_digitizer_t)); +# endif +#endif +} + /* --------------------------------------------------------- * Console functions * --------------------------------------------------------- diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index 4ac079e168..8ddb8b1c4b 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -142,9 +142,7 @@ static void send_keyboard(report_keyboard_t *report); static void send_mouse(report_mouse_t *report); static void send_system(uint16_t data); static void send_consumer(uint16_t data); -host_driver_t lufa_driver = { - keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer, -}; +host_driver_t lufa_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer}; #ifdef VIRTSER_ENABLE // clang-format off @@ -525,6 +523,11 @@ void EVENT_USB_Device_ConfigurationChanged(void) { /* Setup joystick endpoint */ ConfigSuccess &= Endpoint_ConfigureEndpoint((JOYSTICK_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_INTERRUPT, JOYSTICK_EPSIZE, 1); #endif + +#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP) + /* Setup digitizer endpoint */ + ConfigSuccess &= Endpoint_ConfigureEndpoint((DIGITIZER_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_INTERRUPT, DIGITIZER_EPSIZE, 1); +#endif } /* FIXME: Expose this table in the docs somehow @@ -983,6 +986,23 @@ void virtser_send(const uint8_t byte) { } #endif +void send_digitizer(report_digitizer_t *report) { +#ifdef DIGITIZER_ENABLE + uint8_t timeout = 255; + + if (USB_DeviceState != DEVICE_STATE_Configured) return; + + Endpoint_SelectEndpoint(DIGITIZER_IN_EPNUM); + + /* Check if write ready for a polling interval around 10ms */ + while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40); + if (!Endpoint_IsReadWriteAllowed()) return; + + Endpoint_Write_Stream_LE(report, sizeof(report_digitizer_t), NULL); + Endpoint_ClearIN(); +#endif +} + /******************************************************************************* * main ******************************************************************************/ diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c index 7a4a790315..099964ae56 100644 --- a/tmk_core/protocol/usb_descriptor.c +++ b/tmk_core/protocol/usb_descriptor.c @@ -158,6 +158,53 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = { # endif #endif +#ifdef DIGITIZER_ENABLE +# ifndef DIGITIZER_SHARED_EP +const USB_Descriptor_HIDReport_Datatype_t PROGMEM DigitizerReport[] = { +# elif !defined(SHARED_REPORT_STARTED) +const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = { +# define SHARED_REPORT_STARTED +# endif + HID_RI_USAGE_PAGE(8, 0x0D), // Digitizers + HID_RI_USAGE(8, 0x01), // Digitizer + HID_RI_COLLECTION(8, 0x01), // Application +# ifdef DIGITIZER_SHARED_EP + HID_RI_REPORT_ID(8, REPORT_ID_DIGITIZER), +# endif + HID_RI_USAGE(8, 0x20), // Stylus + HID_RI_COLLECTION(8, 0x00), // Physical + // Tip Switch (1 bit) + HID_RI_USAGE(8, 0x42), // Tip Switch + HID_RI_LOGICAL_MINIMUM(8, 0x00), + HID_RI_LOGICAL_MAXIMUM(8, 0x01), + HID_RI_REPORT_SIZE(8, 0x01), + HID_RI_REPORT_COUNT(8, 0x01), + HID_RI_INPUT(8, HID_IOF_VARIABLE), + // In Range (1 bit) + HID_RI_USAGE(8, 0x32), // In Range + HID_RI_INPUT(8, HID_IOF_VARIABLE), + // Padding (6 bits) + HID_RI_REPORT_COUNT(8, 0x06), + HID_RI_INPUT(8, HID_IOF_CONSTANT | HID_IOF_VARIABLE), + + // X/Y Position (4 bytes) + HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop + HID_RI_LOGICAL_MAXIMUM(16, 0x7FFF), + HID_RI_REPORT_SIZE(8, 0x10), + HID_RI_REPORT_COUNT(8, 0x01), + HID_RI_UNIT(8, 0x33), // Inch, English Linear + HID_RI_UNIT_EXPONENT(8, 0x0E), // -2 + HID_RI_USAGE(8, 0x30), // X + HID_RI_INPUT(8, HID_IOF_VARIABLE), + HID_RI_USAGE(8, 0x31), // Y + HID_RI_INPUT(8, HID_IOF_VARIABLE), + HID_RI_END_COLLECTION(0), + HID_RI_END_COLLECTION(0), +# ifndef DIGITIZER_SHARED_EP +}; +# endif +#endif + #if defined(SHARED_EP_ENABLE) && !defined(SHARED_REPORT_STARTED) const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = { #endif @@ -227,6 +274,7 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = { HID_RI_OUTPUT(8, HID_IOF_CONSTANT), HID_RI_END_COLLECTION(0), #endif + #ifdef SHARED_EP_ENABLE }; #endif @@ -921,6 +969,46 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = { .PollingIntervalMS = USB_POLLING_INTERVAL_MS } #endif + +#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP) + /* + * Digitizer + */ + .Digitizer_Interface = { + .Header = { + .Size = sizeof(USB_Descriptor_Interface_t), + .Type = DTYPE_Interface + }, + .InterfaceNumber = DIGITIZER_INTERFACE, + .AlternateSetting = 0x00, + .TotalEndpoints = 1, + .Class = HID_CSCP_HIDClass, + .SubClass = HID_CSCP_NonBootSubclass, + .Protocol = HID_CSCP_NonBootProtocol, + .InterfaceStrIndex = NO_DESCRIPTOR + }, + .Digitizer_HID = { + .Header = { + .Size = sizeof(USB_HID_Descriptor_HID_t), + .Type = HID_DTYPE_HID + }, + .HIDSpec = VERSION_BCD(1, 1, 1), + .CountryCode = 0x00, + .TotalReportDescriptors = 1, + .HIDReportType = HID_DTYPE_Report, + .HIDReportLength = sizeof(DigitizerReport) + }, + .Digitizer_INEndpoint = { + .Header = { + .Size = sizeof(USB_Descriptor_Endpoint_t), + .Type = DTYPE_Endpoint + }, + .EndpointAddress = (ENDPOINT_DIR_IN | DIGITIZER_IN_EPNUM), + .Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = DIGITIZER_EPSIZE, + .PollingIntervalMS = USB_POLLING_INTERVAL_MS + }, +#endif }; /* @@ -1059,6 +1147,13 @@ uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const Size = sizeof(USB_HID_Descriptor_HID_t); break; #endif +#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP) + case DIGITIZER_INTERFACE: + Address = &ConfigurationDescriptor.Digitizer_HID; + Size = sizeof(USB_HID_Descriptor_HID_t); + + break; +#endif } break; @@ -1109,6 +1204,12 @@ uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const Size = sizeof(JoystickReport); break; #endif +#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP) + case DIGITIZER_INTERFACE: + Address = &DigitizerReport; + Size = sizeof(DigitizerReport); + break; +#endif } break; diff --git a/tmk_core/protocol/usb_descriptor.h b/tmk_core/protocol/usb_descriptor.h index 867e549b4f..0f0c78f66c 100644 --- a/tmk_core/protocol/usb_descriptor.h +++ b/tmk_core/protocol/usb_descriptor.h @@ -135,6 +135,13 @@ typedef struct { USB_HID_Descriptor_HID_t Joystick_HID; USB_Descriptor_Endpoint_t Joystick_INEndpoint; #endif + +#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP) + // Digitizer HID Interface + USB_Descriptor_Interface_t Digitizer_Interface; + USB_HID_Descriptor_HID_t Digitizer_HID; + USB_Descriptor_Endpoint_t Digitizer_INEndpoint; +#endif } USB_Descriptor_Configuration_t; /* @@ -180,6 +187,10 @@ enum usb_interfaces { #if defined(JOYSTICK_ENABLE) JOYSTICK_INTERFACE, #endif + +#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP) + DIGITIZER_INTERFACE, +#endif TOTAL_INTERFACES }; @@ -226,7 +237,7 @@ enum usb_endpoints { # if STM32_USB_USE_OTG1 # define CONSOLE_OUT_EPNUM CONSOLE_IN_EPNUM # else - CONSOLE_OUT_EPNUM = NEXT_EPNUM, + CONSOLE_OUT_EPNUM = NEXT_EPNUM, # endif # else # define CONSOLE_OUT_EPNUM CONSOLE_IN_EPNUM @@ -259,6 +270,19 @@ enum usb_endpoints { JOYSTICK_OUT_EPNUM = NEXT_EPNUM, # endif #endif + +#ifdef DIGITIZER_ENABLE +# if !defined(DIGITIZER_SHARED_EP) + DIGITIZER_IN_EPNUM = NEXT_EPNUM, +# if STM32_USB_USE_OTG1 + DIGITIZER_OUT_EPNUM = DIGITIZER_IN_EPNUM, +# else + DIGITIZER_OUT_EPNUM = NEXT_EPNUM, +# endif +# else +# define DIGITIZER_IN_EPNUM SHARED_IN_EPNUM +# endif +#endif }; #ifdef PROTOCOL_LUFA @@ -284,5 +308,6 @@ enum usb_endpoints { #define CDC_NOTIFICATION_EPSIZE 8 #define CDC_EPSIZE 16 #define JOYSTICK_EPSIZE 8 +#define DIGITIZER_EPSIZE 8 uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const void** const DescriptorAddress); diff --git a/tmk_core/protocol/vusb/vusb.c b/tmk_core/protocol/vusb/vusb.c index 98cebf6012..485b20c900 100644 --- a/tmk_core/protocol/vusb/vusb.c +++ b/tmk_core/protocol/vusb/vusb.c @@ -292,6 +292,14 @@ static void send_consumer(uint16_t data) { #endif } +void send_digitizer(report_digitizer_t *report) { +#ifdef DIGITIZER_ENABLE + if (usbInterruptIsReadyShared()) { + usbSetInterruptShared((void *)report, sizeof(report_digitizer_t)); + } +#endif +} + /*------------------------------------------------------------------* * Request from host * *------------------------------------------------------------------*/ @@ -510,8 +518,46 @@ const PROGMEM uchar shared_hid_report[] = { 0x95, 0x01, // Report Count (1) 0x75, 0x10, // Report Size (16) 0x81, 0x00, // Input (Data, Array, Absolute) - 0xC0 // End Collection + 0xC0, // End Collection +#endif + +#ifdef DIGITIZER_ENABLE + // Digitizer report descriptor + 0x05, 0x0D, // Usage Page (Digitizers) + 0x09, 0x01, // Usage (Digitizer) + 0xA1, 0x01, // Collection (Application) + 0x85, REPORT_ID_DIGITIZER, // Report ID + 0x09, 0x22, // Usage (Finger) + 0xA1, 0x00, // Collection (Physical) + // Tip Switch (1 bit) + 0x09, 0x42, // Usage (Tip Switch) + 0x15, 0x00, // Logical Minimum + 0x25, 0x01, // Logical Maximum + 0x95, 0x01, // Report Count (1) + 0x75, 0x01, // Report Size (16) + 0x81, 0x02, // Input (Data, Variable, Absolute) + // In Range (1 bit) + 0x09, 0x32, // Usage (In Range) + 0x81, 0x02, // Input (Data, Variable, Absolute) + // Padding (6 bits) + 0x95, 0x06, // Report Count (6) + 0x81, 0x03, // Input (Constant) + + // X/Y Position (4 bytes) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x26, 0xFF, 0x7F, // Logical Maximum (32767) + 0x95, 0x01, // Report Count (1) + 0x75, 0x10, // Report Size (16) + 0x65, 0x33, // Unit (Inch, English Linear) + 0x55, 0x0E, // Unit Exponent (-2) + 0x09, 0x30, // Usage (X) + 0x81, 0x02, // Input (Data, Variable, Absolute) + 0x09, 0x31, // Usage (Y) + 0x81, 0x02, // Input (Data, Variable, Absolute) + 0xC0, // End Collection + 0xC0 // End Collection #endif + #ifdef SHARED_EP_ENABLE }; #endif |