mirror of
				https://github.com/mfulz/qmk_firmware.git
				synced 2025-10-31 05:12:33 +01:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									7794e97f32
								
							
						
					
					
						commit
						75b49aff56
					
				| @ -695,6 +695,11 @@ ifeq ($(strip $(JOYSTICK_ENABLE)), digital) | |||||||
|     OPT_DEFS += -DDIGITAL_JOYSTICK_ENABLE |     OPT_DEFS += -DDIGITAL_JOYSTICK_ENABLE | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
|  | DIGITIZER_ENABLE ?= no | ||||||
|  | ifneq ($(strip $(DIGITIZER_ENABLE)), no) | ||||||
|  |     SRC += $(QUANTUM_DIR)/digitizer.c | ||||||
|  | endif | ||||||
|  | 
 | ||||||
| USBPD_ENABLE ?= no | USBPD_ENABLE ?= no | ||||||
| VALID_USBPD_DRIVER_TYPES = custom vendor | VALID_USBPD_DRIVER_TYPES = custom vendor | ||||||
| USBPD_DRIVER ?= vendor | USBPD_DRIVER ?= vendor | ||||||
|  | |||||||
| @ -108,6 +108,7 @@ | |||||||
|     * [Bluetooth](feature_bluetooth.md) |     * [Bluetooth](feature_bluetooth.md) | ||||||
|     * [Bootmagic Lite](feature_bootmagic.md) |     * [Bootmagic Lite](feature_bootmagic.md) | ||||||
|     * [Custom Matrix](custom_matrix.md) |     * [Custom Matrix](custom_matrix.md) | ||||||
|  |     * [Digitizer](feature_digitizer.md) | ||||||
|     * [DIP Switch](feature_dip_switch.md) |     * [DIP Switch](feature_dip_switch.md) | ||||||
|     * [Encoders](feature_encoders.md) |     * [Encoders](feature_encoders.md) | ||||||
|     * [Haptic Feedback](feature_haptic_feedback.md) |     * [Haptic Feedback](feature_haptic_feedback.md) | ||||||
|  | |||||||
							
								
								
									
										35
									
								
								docs/feature_digitizer.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								docs/feature_digitizer.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | ## Digitizer | ||||||
|  | 
 | ||||||
|  | The digitizer HID interface allows setting the mouse cursor position at absolute coordinates, unlike the Pointing Device feature that applies relative displacements. | ||||||
|  | 
 | ||||||
|  | To enable the digitizer interface, add the following line to your rules.mk:  | ||||||
|  | 
 | ||||||
|  | ```makefile | ||||||
|  | DIGITIZER_ENABLE = yes | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | In order to change the mouse cursor position from your keymap.c file, include the digitizer header :  | ||||||
|  | 
 | ||||||
|  | ```c | ||||||
|  | #include "digitizer.h" | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | This gives you access to the `digitizer` structure which members allow you to change the cursor position. | ||||||
|  | 
 | ||||||
|  | The coordinates are normalized, meaning there value must be set between 0 and 1. For the `x` coordinate, the value `0` is the leftmost position, whereas the value `1` is the rightmost position. | ||||||
|  | For the `y` coordinate, `0` is at the top and `1` at the bottom. | ||||||
|  | 
 | ||||||
|  | Here is an example setting the cursor in the middle of the screen: | ||||||
|  | 
 | ||||||
|  | ```c | ||||||
|  | digitizer_t digitizer; | ||||||
|  | digitizer.x = 0.5; | ||||||
|  | digitizer.y = 0.5; | ||||||
|  | digitizer.tipswitch = 0; | ||||||
|  | digitizer.inrange = 1; | ||||||
|  | digitizer_set_report(digitizer); | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The `tipswitch` member triggers what equates to a click when set to `1`. The `inrange` member is required for the change in coordinates to be taken. It can then be set to `0` in a new report to signal the end of the digitizer interaction, but it is not strictly required. | ||||||
|  | 
 | ||||||
|  | Once all members are set to the desired value, the `status` member needs its bitmask `DZ_UPDATED` to be set so the report is sent during the next main loop iteration. | ||||||
							
								
								
									
										38
									
								
								keyboards/handwired/onekey/keymaps/digitizer/keymap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								keyboards/handwired/onekey/keymaps/digitizer/keymap.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | |||||||
|  |  /* Copyright 2021 QMK 
 | ||||||
|  |   *  | ||||||
|  |   * This program is free software: you can redistribute it and/or modify  | ||||||
|  |   * it under the terms of the GNU General Public License as published by  | ||||||
|  |   * the Free Software Foundation, either version 2 of the License, or  | ||||||
|  |   * (at your option) any later version.  | ||||||
|  |   *  | ||||||
|  |   * This program is distributed in the hope that it will be useful,  | ||||||
|  |   * but WITHOUT ANY WARRANTY; without even the implied warranty of  | ||||||
|  |   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  | ||||||
|  |   * GNU General Public License for more details.  | ||||||
|  |   *  | ||||||
|  |   * You should have received a copy of the GNU General Public License  | ||||||
|  |   * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 | ||||||
|  |   */  | ||||||
|  | #include QMK_KEYBOARD_H | ||||||
|  | 
 | ||||||
|  | #include "digitizer.h" | ||||||
|  | 
 | ||||||
|  | #include "math.h" | ||||||
|  | 
 | ||||||
|  | const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {LAYOUT_ortho_1x1(KC_A)}; | ||||||
|  | 
 | ||||||
|  | uint32_t timer = 0; | ||||||
|  | 
 | ||||||
|  | void matrix_scan_user() { | ||||||
|  |     if (timer_elapsed32(timer) < 200) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     timer               = timer_read32(); | ||||||
|  |     digitizer_t digitizer; | ||||||
|  |     digitizer.x         = 0.5 - 0.2 * cos(timer_read() / 250. / 6.28); | ||||||
|  |     digitizer.y         = 0.5 - 0.2 * sin(timer_read() / 250. / 6.28); | ||||||
|  |     digitizer.tipswitch = 0; | ||||||
|  |     digitizer.inrange   = 1; | ||||||
|  |     digitizer_set_report(digitizer); | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								keyboards/handwired/onekey/keymaps/digitizer/rules.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								keyboards/handwired/onekey/keymaps/digitizer/rules.mk
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | DIGITIZER_ENABLE = yes | ||||||
							
								
								
									
										34
									
								
								quantum/digitizer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								quantum/digitizer.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | |||||||
|  | /* Copyright 2021
 | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU General Public License as published by | ||||||
|  |  * the Free Software Foundation, either version 2 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU General Public License | ||||||
|  |  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  |  */ | ||||||
|  | #include "digitizer.h" | ||||||
|  | 
 | ||||||
|  | digitizer_t digitizerReport = {.tipswitch = 0, .inrange = 0, .id = 0, .x = 0, .y = 0, .status = DZ_INITIALIZED}; | ||||||
|  | 
 | ||||||
|  | __attribute__((weak)) void digitizer_send(void) { | ||||||
|  |     if (digitizerReport.status & DZ_UPDATED) { | ||||||
|  |         host_digitizer_send(&digitizerReport); | ||||||
|  |         digitizerReport.status &= ~DZ_UPDATED; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | __attribute__((weak)) void digitizer_task(void) { digitizer_send(); } | ||||||
|  | 
 | ||||||
|  | digitizer_t digitizer_get_report(void) { return digitizerReport; } | ||||||
|  | 
 | ||||||
|  | void digitizer_set_report(digitizer_t newDigitizerReport) { | ||||||
|  |     digitizerReport = newDigitizerReport; | ||||||
|  |     digitizerReport.status |= DZ_UPDATED; | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								quantum/digitizer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								quantum/digitizer.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | /* Copyright 2021
 | ||||||
|  |  * | ||||||
|  |  * This program is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU General Public License as published by | ||||||
|  |  * the Free Software Foundation, either version 2 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * 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 | ||||||
|  | 
 | ||||||
|  | #include "quantum.h" | ||||||
|  | 
 | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | enum digitizer_status { DZ_INITIALIZED = 1, DZ_UPDATED = 2 }; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     int8_t  tipswitch; | ||||||
|  |     int8_t  inrange; | ||||||
|  |     uint8_t id; | ||||||
|  |     float   x; | ||||||
|  |     float   y; | ||||||
|  |     uint8_t status : 2; | ||||||
|  | } digitizer_t; | ||||||
|  | 
 | ||||||
|  | extern digitizer_t digitizer; | ||||||
|  | 
 | ||||||
|  | digitizer_t digitizer_get_report(void); | ||||||
|  | 
 | ||||||
|  | void digitizer_set_report(digitizer_t newDigitizerReport); | ||||||
|  | 
 | ||||||
|  | void digitizer_task(void); | ||||||
|  | 
 | ||||||
|  | void host_digitizer_send(digitizer_t *digitizer); | ||||||
| @ -106,6 +106,19 @@ ifeq ($(strip $(NO_USB_STARTUP_CHECK)), yes) | |||||||
|     TMK_COMMON_DEFS += -DNO_USB_STARTUP_CHECK |     TMK_COMMON_DEFS += -DNO_USB_STARTUP_CHECK | ||||||
| endif | 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) | ifeq ($(strip $(SHARED_EP_ENABLE)), yes) | ||||||
|     TMK_COMMON_DEFS += -DSHARED_EP_ENABLE |     TMK_COMMON_DEFS += -DSHARED_EP_ENABLE | ||||||
| endif | endif | ||||||
|  | |||||||
| @ -22,6 +22,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>. | |||||||
| #include "host.h" | #include "host.h" | ||||||
| #include "util.h" | #include "util.h" | ||||||
| #include "debug.h" | #include "debug.h" | ||||||
|  | #include "digitizer.h" | ||||||
| 
 | 
 | ||||||
| #ifdef NKRO_ENABLE | #ifdef NKRO_ENABLE | ||||||
| #    include "keycode_config.h" | #    include "keycode_config.h" | ||||||
| @ -103,6 +104,24 @@ void host_consumer_send(uint16_t report) { | |||||||
|     (*driver->send_consumer)(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_system_report(void) { return last_system_report; } | ||||||
| 
 | 
 | ||||||
| uint16_t host_last_consumer_report(void) { return last_consumer_report; } | uint16_t host_last_consumer_report(void) { return last_consumer_report; } | ||||||
|  | |||||||
| @ -30,3 +30,5 @@ typedef struct { | |||||||
|     void (*send_system)(uint16_t); |     void (*send_system)(uint16_t); | ||||||
|     void (*send_consumer)(uint16_t); |     void (*send_consumer)(uint16_t); | ||||||
| } host_driver_t; | } host_driver_t; | ||||||
|  | 
 | ||||||
|  | void send_digitizer(report_digitizer_t *report); | ||||||
| @ -106,6 +106,9 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>. | |||||||
| #if defined(CRC_ENABLE) | #if defined(CRC_ENABLE) | ||||||
| #    include "crc.h" | #    include "crc.h" | ||||||
| #endif | #endif | ||||||
|  | #ifdef DIGITIZER_ENABLE | ||||||
|  | #    include "digitizer.h" | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| static uint32_t last_input_modification_time = 0; | static uint32_t last_input_modification_time = 0; | ||||||
| uint32_t        last_input_activity_time(void) { return last_input_modification_time; } | uint32_t        last_input_activity_time(void) { return last_input_modification_time; } | ||||||
| @ -537,6 +540,10 @@ MATRIX_LOOP_END: | |||||||
|     joystick_task(); |     joystick_task(); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef DIGITIZER_ENABLE | ||||||
|  |     digitizer_task(); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|     // update LED
 |     // update LED
 | ||||||
|     if (led_status != host_keyboard_leds()) { |     if (led_status != host_keyboard_leds()) { | ||||||
|         led_status = host_keyboard_leds(); |         led_status = host_keyboard_leds(); | ||||||
|  | |||||||
| @ -30,7 +30,8 @@ enum hid_report_ids { | |||||||
|     REPORT_ID_SYSTEM, |     REPORT_ID_SYSTEM, | ||||||
|     REPORT_ID_CONSUMER, |     REPORT_ID_CONSUMER, | ||||||
|     REPORT_ID_NKRO, |     REPORT_ID_NKRO, | ||||||
|     REPORT_ID_JOYSTICK |     REPORT_ID_JOYSTICK, | ||||||
|  |     REPORT_ID_DIGITIZER | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* Mouse buttons */ | /* Mouse buttons */ | ||||||
| @ -205,6 +206,17 @@ typedef struct { | |||||||
|     int8_t  h; |     int8_t  h; | ||||||
| } __attribute__((packed)) report_mouse_t; | } __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 { | typedef struct { | ||||||
| #if JOYSTICK_AXES_COUNT > 0 | #if JOYSTICK_AXES_COUNT > 0 | ||||||
| #    if JOYSTICK_AXES_RESOLUTION > 8 | #    if JOYSTICK_AXES_RESOLUTION > 8 | ||||||
|  | |||||||
| @ -65,6 +65,7 @@ void    send_keyboard(report_keyboard_t *report); | |||||||
| void    send_mouse(report_mouse_t *report); | void    send_mouse(report_mouse_t *report); | ||||||
| void    send_system(uint16_t data); | void    send_system(uint16_t data); | ||||||
| void    send_consumer(uint16_t data); | void    send_consumer(uint16_t data); | ||||||
|  | void    send_digitizer(report_digitizer_t *report); | ||||||
| 
 | 
 | ||||||
| /* host struct */ | /* host struct */ | ||||||
| host_driver_t chibios_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer}; | host_driver_t chibios_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer}; | ||||||
|  | |||||||
| @ -315,6 +315,9 @@ typedef struct { | |||||||
| #endif | #endif | ||||||
| #ifdef JOYSTICK_ENABLE | #ifdef JOYSTICK_ENABLE | ||||||
|             usb_driver_config_t joystick_driver; |             usb_driver_config_t joystick_driver; | ||||||
|  | #endif | ||||||
|  | #if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP) | ||||||
|  |             usb_driver_config_t digitizer_driver; | ||||||
| #endif | #endif | ||||||
|         }; |         }; | ||||||
|         usb_driver_config_t array[0]; |         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 | #    define JOYSTICK_OUT_MODE USB_EP_MODE_TYPE_BULK | ||||||
|     .joystick_driver = QMK_USB_DRIVER_CONFIG(JOYSTICK, 0, false), |     .joystick_driver = QMK_USB_DRIVER_CONFIG(JOYSTICK, 0, false), | ||||||
| #endif | #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)) | #define NUM_USB_DRIVERS (sizeof(drivers) / sizeof(usb_driver_config_t)) | ||||||
| @ -930,6 +941,23 @@ void send_consumer(uint16_t data) { | |||||||
| #endif | #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 |  *                   Console functions | ||||||
|  * --------------------------------------------------------- |  * --------------------------------------------------------- | ||||||
|  | |||||||
| @ -142,9 +142,7 @@ static void    send_keyboard(report_keyboard_t *report); | |||||||
| static void    send_mouse(report_mouse_t *report); | static void    send_mouse(report_mouse_t *report); | ||||||
| static void    send_system(uint16_t data); | static void    send_system(uint16_t data); | ||||||
| static void    send_consumer(uint16_t data); | static void    send_consumer(uint16_t data); | ||||||
| host_driver_t  lufa_driver = { | host_driver_t  lufa_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer}; | ||||||
|     keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| #ifdef VIRTSER_ENABLE | #ifdef VIRTSER_ENABLE | ||||||
| // clang-format off
 | // clang-format off
 | ||||||
| @ -525,6 +523,11 @@ void EVENT_USB_Device_ConfigurationChanged(void) { | |||||||
|     /* Setup joystick endpoint */ |     /* Setup joystick endpoint */ | ||||||
|     ConfigSuccess &= Endpoint_ConfigureEndpoint((JOYSTICK_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_INTERRUPT, JOYSTICK_EPSIZE, 1); |     ConfigSuccess &= Endpoint_ConfigureEndpoint((JOYSTICK_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_INTERRUPT, JOYSTICK_EPSIZE, 1); | ||||||
| #endif | #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
 | /* FIXME: Expose this table in the docs somehow
 | ||||||
| @ -983,6 +986,23 @@ void virtser_send(const uint8_t byte) { | |||||||
| } | } | ||||||
| #endif | #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 |  * main | ||||||
|  ******************************************************************************/ |  ******************************************************************************/ | ||||||
|  | |||||||
| @ -158,6 +158,53 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = { | |||||||
| #    endif | #    endif | ||||||
| #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) | #if defined(SHARED_EP_ENABLE) && !defined(SHARED_REPORT_STARTED) | ||||||
| const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = { | const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = { | ||||||
| #endif | #endif | ||||||
| @ -227,6 +274,7 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = { | |||||||
|         HID_RI_OUTPUT(8, HID_IOF_CONSTANT), |         HID_RI_OUTPUT(8, HID_IOF_CONSTANT), | ||||||
|     HID_RI_END_COLLECTION(0), |     HID_RI_END_COLLECTION(0), | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
| #ifdef SHARED_EP_ENABLE | #ifdef SHARED_EP_ENABLE | ||||||
| }; | }; | ||||||
| #endif | #endif | ||||||
| @ -921,6 +969,46 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = { | |||||||
|         .PollingIntervalMS      = USB_POLLING_INTERVAL_MS |         .PollingIntervalMS      = USB_POLLING_INTERVAL_MS | ||||||
|     } |     } | ||||||
| #endif | #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); |                     Size    = sizeof(USB_HID_Descriptor_HID_t); | ||||||
|                     break; |                     break; | ||||||
| #endif | #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; |             break; | ||||||
| @ -1108,6 +1203,12 @@ uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const | |||||||
|                     Address = &JoystickReport; |                     Address = &JoystickReport; | ||||||
|                     Size    = sizeof(JoystickReport); |                     Size    = sizeof(JoystickReport); | ||||||
|                     break; |                     break; | ||||||
|  | #endif | ||||||
|  | #if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP) | ||||||
|  |                 case DIGITIZER_INTERFACE: | ||||||
|  |                     Address = &DigitizerReport; | ||||||
|  |                     Size    = sizeof(DigitizerReport); | ||||||
|  |                     break; | ||||||
| #endif | #endif | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -135,6 +135,13 @@ typedef struct { | |||||||
|     USB_HID_Descriptor_HID_t   Joystick_HID; |     USB_HID_Descriptor_HID_t   Joystick_HID; | ||||||
|     USB_Descriptor_Endpoint_t  Joystick_INEndpoint; |     USB_Descriptor_Endpoint_t  Joystick_INEndpoint; | ||||||
| #endif | #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; | } USB_Descriptor_Configuration_t; | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
| @ -180,6 +187,10 @@ enum usb_interfaces { | |||||||
| #if defined(JOYSTICK_ENABLE) | #if defined(JOYSTICK_ENABLE) | ||||||
|     JOYSTICK_INTERFACE, |     JOYSTICK_INTERFACE, | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  | #if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP) | ||||||
|  |     DIGITIZER_INTERFACE, | ||||||
|  | #endif | ||||||
|     TOTAL_INTERFACES |     TOTAL_INTERFACES | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -226,7 +237,7 @@ enum usb_endpoints { | |||||||
| #        if STM32_USB_USE_OTG1 | #        if STM32_USB_USE_OTG1 | ||||||
| #            define CONSOLE_OUT_EPNUM CONSOLE_IN_EPNUM | #            define CONSOLE_OUT_EPNUM CONSOLE_IN_EPNUM | ||||||
| #        else | #        else | ||||||
|     CONSOLE_OUT_EPNUM = NEXT_EPNUM, |     CONSOLE_OUT_EPNUM   = NEXT_EPNUM, | ||||||
| #        endif | #        endif | ||||||
| #    else | #    else | ||||||
| #        define CONSOLE_OUT_EPNUM CONSOLE_IN_EPNUM | #        define CONSOLE_OUT_EPNUM CONSOLE_IN_EPNUM | ||||||
| @ -259,6 +270,19 @@ enum usb_endpoints { | |||||||
|     JOYSTICK_OUT_EPNUM    = NEXT_EPNUM, |     JOYSTICK_OUT_EPNUM    = NEXT_EPNUM, | ||||||
| #    endif | #    endif | ||||||
| #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 | #ifdef PROTOCOL_LUFA | ||||||
| @ -284,5 +308,6 @@ enum usb_endpoints { | |||||||
| #define CDC_NOTIFICATION_EPSIZE 8 | #define CDC_NOTIFICATION_EPSIZE 8 | ||||||
| #define CDC_EPSIZE 16 | #define CDC_EPSIZE 16 | ||||||
| #define JOYSTICK_EPSIZE 8 | #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); | uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const void** const DescriptorAddress); | ||||||
|  | |||||||
| @ -292,6 +292,14 @@ static void send_consumer(uint16_t data) { | |||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void send_digitizer(report_digitizer_t *report) { | ||||||
|  | #ifdef DIGITIZER_ENABLE | ||||||
|  |     if (usbInterruptIsReadyShared()) { | ||||||
|  |         usbSetInterruptShared((void *)report, sizeof(report_digitizer_t)); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*------------------------------------------------------------------*
 | /*------------------------------------------------------------------*
 | ||||||
|  * Request from host                                                * |  * Request from host                                                * | ||||||
|  *------------------------------------------------------------------*/ |  *------------------------------------------------------------------*/ | ||||||
| @ -510,8 +518,46 @@ const PROGMEM uchar shared_hid_report[] = { | |||||||
|     0x95, 0x01,                //   Report Count (1)
 |     0x95, 0x01,                //   Report Count (1)
 | ||||||
|     0x75, 0x10,                //   Report Size (16)
 |     0x75, 0x10,                //   Report Size (16)
 | ||||||
|     0x81, 0x00,                //   Input (Data, Array, Absolute)
 |     0x81, 0x00,                //   Input (Data, Array, Absolute)
 | ||||||
|     0xC0                       // End Collection
 |     0xC0,                      // End Collection
 | ||||||
| #endif | #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 | #ifdef SHARED_EP_ENABLE | ||||||
| }; | }; | ||||||
| #endif | #endif | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 a-chol
						a-chol