|
@@ -43,7 +43,8 @@ typedef struct
|
|
|
uint8_t itf_num;
|
|
uint8_t itf_num;
|
|
|
uint8_t ep_in;
|
|
uint8_t ep_in;
|
|
|
uint8_t ep_out; // optional Out endpoint
|
|
uint8_t ep_out; // optional Out endpoint
|
|
|
- uint8_t boot_protocol; // Boot mouse or keyboard
|
|
|
|
|
|
|
+ uint8_t itf_protocol; // Boot mouse or keyboard
|
|
|
|
|
+
|
|
|
bool boot_mode; // default = false (Report)
|
|
bool boot_mode; // default = false (Report)
|
|
|
uint8_t idle_rate; // up to application to handle idle rate
|
|
uint8_t idle_rate; // up to application to handle idle rate
|
|
|
uint16_t report_desc_len;
|
|
uint16_t report_desc_len;
|
|
@@ -51,6 +52,8 @@ typedef struct
|
|
|
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE];
|
|
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE];
|
|
|
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE];
|
|
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE];
|
|
|
|
|
|
|
|
|
|
+ // TODO save hid descriptor since host can specifically request this after enumeration
|
|
|
|
|
+ // Note: HID descriptor may be not available from application after enumeration
|
|
|
tusb_hid_descriptor_hid_t const * hid_descriptor;
|
|
tusb_hid_descriptor_hid_t const * hid_descriptor;
|
|
|
} hidd_interface_t;
|
|
} hidd_interface_t;
|
|
|
|
|
|
|
@@ -70,16 +73,16 @@ static inline uint8_t get_index_by_itfnum(uint8_t itf_num)
|
|
|
//--------------------------------------------------------------------+
|
|
//--------------------------------------------------------------------+
|
|
|
// APPLICATION API
|
|
// APPLICATION API
|
|
|
//--------------------------------------------------------------------+
|
|
//--------------------------------------------------------------------+
|
|
|
-bool tud_hid_n_ready(uint8_t itf)
|
|
|
|
|
|
|
+bool tud_hid_n_ready(uint8_t instance)
|
|
|
{
|
|
{
|
|
|
- uint8_t const ep_in = _hidd_itf[itf].ep_in;
|
|
|
|
|
|
|
+ uint8_t const ep_in = _hidd_itf[instance].ep_in;
|
|
|
return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(TUD_OPT_RHPORT, ep_in);
|
|
return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(TUD_OPT_RHPORT, ep_in);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-bool tud_hid_n_report(uint8_t itf, uint8_t report_id, void const* report, uint8_t len)
|
|
|
|
|
|
|
+bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint8_t len)
|
|
|
{
|
|
{
|
|
|
uint8_t const rhport = 0;
|
|
uint8_t const rhport = 0;
|
|
|
- hidd_interface_t * p_hid = &_hidd_itf[itf];
|
|
|
|
|
|
|
+ hidd_interface_t * p_hid = &_hidd_itf[instance];
|
|
|
|
|
|
|
|
// claim endpoint
|
|
// claim endpoint
|
|
|
TU_VERIFY( usbd_edpt_claim(rhport, p_hid->ep_in) );
|
|
TU_VERIFY( usbd_edpt_claim(rhport, p_hid->ep_in) );
|
|
@@ -102,12 +105,17 @@ bool tud_hid_n_report(uint8_t itf, uint8_t report_id, void const* report, uint8_
|
|
|
return usbd_edpt_xfer(TUD_OPT_RHPORT, p_hid->ep_in, p_hid->epin_buf, len);
|
|
return usbd_edpt_xfer(TUD_OPT_RHPORT, p_hid->ep_in, p_hid->epin_buf, len);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-bool tud_hid_n_boot_mode(uint8_t itf)
|
|
|
|
|
|
|
+uint8_t tud_hid_n_interface_protocol(uint8_t instance)
|
|
|
|
|
+{
|
|
|
|
|
+ return _hidd_itf[instance].itf_protocol;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+bool tud_hid_n_get_protocol(uint8_t instance)
|
|
|
{
|
|
{
|
|
|
- return _hidd_itf[itf].boot_mode;
|
|
|
|
|
|
|
+ return _hidd_itf[instance].boot_mode;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-bool tud_hid_n_keyboard_report(uint8_t itf, uint8_t report_id, uint8_t modifier, uint8_t keycode[6])
|
|
|
|
|
|
|
+bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6])
|
|
|
{
|
|
{
|
|
|
hid_keyboard_report_t report;
|
|
hid_keyboard_report_t report;
|
|
|
|
|
|
|
@@ -121,10 +129,10 @@ bool tud_hid_n_keyboard_report(uint8_t itf, uint8_t report_id, uint8_t modifier,
|
|
|
tu_memclr(report.keycode, 6);
|
|
tu_memclr(report.keycode, 6);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return tud_hid_n_report(itf, report_id, &report, sizeof(report));
|
|
|
|
|
|
|
+ return tud_hid_n_report(instance, report_id, &report, sizeof(report));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-bool tud_hid_n_mouse_report(uint8_t itf, uint8_t report_id,
|
|
|
|
|
|
|
+bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id,
|
|
|
uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal)
|
|
uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal)
|
|
|
{
|
|
{
|
|
|
hid_mouse_report_t report =
|
|
hid_mouse_report_t report =
|
|
@@ -136,10 +144,10 @@ bool tud_hid_n_mouse_report(uint8_t itf, uint8_t report_id,
|
|
|
.pan = horizontal
|
|
.pan = horizontal
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- return tud_hid_n_report(itf, report_id, &report, sizeof(report));
|
|
|
|
|
|
|
+ return tud_hid_n_report(instance, report_id, &report, sizeof(report));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-bool tud_hid_n_gamepad_report(uint8_t itf, uint8_t report_id,
|
|
|
|
|
|
|
+bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id,
|
|
|
int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint16_t buttons)
|
|
int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint16_t buttons)
|
|
|
{
|
|
{
|
|
|
hid_gamepad_report_t report =
|
|
hid_gamepad_report_t report =
|
|
@@ -154,7 +162,7 @@ bool tud_hid_n_gamepad_report(uint8_t itf, uint8_t report_id,
|
|
|
.buttons = buttons,
|
|
.buttons = buttons,
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- return tud_hid_n_report(itf, report_id, &report, sizeof(report));
|
|
|
|
|
|
|
+ return tud_hid_n_report(instance, report_id, &report, sizeof(report));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------+
|
|
//--------------------------------------------------------------------+
|
|
@@ -203,7 +211,7 @@ uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint1
|
|
|
p_desc = tu_desc_next(p_desc);
|
|
p_desc = tu_desc_next(p_desc);
|
|
|
TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_hid->ep_out, &p_hid->ep_in), 0);
|
|
TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_hid->ep_out, &p_hid->ep_in), 0);
|
|
|
|
|
|
|
|
- if ( desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT ) p_hid->boot_protocol = desc_itf->bInterfaceProtocol;
|
|
|
|
|
|
|
+ if ( desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT ) p_hid->itf_protocol = desc_itf->bInterfaceProtocol;
|
|
|
|
|
|
|
|
p_hid->boot_mode = false; // default mode is REPORT
|
|
p_hid->boot_mode = false; // default mode is REPORT
|
|
|
p_hid->itf_num = desc_itf->bInterfaceNumber;
|
|
p_hid->itf_num = desc_itf->bInterfaceNumber;
|
|
@@ -318,8 +326,7 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
|
|
|
case HID_REQ_CONTROL_GET_PROTOCOL:
|
|
case HID_REQ_CONTROL_GET_PROTOCOL:
|
|
|
if ( stage == CONTROL_STAGE_SETUP )
|
|
if ( stage == CONTROL_STAGE_SETUP )
|
|
|
{
|
|
{
|
|
|
- // 0 is Boot, 1 is Report protocol
|
|
|
|
|
- uint8_t protocol = (uint8_t)(1-p_hid->boot_mode);
|
|
|
|
|
|
|
+ uint8_t protocol = (p_hid->boot_mode ? HID_PROTOCOL_BOOT : HID_PROTOCOL_REPORT);
|
|
|
tud_control_xfer(rhport, request, &protocol, 1);
|
|
tud_control_xfer(rhport, request, &protocol, 1);
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
@@ -327,15 +334,14 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
|
|
|
case HID_REQ_CONTROL_SET_PROTOCOL:
|
|
case HID_REQ_CONTROL_SET_PROTOCOL:
|
|
|
if ( stage == CONTROL_STAGE_SETUP )
|
|
if ( stage == CONTROL_STAGE_SETUP )
|
|
|
{
|
|
{
|
|
|
- // 0 is Boot, 1 is Report protocol
|
|
|
|
|
- p_hid->boot_mode = 1 - request->wValue;
|
|
|
|
|
|
|
+ p_hid->boot_mode = (request->wValue == HID_PROTOCOL_BOOT);
|
|
|
tud_control_status(rhport, request);
|
|
tud_control_status(rhport, request);
|
|
|
}
|
|
}
|
|
|
else if ( stage == CONTROL_STAGE_ACK )
|
|
else if ( stage == CONTROL_STAGE_ACK )
|
|
|
{
|
|
{
|
|
|
- if (tud_hid_boot_mode_cb)
|
|
|
|
|
|
|
+ if (tud_hid_set_protocol_cb)
|
|
|
{
|
|
{
|
|
|
- tud_hid_boot_mode_cb(hid_itf, p_hid->boot_mode);
|
|
|
|
|
|
|
+ tud_hid_set_protocol_cb(hid_itf, p_hid->boot_mode);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
@@ -354,29 +360,29 @@ bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
|
|
|
{
|
|
{
|
|
|
(void) result;
|
|
(void) result;
|
|
|
|
|
|
|
|
- uint8_t itf = 0;
|
|
|
|
|
|
|
+ uint8_t instance = 0;
|
|
|
hidd_interface_t * p_hid = _hidd_itf;
|
|
hidd_interface_t * p_hid = _hidd_itf;
|
|
|
|
|
|
|
|
// Identify which interface to use
|
|
// Identify which interface to use
|
|
|
- for (itf = 0; itf < CFG_TUD_HID; itf++)
|
|
|
|
|
|
|
+ for (instance = 0; instance < CFG_TUD_HID; instance++)
|
|
|
{
|
|
{
|
|
|
- p_hid = &_hidd_itf[itf];
|
|
|
|
|
|
|
+ p_hid = &_hidd_itf[instance];
|
|
|
if ( (ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in) ) break;
|
|
if ( (ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in) ) break;
|
|
|
}
|
|
}
|
|
|
- TU_ASSERT(itf < CFG_TUD_HID);
|
|
|
|
|
|
|
+ TU_ASSERT(instance < CFG_TUD_HID);
|
|
|
|
|
|
|
|
// Sent report successfully
|
|
// Sent report successfully
|
|
|
if (ep_addr == p_hid->ep_in)
|
|
if (ep_addr == p_hid->ep_in)
|
|
|
{
|
|
{
|
|
|
if (tud_hid_report_complete_cb)
|
|
if (tud_hid_report_complete_cb)
|
|
|
{
|
|
{
|
|
|
- tud_hid_report_complete_cb(itf, p_hid->epin_buf, (uint8_t) xferred_bytes);
|
|
|
|
|
|
|
+ tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint8_t) xferred_bytes);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
// Received report
|
|
// Received report
|
|
|
else if (ep_addr == p_hid->ep_out)
|
|
else if (ep_addr == p_hid->ep_out)
|
|
|
{
|
|
{
|
|
|
- tud_hid_set_report_cb(itf, 0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, xferred_bytes);
|
|
|
|
|
|
|
+ tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, xferred_bytes);
|
|
|
TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
|
|
TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
|
|
|
}
|
|
}
|
|
|
|
|
|