Merge pull request #14629 from Ollrogge/usb_hid_pr
USB HID minimal implementation
This commit is contained in:
commit
916f554d2a
@ -971,6 +971,11 @@ ifneq (,$(filter usbus_cdc_ecm,$(USEMODULE)))
|
||||
USEMODULE += luid
|
||||
endif
|
||||
|
||||
ifneq (,$(filter usbus_hid,$(USEMODULE)))
|
||||
USEMODULE += isrpipe_read_timeout
|
||||
USEMODULE += usbus
|
||||
endif
|
||||
|
||||
ifneq (,$(filter uuid,$(USEMODULE)))
|
||||
USEMODULE += hashes
|
||||
USEMODULE += random
|
||||
|
||||
111
sys/include/usb/hid.h
Normal file
111
sys/include/usb/hid.h
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nils Ollrogge
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser General
|
||||
* Public License v2.1. See the file LICENSE in the top level directory for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup usb_hid HID - USB communications device class
|
||||
* @ingroup usb
|
||||
* @brief Generic USB HID defines and helpers
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Definition for USB HID interfaces
|
||||
*
|
||||
* @author Nils Ollrogge <nils-ollrogge@outlook.de>
|
||||
*/
|
||||
|
||||
#ifndef USB_HID_H
|
||||
#define USB_HID_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief USB HID type descriptor
|
||||
*/
|
||||
#define USB_TYPE_DESCRIPTOR_HID 0x21
|
||||
|
||||
/**
|
||||
* @brief USB HID version in BCD
|
||||
*/
|
||||
#define USB_HID_VERSION_BCD 0x0110
|
||||
|
||||
/**
|
||||
* @name USB HID subclass types
|
||||
* @{
|
||||
*/
|
||||
#define USB_HID_SUBCLASS_NONE 0x0
|
||||
#define USB_HID_SUBCLASS_BOOT 0x1
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name USB HID protocol types
|
||||
* @{
|
||||
*/
|
||||
#define USB_HID_PROTOCOL_NONE 0x0
|
||||
#define USB_HID_PROTOCOL_KEYBOARD 0x1
|
||||
#define USB_HID_PROTOCOL_MOUSE 0x2
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name USB HID descriptor types
|
||||
* @{
|
||||
*/
|
||||
#define USB_HID_DESCR_HID 0x21
|
||||
#define USB_HID_DESCR_REPORT 0x22
|
||||
#define USB_HID_DESCR_PHYSICAL 0x23
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief USB HID country codes
|
||||
*/
|
||||
#define USB_HID_COUNTRY_CODE_NOTSUPPORTED 0x00
|
||||
|
||||
/**
|
||||
* @name USB HID class specific control requests
|
||||
* @{
|
||||
*/
|
||||
#define USB_HID_REQUEST_GET_REPORT 0x01
|
||||
#define USB_HID_REQUEST_GET_IDLE 0x02
|
||||
#define USB_HID_REQUEST_GET_PROTOCOL 0x03
|
||||
#define USB_HID_REQUEST_SET_REPORT 0x09
|
||||
#define USB_HID_REQUEST_SET_IDLE 0x0a
|
||||
#define USB_HID_REQUEST_SET_PROTOCOL 0x0b
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief USB HID descriptor struct
|
||||
*
|
||||
* @see USB HID 1.11 spec section 6.2.1
|
||||
*/
|
||||
typedef struct __attribute__((packed)){
|
||||
uint8_t length; /**< Numeric expression that is the total size of
|
||||
the HID descriptor */
|
||||
uint8_t desc_type; /**< Constant name specifying type of HID
|
||||
descriptor.*/
|
||||
|
||||
uint16_t bcd_hid; /**< Numeric expression identifying the HID Class
|
||||
Specification release */
|
||||
uint8_t country_code; /**< Numeric expression identifying country code of
|
||||
the localized hardware. */
|
||||
uint8_t num_descrs; /**< Numeric expression specifying the number of
|
||||
class descriptors */
|
||||
|
||||
uint8_t report_type; /**< Type of HID class report. */
|
||||
uint16_t report_length; /**< the total size of the Report descriptor. */
|
||||
} usb_desc_hid_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USB_HID_H */
|
||||
/** @} */
|
||||
119
sys/include/usb/usbus/hid.h
Normal file
119
sys/include/usb/usbus/hid.h
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nils Ollrogge
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser General
|
||||
* Public License v2.1. See the file LICENSE in the top level directory for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup usbus_hid USBUS HID
|
||||
* @ingroup usb
|
||||
* @brief USBUS HID interface module
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Interface and definitions for USB HID type interfaces in
|
||||
* USBUS.
|
||||
*
|
||||
* The functionality provided here only implements the USB
|
||||
* specific handling. A different module is required to provide
|
||||
* functional handling of the data e.g. UART or STDIO integration.
|
||||
*
|
||||
* @author Nils Ollrogge <nils-ollrogge@outlook.de>
|
||||
*/
|
||||
|
||||
#ifndef USB_USBUS_HID_H
|
||||
#define USB_USBUS_HID_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "usb/usbus.h"
|
||||
#include "usb/hid.h"
|
||||
#include "mutex.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief USB HID interrupt endpoint size
|
||||
*/
|
||||
#ifndef CONFIG_USBUS_HID_INTERRUPT_EP_SIZE
|
||||
#define CONFIG_USBUS_HID_INTERRUPT_EP_SIZE 0x40
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief USBUS HID context struct forward declaration
|
||||
*/
|
||||
typedef struct usbus_hid_device usbus_hid_device_t;
|
||||
|
||||
/**
|
||||
* @brief HID data callback.
|
||||
*
|
||||
* Callback for received data from the USB host
|
||||
*
|
||||
* @param[in] hid HID handler context
|
||||
* @param[in] data ptr to the data
|
||||
* @param[in] len Length of the received data
|
||||
*/
|
||||
typedef void (*usbus_hid_cb_t)(usbus_hid_device_t *hid, uint8_t *data,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* @brief USBUS HID context struct
|
||||
*/
|
||||
struct usbus_hid_device {
|
||||
usbus_handler_t handler_ctrl; /**< control handler */
|
||||
usbus_interface_t iface; /**< HID interface */
|
||||
usbus_endpoint_t *ep_out; /**< OUT endpoint */
|
||||
usbus_endpoint_t *ep_in; /**< IN endpoint */
|
||||
usbus_descr_gen_t hid_descr; /**< HID descriptor generator */
|
||||
const uint8_t *report_desc; /**< report descriptor reference */
|
||||
size_t report_desc_size; /**< report descriptor size */
|
||||
usbus_t *usbus; /**< USBUS reference */
|
||||
size_t occupied; /**< Number of bytes for the host */
|
||||
usbus_hid_cb_t cb; /**< Callback for data handlers */
|
||||
event_t tx_ready; /**< Transmit ready event */
|
||||
mutex_t in_lock; /**< mutex used for locking hid send */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Initialize an USBUS HID interface
|
||||
*
|
||||
* @param[in] usbus USBUS context to register with
|
||||
* @param[in] hid USBUS HID handler
|
||||
* @param[in] cb Callback for data from the USB interface
|
||||
* @param[in] report_desc USB_HID report descriptor
|
||||
* @param[in] report_desc_size Size of USB_HID report descriptor
|
||||
*/
|
||||
void usbus_hid_init(usbus_t *usbus, usbus_hid_device_t *hid,
|
||||
usbus_hid_cb_t cb, const uint8_t *report_desc,
|
||||
size_t report_desc_size);
|
||||
|
||||
/**
|
||||
* @brief Submit bytes to the HID handler
|
||||
*
|
||||
* @param[in] hid USBUS HID handler context
|
||||
* @param[in] buf buffer to submit
|
||||
* @param[in] len length of the submitted buffer
|
||||
*
|
||||
* @return Number of bytes added to the HID ring buffer
|
||||
*/
|
||||
size_t usbus_hid_submit(usbus_hid_device_t *hid, const uint8_t *buf,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* @brief Flush the buffer to the USB host
|
||||
*
|
||||
* @param[in] hid USBUS HID handler context
|
||||
*/
|
||||
void usbus_hid_flush(usbus_hid_device_t *hid);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USB_USBUS_HID_H */
|
||||
/** @} */
|
||||
@ -7,4 +7,7 @@ endif
|
||||
ifneq (,$(filter usbus_cdc_acm,$(USEMODULE)))
|
||||
DIRS += cdc/acm
|
||||
endif
|
||||
ifneq (,$(filter usbus_hid,$(USEMODULE)))
|
||||
DIRS += hid
|
||||
endif
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
|
||||
3
sys/usb/usbus/hid/Makefile
Normal file
3
sys/usb/usbus/hid/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = usbus_hid
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
229
sys/usb/usbus/hid/hid.c
Normal file
229
sys/usb/usbus/hid/hid.c
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nils Ollrogge
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup usbus_hid
|
||||
* @{
|
||||
* @file
|
||||
*
|
||||
* @author Nils Ollrogge <nils-ollrogge@outlook.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#define USB_H_USER_IS_RIOT_INTERNAL
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "usb/usbus.h"
|
||||
#include "usb/usbus/control.h"
|
||||
#include "usb/usbus/hid.h"
|
||||
#include "tsrb.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
static void _init(usbus_t *usbus, usbus_handler_t *handler);
|
||||
static void _event_handler(usbus_t *usbus, usbus_handler_t *handler,
|
||||
usbus_event_usb_t event);
|
||||
static int _control_handler(usbus_t *usbus, usbus_handler_t *handler,
|
||||
usbus_control_request_state_t state,
|
||||
usb_setup_t *setup);
|
||||
static void _transfer_handler(usbus_t *usbus, usbus_handler_t *handler,
|
||||
usbdev_ep_t *ep, usbus_event_transfer_t event);
|
||||
|
||||
static void _handle_tx_ready(event_t *ev);
|
||||
|
||||
static const usbus_handler_driver_t hid_driver = {
|
||||
.init = _init,
|
||||
.event_handler = _event_handler,
|
||||
.control_handler = _control_handler,
|
||||
.transfer_handler = _transfer_handler
|
||||
};
|
||||
|
||||
static size_t _gen_hid_descriptor(usbus_t *usbus, void *arg);
|
||||
|
||||
static const usbus_descr_gen_funcs_t _hid_descriptor = {
|
||||
.fmt_post_descriptor = _gen_hid_descriptor,
|
||||
.len = {
|
||||
.fixed_len = sizeof(usb_desc_hid_t)
|
||||
},
|
||||
.len_type = USBUS_DESCR_LEN_FIXED
|
||||
};
|
||||
|
||||
static size_t _gen_hid_descriptor(usbus_t *usbus, void *arg)
|
||||
{
|
||||
usbus_hid_device_t *hid_dev = arg;
|
||||
usb_desc_hid_t hid_desc;
|
||||
|
||||
hid_desc.length = sizeof(usb_desc_hid_t);
|
||||
hid_desc.desc_type = USB_HID_DESCR_HID;
|
||||
hid_desc.bcd_hid = USB_HID_VERSION_BCD;
|
||||
hid_desc.country_code = USB_HID_COUNTRY_CODE_NOTSUPPORTED;
|
||||
hid_desc.num_descrs = 0x01;
|
||||
hid_desc.report_type = USB_HID_DESCR_REPORT;
|
||||
hid_desc.report_length = hid_dev->report_desc_size;
|
||||
|
||||
usbus_control_slicer_put_bytes(usbus, (uint8_t *)&hid_desc,
|
||||
sizeof(hid_desc));
|
||||
return sizeof(usb_desc_hid_t);
|
||||
}
|
||||
|
||||
static void _handle_tx_ready(event_t *ev)
|
||||
{
|
||||
usbus_hid_device_t *hid = container_of(ev, usbus_hid_device_t, tx_ready);
|
||||
|
||||
usbdev_ep_ready(hid->ep_in->ep, hid->occupied);
|
||||
}
|
||||
|
||||
void usbus_hid_init(usbus_t *usbus, usbus_hid_device_t *hid, usbus_hid_cb_t cb,
|
||||
const uint8_t *report_desc, size_t report_desc_size)
|
||||
{
|
||||
memset(hid, 0, sizeof(usbus_hid_device_t));
|
||||
hid->usbus = usbus;
|
||||
mutex_init(&hid->in_lock);
|
||||
hid->handler_ctrl.driver = &hid_driver;
|
||||
hid->report_desc = report_desc;
|
||||
hid->report_desc_size = report_desc_size;
|
||||
hid->cb = cb;
|
||||
|
||||
DEBUG("hid_init: %d %d \n", report_desc_size, report_desc[0]);
|
||||
usbus_register_event_handler(usbus, &hid->handler_ctrl);
|
||||
}
|
||||
|
||||
static void _init(usbus_t *usbus, usbus_handler_t *handler)
|
||||
{
|
||||
DEBUG("USB_HID: initialization\n");
|
||||
usbus_hid_device_t *hid = (usbus_hid_device_t *)handler;
|
||||
|
||||
hid->tx_ready.handler = _handle_tx_ready;
|
||||
|
||||
hid->hid_descr.next = NULL;
|
||||
hid->hid_descr.funcs = &_hid_descriptor;
|
||||
hid->hid_descr.arg = hid;
|
||||
|
||||
/*
|
||||
Configure Interface as USB_HID interface, choosing NONE for subclass and
|
||||
protocol in order to represent a generic I/O device
|
||||
*/
|
||||
hid->iface.class = USB_CLASS_HID;
|
||||
hid->iface.subclass = USB_HID_SUBCLASS_NONE;
|
||||
hid->iface.protocol = USB_HID_PROTOCOL_NONE;
|
||||
hid->iface.descr_gen = &hid->hid_descr;
|
||||
hid->iface.handler = handler;
|
||||
|
||||
/* IN endpoint to send data to host */
|
||||
hid->ep_in = usbus_add_endpoint(usbus, &hid->iface,
|
||||
USB_EP_TYPE_INTERRUPT,
|
||||
USB_EP_DIR_IN,
|
||||
CONFIG_USBUS_HID_INTERRUPT_EP_SIZE);
|
||||
|
||||
/* interrupt endpoint polling rate in ms */
|
||||
hid->ep_in->interval = 0x05;
|
||||
|
||||
usbus_enable_endpoint(hid->ep_in);
|
||||
|
||||
/* OUT endpoint to receive data from host */
|
||||
hid->ep_out = usbus_add_endpoint(usbus, &hid->iface,
|
||||
USB_EP_TYPE_INTERRUPT, USB_EP_DIR_OUT,
|
||||
CONFIG_USBUS_HID_INTERRUPT_EP_SIZE);
|
||||
|
||||
/* interrupt endpoint polling rate in ms */
|
||||
hid->ep_out->interval = 0x05;
|
||||
|
||||
usbus_enable_endpoint(hid->ep_out);
|
||||
|
||||
/* signal that INTERRUPT OUT is ready to receive data */
|
||||
usbdev_ep_ready(hid->ep_out->ep, 0);
|
||||
|
||||
usbus_add_interface(usbus, &hid->iface);
|
||||
}
|
||||
|
||||
static void _event_handler(usbus_t *usbus, usbus_handler_t *handler,
|
||||
usbus_event_usb_t event)
|
||||
{
|
||||
(void)usbus;
|
||||
(void)handler;
|
||||
|
||||
switch (event) {
|
||||
default:
|
||||
DEBUG("USB HID unhandled event: 0x%x\n", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int _control_handler(usbus_t *usbus, usbus_handler_t *handler,
|
||||
usbus_control_request_state_t state,
|
||||
usb_setup_t *setup)
|
||||
{
|
||||
usbus_hid_device_t *hid = (usbus_hid_device_t *)handler;
|
||||
|
||||
DEBUG("USB_HID: request: %d type: %d value: %d length: %d state: %d \n",
|
||||
setup->request, setup->type, setup->value >> 8, setup->length, state);
|
||||
|
||||
/* Requests defined in USB HID 1.11 spec section 7 */
|
||||
switch (setup->request) {
|
||||
case USB_SETUP_REQ_GET_DESCRIPTOR: {
|
||||
uint8_t desc_type = setup->value >> 8;
|
||||
if (desc_type == USB_HID_DESCR_REPORT) {
|
||||
usbus_control_slicer_put_bytes(usbus, hid->report_desc,
|
||||
hid->report_desc_size);
|
||||
}
|
||||
else if (desc_type == USB_HID_DESCR_HID) {
|
||||
_gen_hid_descriptor(usbus, NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case USB_HID_REQUEST_GET_REPORT:
|
||||
break;
|
||||
case USB_HID_REQUEST_GET_IDLE:
|
||||
break;
|
||||
case USB_HID_REQUEST_GET_PROTOCOL:
|
||||
break;
|
||||
case USB_HID_REQUEST_SET_REPORT:
|
||||
if ((state == USBUS_CONTROL_REQUEST_STATE_OUTDATA)) {
|
||||
size_t size = 0;
|
||||
uint8_t *data = usbus_control_get_out_data(usbus, &size);
|
||||
if (size > 0) {
|
||||
hid->cb(hid, data, size);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case USB_HID_REQUEST_SET_IDLE:
|
||||
break;
|
||||
case USB_HID_REQUEST_SET_PROTOCOL:
|
||||
break;
|
||||
default:
|
||||
DEBUG("USB_HID: unknown request %d \n", setup->request);
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _transfer_handler(usbus_t *usbus, usbus_handler_t *handler,
|
||||
usbdev_ep_t *ep, usbus_event_transfer_t event)
|
||||
{
|
||||
(void)usbus;
|
||||
(void)event;
|
||||
DEBUG("USB_HID: transfer_handler\n");
|
||||
|
||||
usbus_hid_device_t *hid = (usbus_hid_device_t *)handler;
|
||||
|
||||
if ((ep->dir == USB_EP_DIR_IN) && (ep->type == USB_EP_TYPE_INTERRUPT)) {
|
||||
mutex_unlock(&hid->in_lock);
|
||||
hid->occupied = 0;
|
||||
}
|
||||
else if ((ep->dir == USB_EP_DIR_OUT) &&
|
||||
(ep->type == USB_EP_TYPE_INTERRUPT)) {
|
||||
size_t len;
|
||||
usbdev_ep_get(ep, USBOPT_EP_AVAILABLE, &len, sizeof(size_t));
|
||||
if (len > 0) {
|
||||
hid->cb(hid, ep->buf, len);
|
||||
}
|
||||
usbdev_ep_ready(ep, 0);
|
||||
}
|
||||
}
|
||||
82
sys/usb/usbus/hid/hid_io.c
Normal file
82
sys/usb/usbus/hid/hid_io.c
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nils Ollrogge
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup usbus_hid
|
||||
* @{
|
||||
* @file
|
||||
* @brief This file implements a USB HID callback and read/write functions.
|
||||
*
|
||||
* @author Nils Ollrogge <nils-ollrogge@outlook.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#define USB_H_USER_IS_RIOT_INTERNAL
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "isrpipe.h"
|
||||
#include "isrpipe/read_timeout.h"
|
||||
|
||||
#include "usb/usbus.h"
|
||||
#include "usb/usbus/hid.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
static usbus_hid_device_t hid;
|
||||
static uint8_t _hid_rx_buf_mem[CONFIG_USBUS_HID_INTERRUPT_EP_SIZE];
|
||||
static isrpipe_t _hid_stdio_isrpipe = ISRPIPE_INIT(_hid_rx_buf_mem);
|
||||
|
||||
int usb_hid_io_read(void *buffer, size_t size)
|
||||
{
|
||||
return isrpipe_read(&_hid_stdio_isrpipe, buffer, size);
|
||||
}
|
||||
|
||||
int usb_hid_io_read_timeout(void *buffer, size_t size, uint32_t timeout)
|
||||
{
|
||||
return isrpipe_read_timeout(&_hid_stdio_isrpipe, buffer, size, timeout);
|
||||
}
|
||||
|
||||
void usb_hid_io_write(const void *buffer, size_t len)
|
||||
{
|
||||
uint8_t* buffer_ep = hid.ep_in->ep->buf;
|
||||
uint16_t max_size = hid.ep_in->maxpacketsize;
|
||||
size_t offset = 0;
|
||||
|
||||
while (len) {
|
||||
mutex_lock(&hid.in_lock);
|
||||
if (len > max_size) {
|
||||
memmove(buffer_ep + offset, (uint8_t *)buffer + offset, max_size);
|
||||
offset += max_size;
|
||||
hid.occupied = max_size;
|
||||
len -= max_size;
|
||||
}
|
||||
else {
|
||||
memmove(buffer_ep + offset, (uint8_t *)buffer + offset, len);
|
||||
offset += len;
|
||||
hid.occupied = len;
|
||||
len = 0;
|
||||
}
|
||||
usbus_event_post(hid.usbus, &hid.tx_ready);
|
||||
}
|
||||
}
|
||||
|
||||
static void _hid_rx_pipe(usbus_hid_device_t *hid, uint8_t *data, size_t len)
|
||||
{
|
||||
(void)hid;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
isrpipe_write_one(&_hid_stdio_isrpipe, data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_hid_io_init(usbus_t *usbus, uint8_t *report_desc,
|
||||
size_t report_desc_size)
|
||||
{
|
||||
usbus_hid_init(usbus, &hid, _hid_rx_pipe, report_desc, report_desc_size);
|
||||
}
|
||||
12
tests/usbus_hid/Makefile
Normal file
12
tests/usbus_hid/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
BOARD ?= nrf52840dk
|
||||
|
||||
include ../Makefile.tests_common
|
||||
|
||||
USEMODULE += usbus_hid
|
||||
|
||||
DISABLE_MODULE += auto_init_usbus
|
||||
|
||||
USB_VID ?= ${USB_VID_TESTING}
|
||||
USB_PID ?= ${USB_PID_TESTING}
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
||||
40
tests/usbus_hid/README.md
Normal file
40
tests/usbus_hid/README.md
Normal file
@ -0,0 +1,40 @@
|
||||
Expected result
|
||||
===============
|
||||
|
||||
Connect you computer to the USB interface directly for the SoC and the
|
||||
USB interface for power and debug.
|
||||
|
||||
Flash the device.
|
||||
|
||||
After flashing the device executing the command:
|
||||
|
||||
```
|
||||
dmesg
|
||||
```
|
||||
|
||||
should contain logs stating that a new USB HID device was found.
|
||||
|
||||
The output should look like the following:
|
||||
|
||||
```
|
||||
[18579.559436] usb 1-9: new full-speed USB device number 7 using xhci_hcd
|
||||
[18579.701474] usb 1-9: New USB device found, idVendor=1915, idProduct=521f, bcdDevice= 0.00
|
||||
[18579.701481] usb 1-9: New USB device strings: Mfr=3, Product=2, SerialNumber=0
|
||||
[18579.701484] usb 1-9: Product: Usb Hid Test Device
|
||||
[18579.701487] usb 1-9: Manufacturer: RIOT-os.org
|
||||
[18579.704613] hid-generic 0003:1915:521F.0008: hiddev0,hidraw6: USB HID v1.10 Device [RIOT-os.org Usb Hid Test Device] on usb-0000:00:14.0-9/input0
|
||||
```
|
||||
|
||||
Note, that the endpoint (in this case hidraw6) might differ.
|
||||
|
||||
After successful initialization of USB HID one should be able to communicate
|
||||
via USB HID simply by echoing input to the device.
|
||||
|
||||
Based on the screenshot above, an example command:
|
||||
|
||||
```
|
||||
echo "Test" > /dev/hidraw6
|
||||
```
|
||||
|
||||
The input string "Test" should be read by the test application and
|
||||
printed to stdout.
|
||||
85
tests/usbus_hid/main.c
Normal file
85
tests/usbus_hid/main.c
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nils Ollrogge
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup tests
|
||||
* @brief
|
||||
* @{
|
||||
*
|
||||
* @brief Tests for USB HID
|
||||
*
|
||||
* @author Nils Ollrogge <nils-ollrogge@outlook.de>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "usb/usbus.h"
|
||||
#include "xtimer.h"
|
||||
#include "usb/usbus/hid.h"
|
||||
|
||||
/*
|
||||
this descriptor is used, because the basic usb_hid interface was developed in
|
||||
conjunction with FIDO2. Descriptor is taken from CTAP2 specification
|
||||
(version 20190130) section 8.1.8.2
|
||||
*/
|
||||
static uint8_t report_desc_ctap[] = {
|
||||
0x06, 0xD0, 0xF1, /* HID_UsagePage ( FIDO_USAGE_PAGE ) */
|
||||
0x09, 0x01, /* HID_Usage ( FIDO_USAGE_CTAPHID ) */
|
||||
0xA1, 0x01, /* HID_Collection ( HID_Application ) */
|
||||
0x09, 0x20, /* HID_Usage ( FIDO_USAGE_DATA_IN ) */
|
||||
0x15, 0x00, /* HID_LogicalMin ( 0 ) */
|
||||
0x26, 0xFF, 0x00, /* HID_LogicalMaxS ( 0xff ) */
|
||||
0x75, 0x08, /* HID_ReportSize ( 8 ) */
|
||||
0x95, 0x40, /* HID_ReportCount ( HID_INPUT_REPORT_BYTES ) */
|
||||
0x81, 0x02, /* HID_Input ( HID_Data | HID_Absolute | HID_Variable ) */
|
||||
0x09, 0x21, /* HID_Usage ( FIDO_USAGE_DATA_OUT ) */
|
||||
0x15, 0x00, /* HID_LogicalMin ( 0 ) */
|
||||
0x26, 0xFF, 0x00, /* HID_LogicalMaxS ( 0xff ) */
|
||||
0x75, 0x08, /* HID_ReportSize ( 8 ) */
|
||||
0x95, 0x40, /* HID_ReportCount ( HID_OUTPUT_REPORT_BYTES ) */
|
||||
0x91, 0x02, /* HID_Output ( HID_Data | HID_Absolute | HID_Variable ) */
|
||||
0xC0, /* HID_EndCollection */
|
||||
};
|
||||
|
||||
static usbus_t usbus;
|
||||
static char _stack[USBUS_STACKSIZE];
|
||||
|
||||
void usb_hid_io_init(usbus_t* usbus, uint8_t* report_desc,
|
||||
size_t report_desc_size);
|
||||
ssize_t usb_hid_io_read(void* buffer, size_t len);
|
||||
|
||||
void init(void)
|
||||
{
|
||||
usbdev_t *usbdev = usbdev_get_ctx(0);
|
||||
usbus_init(&usbus, usbdev);
|
||||
|
||||
usb_hid_io_init(&usbus, report_desc_ctap, sizeof(report_desc_ctap));
|
||||
|
||||
usbus_create(_stack, USBUS_STACKSIZE, USBUS_PRIO, USBUS_TNAME, &usbus);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* sleep to wait for Pyterm attaching in order to see puts messages */
|
||||
xtimer_sleep(3);
|
||||
init();
|
||||
puts("RIOT USB HID echo test");
|
||||
puts("Write input to the hidraw device under /dev/hidrawX, and see if it gets echoed here");
|
||||
|
||||
uint8_t buffer[CONFIG_USBUS_HID_INTERRUPT_EP_SIZE];
|
||||
for (;;) {
|
||||
ssize_t len = usb_hid_io_read(buffer, CONFIG_USBUS_HID_INTERRUPT_EP_SIZE);
|
||||
|
||||
printf("Msg received via USB HID: ");
|
||||
for (int i = 0; i < len; i++) {
|
||||
putc(buffer[i], stdout);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user