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
18 changed files with 435 additions and 6 deletions
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
#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
|
0xC0 // End Collection
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SHARED_EP_ENABLE
|
#ifdef SHARED_EP_ENABLE
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue