~ruther/qmk_firmware

75b49aff56436c57a424e622c91f6d80e1d0ecc2 — a-chol 4 years ago 7794e97
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>
M common_features.mk => common_features.mk +5 -0
@@ 695,6 695,11 @@ ifeq ($(strip $(JOYSTICK_ENABLE)), digital)
    OPT_DEFS += -DDIGITAL_JOYSTICK_ENABLE
endif

DIGITIZER_ENABLE ?= no
ifneq ($(strip $(DIGITIZER_ENABLE)), no)
    SRC += $(QUANTUM_DIR)/digitizer.c
endif

USBPD_ENABLE ?= no
VALID_USBPD_DRIVER_TYPES = custom vendor
USBPD_DRIVER ?= vendor

M docs/_summary.md => docs/_summary.md +1 -0
@@ 108,6 108,7 @@
    * [Bluetooth](feature_bluetooth.md)
    * [Bootmagic Lite](feature_bootmagic.md)
    * [Custom Matrix](custom_matrix.md)
    * [Digitizer](feature_digitizer.md)
    * [DIP Switch](feature_dip_switch.md)
    * [Encoders](feature_encoders.md)
    * [Haptic Feedback](feature_haptic_feedback.md)

A docs/feature_digitizer.md => docs/feature_digitizer.md +35 -0
@@ 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.

A keyboards/handwired/onekey/keymaps/digitizer/keymap.c => keyboards/handwired/onekey/keymaps/digitizer/keymap.c +38 -0
@@ 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);
}

A keyboards/handwired/onekey/keymaps/digitizer/rules.mk => keyboards/handwired/onekey/keymaps/digitizer/rules.mk +1 -0
@@ 0,0 1,1 @@
DIGITIZER_ENABLE = yes
\ No newline at end of file

A quantum/digitizer.c => quantum/digitizer.c +34 -0
@@ 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;
}
\ No newline at end of file

A quantum/digitizer.h => quantum/digitizer.h +41 -0
@@ 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);

M tmk_core/common.mk => tmk_core/common.mk +13 -0
@@ 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

M tmk_core/common/host.c => tmk_core/common/host.c +19 -0
@@ 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; }

M tmk_core/common/host_driver.h => tmk_core/common/host_driver.h +2 -0
@@ 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

M tmk_core/common/keyboard.c => tmk_core/common/keyboard.c +7 -0
@@ 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();

M tmk_core/common/report.h => tmk_core/common/report.h +13 -1
@@ 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];

M tmk_core/protocol/chibios/main.c => tmk_core/protocol/chibios/main.c +1 -0
@@ 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};

M tmk_core/protocol/chibios/usb_main.c => tmk_core/protocol/chibios/usb_main.c +28 -0
@@ 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
 * ---------------------------------------------------------

M tmk_core/protocol/lufa/lufa.c => tmk_core/protocol/lufa/lufa.c +23 -3
@@ 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
 ******************************************************************************/

M tmk_core/protocol/usb_descriptor.c => tmk_core/protocol/usb_descriptor.c +101 -0
@@ 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;

M tmk_core/protocol/usb_descriptor.h => tmk_core/protocol/usb_descriptor.h +26 -1
@@ 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);

M tmk_core/protocol/vusb/vusb.c => tmk_core/protocol/vusb/vusb.c +47 -1
@@ 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