Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add hid_raw feature to VUSB #8380

Merged
merged 6 commits into from
Mar 30, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions tmk_core/protocol/vusb/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ int main(void) {
keyboard_task();
}
vusb_transfer_keyboard();
#ifdef RAW_ENABLE
usbPoll();

if (usbConfiguration && usbInterruptIsReady3()) {
raw_hid_task();
}
#endif
}
}
}
162 changes: 161 additions & 1 deletion tmk_core/protocol/vusb/vusb.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "vusb.h"
#include <util/delay.h>

#if defined(RAW_ENABLE)
# include "raw_hid.h"
#endif

#if (defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)) && defined(RAW_ENABLE)
# error "can't use mouse/extra key and hid raw at same time on VUSB"
hsgw marked this conversation as resolved.
Show resolved Hide resolved
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC, this is handled automatically, and should error out anyways, if there are too many endpoints enabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be handled in makefile? Now this is not implemented in makefile.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is good as it is now, as it's explicit about the mutual exclusivity and conditional compilation requirement of this code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, Leave this as it is.

Copy link
Member

@drashna drashna Mar 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, okay, LUFA and ChibiOS has a check for the number of endpoints, but V-USB doesn't.

This is fine, for now, but is something that we would want to change in the near future, @fauxpark?

For reference:

#if (NEXT_EPNUM - 1) > MAX_ENDPOINTS
# error There are not enough available endpoints to support all functions. Please disable one or more of the following: Mouse Keys, Extra Keys, Console, NKRO, MIDI, Serial, Steno
#endif

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zvecr 's console PR #8559 includes something like that - perhaps we should pull that out and merge it first to simplify both these PRs.


static uint8_t vusb_keyboard_leds = 0;
static uint8_t vusb_idle_rate = 0;

Expand Down Expand Up @@ -71,6 +79,52 @@ void vusb_transfer_keyboard(void) {
}
}

/*------------------------------------------------------------------*
* RAW HID
*------------------------------------------------------------------*/
#ifdef RAW_ENABLE
# define RAW_INPUT_SIZE (32)
# define RAW_OUTPUT_SIZE (32)
fauxpark marked this conversation as resolved.
Show resolved Hide resolved

static uint8_t raw_output_buffer[RAW_OUTPUT_SIZE];
hsgw marked this conversation as resolved.
Show resolved Hide resolved
static uint8_t raw_output_recieved_bytes = 0;
hsgw marked this conversation as resolved.
Show resolved Hide resolved

void raw_hid_send(uint8_t *data, uint8_t length) {
if (length != RAW_INPUT_SIZE) {
hsgw marked this conversation as resolved.
Show resolved Hide resolved
return;
}

uint8_t *temp = data;
for (uint8_t i = 0; i < 4; i++) {
while (!usbInterruptIsReady3()) {
usbPoll();
}
usbSetInterrupt3(temp, 8);
temp += 8;
}
while (!usbInterruptIsReady3()) {
usbPoll();
}
usbSetInterrupt3(0, 0);
usbPoll();
_delay_ms(1);
}

__attribute__((weak)) void raw_hid_receive(uint8_t *data, uint8_t length) {
// Users should #include "raw_hid.h" in their own code
// and implement this function there. Leave this as weak linkage
// so users can opt to not handle data coming in.
}

void raw_hid_task(void) {
if (raw_output_recieved_bytes == RAW_OUTPUT_SIZE) {
raw_hid_receive(raw_output_buffer, RAW_OUTPUT_SIZE);
raw_output_recieved_bytes = 0;
}
}

#endif

/*------------------------------------------------------------------*
* Host driver
*------------------------------------------------------------------*/
Expand Down Expand Up @@ -206,6 +260,27 @@ uchar usbFunctionWrite(uchar *data, uchar len) {
return 1;
}

void usbFunctionWriteOut(uchar *data, uchar len) {
#ifdef RAW_ENABLE
// Data from host must be divided every 8bytes
if (len != 8) {
debug("RAW: invalid length");
raw_output_recieved_bytes = 0;
return;
}

if (raw_output_recieved_bytes + len > RAW_OUTPUT_SIZE) {
debug("RAW: buffer full");
raw_output_recieved_bytes = 0;
} else {
for (uint8_t i = 0; i < 8; i++) {
raw_output_buffer[raw_output_recieved_bytes + i] = data[i];
}
raw_output_recieved_bytes += len;
}
#endif
}

/*------------------------------------------------------------------*
* Descriptors *
*------------------------------------------------------------------*/
Expand Down Expand Up @@ -335,6 +410,31 @@ const PROGMEM uchar mouse_extra_hid_report[] = {
};
#endif

#if defined(RAW_ENABLE)
const PROGMEM uchar raw_hid_report[] = {
0x06, 0x60, 0xFF, // Usage Page (Vender Defined)
0x09, 0x61, // Usage (Vender Defined)
0xA1, 0x01, // Collection (Application)
// Data to host
0x09, 0x62, // Vender Defined
0x15, 0x00, // Logical Minimum
0x26, 0xFF, 0x00, // Logical Maximum
0x95, RAW_INPUT_SIZE, // Report Count (8)
0x75, 0x08, // Report Size (8)
0x81, 0x02, // Input (Data, Variable, Absolute)
// (0 << 0) | (1 << 1) | (0 << 2)
// Data from host
0x09, 0x63, // Vender Defined
0x15, 0x00, // Logical Minimum
0x26, 0xFF, 0x00, // Logical Maximum
0x95, RAW_OUTPUT_SIZE, // Report Count (32)
0x75, 0x08, // Report Size (8)
0x91, 0x02, // Output (Data, Variable, Absolute, None-Volatile)
// (0 << 0) | (1 << 1) | (0 << 2) | (0 << 7)
0xC0, // End Collection
hsgw marked this conversation as resolved.
Show resolved Hide resolved
};
#endif

#ifndef SERIAL_NUMBER
# define SERIAL_NUMBER 0
#endif
Expand Down Expand Up @@ -416,7 +516,7 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = {
.bDescriptorType = USBDESCR_CONFIG
},
.wTotalLength = sizeof(usbConfigurationDescriptor_t),
# if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
# if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE) || defined(RAW_ENABLE)
.bNumInterfaces = 2,
# else
.bNumInterfaces = 1,
Expand Down Expand Up @@ -512,6 +612,54 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = {
}
# endif
# endif
# if defined(RAW_ENABLE)
hsgw marked this conversation as resolved.
Show resolved Hide resolved
.rawInterface = {
hsgw marked this conversation as resolved.
Show resolved Hide resolved
.header = {
.bLength = sizeof(usbInterfaceDescriptor_t),
hsgw marked this conversation as resolved.
Show resolved Hide resolved
.bDescriptorType = USBDESCR_INTERFACE
},
.bInterfaceNumber = 1,
.bAlternateSetting = 0x00,
.bNumEndpoints = 2,
.bInterfaceClass = 0x03,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.iInterface = 0x00
},
.rawHID = {
.header = {
.bLength = sizeof(usbHIDDescriptor_t),
.bDescriptorType = USBDESCR_HID
},
.bcdHID = 0x0101,
.bCountryCode = 0x00,
.bNumDescriptors = 2,
.bDescriptorType = USBDESCR_HID_REPORT,
.wDescriptorLength = sizeof(raw_hid_report)
},
# if USB_CFG_HAVE_INTRIN_ENDPOINT3 /* endpoint descriptor for endpoint 3 */
hsgw marked this conversation as resolved.
Show resolved Hide resolved
.rawINEndpoint = {
.header = {
.bLength = sizeof(usbEndpointDescriptor_t),
.bDescriptorType = USBDESCR_ENDPOINT
},
.bEndpointAddress = (USBRQ_DIR_DEVICE_TO_HOST | USB_CFG_EP3_NUMBER),
.bmAttributes = 0x03,
.wMaxPacketSize = 8,
hsgw marked this conversation as resolved.
Show resolved Hide resolved
.bInterval = USB_POLLING_INTERVAL_MS
},
.rawOUTEndpoint = {
.header = {
.bLength = sizeof(usbEndpointDescriptor_t),
.bDescriptorType = USBDESCR_ENDPOINT
},
.bEndpointAddress = (USBRQ_DIR_HOST_TO_DEVICE | USB_CFG_EP3_NUMBER),
.bmAttributes = 0x03,
.wMaxPacketSize = 8,
hsgw marked this conversation as resolved.
Show resolved Hide resolved
.bInterval = USB_POLLING_INTERVAL_MS
}
# endif
# endif
};
#endif

Expand Down Expand Up @@ -572,6 +720,12 @@ USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) {
usbMsgPtr = (unsigned char *)&usbConfigurationDescriptor.mouseExtraHID;
len = sizeof(usbHIDDescriptor_t);
break;
#endif
#if defined(RAW_ENABLE)
hsgw marked this conversation as resolved.
Show resolved Hide resolved
case 1:
usbMsgPtr = (unsigned char *)&usbConfigurationDescriptor.rawHID;
len = 9;
hsgw marked this conversation as resolved.
Show resolved Hide resolved
break;
#endif
}
break;
Expand All @@ -587,6 +741,12 @@ USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) {
usbMsgPtr = (unsigned char *)mouse_extra_hid_report;
len = sizeof(mouse_extra_hid_report);
break;
#endif
#if defined(RAW_ENABLE)
hsgw marked this conversation as resolved.
Show resolved Hide resolved
case 1:
usbMsgPtr = (unsigned char *)raw_hid_report;
len = sizeof(raw_hid_report);
break;
#endif
}
break;
Expand Down
13 changes: 13 additions & 0 deletions tmk_core/protocol/vusb/vusb.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,22 @@ typedef struct usbConfigurationDescriptor {
usbEndpointDescriptor_t mouseExtraINEndpoint;
# endif
#endif

#if defined(RAW_ENABLE)
hsgw marked this conversation as resolved.
Show resolved Hide resolved
usbInterfaceDescriptor_t rawInterface;
usbHIDDescriptor_t rawHID;
# ifdef USB_CFG_HAVE_INTRIN_ENDPOINT3
usbEndpointDescriptor_t rawINEndpoint;
usbEndpointDescriptor_t rawOUTEndpoint;
# endif
#endif
} __attribute__((packed)) usbConfigurationDescriptor_t;

#define USB_STRING_LEN(s) (sizeof(usbDescriptorHeader_t) + ((s) << 1))

host_driver_t *vusb_driver(void);
void vusb_transfer_keyboard(void);

#if defined(RAW_ENABLE)
void raw_hid_task(void);
#endif