File syn_usb_hid.c¶
File List > drivers > syn_usb_hid.c
Go to the documentation of this file
#include "syntropic/drivers/syn_usb_hid.h"
#include <string.h>
static const uint8_t HID_INTERFACE_DESC[25] = {
/* Interface 0: HID Class */
0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,
/* HID Descriptor */
0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x34, 0x00,
/* Endpoint 0x83: Interrupt IN */
0x07, 0x05, 0x83, 0x03, 0x40, 0x00, 0x0A};
static SYN_Status hid_class_setup(void *ctx, const SYN_USB_SetupPacket *pkt, uint8_t *resp,
uint16_t *rlen)
{
SYN_USB_HID *hid = (SYN_USB_HID *)ctx;
if (!hid || !pkt || !resp || !rlen) {
return SYN_INVALID_PARAM;
}
*rlen = 0;
switch (pkt->bRequest) {
case SYN_USB_HID_REQ_GET_REPORT:
if (hid->tx_len > 0U) {
uint16_t copy_len = (pkt->wLength < hid->tx_len) ? pkt->wLength : hid->tx_len;
memcpy(resp, hid->tx_buf, copy_len);
*rlen = copy_len;
return SYN_OK;
}
return SYN_OK;
case SYN_USB_HID_REQ_SET_REPORT:
return SYN_OK;
case SYN_USB_HID_REQ_GET_IDLE:
resp[0] = hid->idle_rate;
*rlen = 1U;
return SYN_OK;
case SYN_USB_HID_REQ_SET_IDLE:
hid->idle_rate = (uint8_t)(pkt->wValue >> 8);
return SYN_OK;
case SYN_USB_HID_REQ_GET_PROTOCOL:
resp[0] = hid->active_protocol;
*rlen = 1U;
return SYN_OK;
case SYN_USB_HID_REQ_SET_PROTOCOL:
hid->active_protocol = (uint8_t)(pkt->wValue & 0xFFU);
return SYN_OK;
case SYN_USB_REQ_GET_DESCRIPTOR: {
uint8_t desc_type = (uint8_t)(pkt->wValue >> 8);
if (desc_type == 0x22U && hid->report_desc) { /* HID Report Descriptor */
uint16_t len =
(pkt->wLength < hid->report_desc_len) ? pkt->wLength : hid->report_desc_len;
memcpy(resp, hid->report_desc, len);
*rlen = len;
return SYN_OK;
}
return SYN_ERROR;
}
default:
return SYN_OK;
}
}
SYN_Status syn_usb_hid_init(SYN_USB_HID *hid)
{
if (!hid) {
return SYN_INVALID_PARAM;
}
memset(hid, 0, sizeof(*hid));
hid->ep_in = 0x83;
hid->idle_rate = 0;
hid->active_protocol = 1; /* 1 = Report Protocol */
return SYN_OK;
}
SYN_Status syn_usb_hid_register(SYN_USB_Device *dev, SYN_USB_HID *hid, const uint8_t *report_desc,
uint16_t report_desc_len)
{
if (!dev || !hid || !report_desc || report_desc_len == 0U) {
return SYN_INVALID_PARAM;
}
hid->report_desc = report_desc;
hid->report_desc_len = report_desc_len;
/* Copy static interface desc template and dynamically update Report Desc Length (bytes 16..17)
*/
uint8_t desc_buf[sizeof(HID_INTERFACE_DESC)];
memcpy(desc_buf, HID_INTERFACE_DESC, sizeof(HID_INTERFACE_DESC));
desc_buf[16] = (uint8_t)(report_desc_len & 0xFFU);
desc_buf[17] = (uint8_t)((report_desc_len >> 8) & 0xFFU);
SYN_USB_ClassDriver cls;
memset(&cls, 0, sizeof(cls));
cls.iface_start = dev->class_count; /* Interface number assignment */
cls.iface_count = 1U;
cls.ctx = hid;
cls.setup = hid_class_setup;
hid->iface_num = cls.iface_start;
return syn_usb_register_class(dev, &cls, desc_buf, sizeof(desc_buf));
}
SYN_Status syn_usb_hid_send_report(SYN_USB_HID *hid, const void *report, size_t len)
{
if (!hid || !report || len == 0U) {
return SYN_INVALID_PARAM;
}
if (len > sizeof(hid->tx_buf)) {
len = sizeof(hid->tx_buf);
}
memcpy(hid->tx_buf, report, len);
hid->tx_len = (uint16_t)len;
return SYN_OK;
}
SYN_Status syn_usb_hid_read_report(SYN_USB_HID *hid, void *buf, size_t max_len, size_t *out_len)
{
if (!hid || !buf || !out_len) {
return SYN_INVALID_PARAM;
}
if (hid->rx_len == 0U) {
*out_len = 0U;
return SYN_OK;
}
size_t copy_len = (hid->rx_len < max_len) ? hid->rx_len : max_len;
memcpy(buf, hid->rx_buf, copy_len);
*out_len = copy_len;
if (copy_len < hid->rx_len) {
memmove(hid->rx_buf, &hid->rx_buf[copy_len], hid->rx_len - copy_len);
hid->rx_len -= (uint16_t)copy_len;
} else {
hid->rx_len = 0U;
}
return SYN_OK;
}
bool syn_usb_hid_report_available(const SYN_USB_HID *hid)
{
return (hid != NULL) && (hid->rx_len > 0U);
}
bool syn_usb_hid_tx_ready(const SYN_USB_HID *hid)
{
return (hid != NULL) && (hid->tx_len == 0U);
}