Skip to content

Commit

Permalink
Merge pull request #6 from WootingKb/feature/TinyUSB-improvements
Browse files Browse the repository at this point in the history
Merging TinyUSB improvements
  • Loading branch information
simon-wh authored May 17, 2024
2 parents cca0c1c + 6056092 commit ac3c2c5
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 34 deletions.
2 changes: 1 addition & 1 deletion examples/device/hid_boot_interface/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol)
// Invoked when sent REPORT successfully to host
// Application can use this to send the next report
// Note: For composite reports, report[0] is report ID
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len)
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len)
{
(void) instance;
(void) report;
Expand Down
2 changes: 1 addition & 1 deletion examples/device/hid_composite/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ void hid_task(void)
// Invoked when sent REPORT successfully to host
// Application can use this to send the next report
// Note: For composite reports, report[0] is report ID
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len)
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len)
{
(void) instance;
(void) len;
Expand Down
2 changes: 1 addition & 1 deletion examples/device/hid_composite_freertos/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ void hid_task(void* param)
// Invoked when sent REPORT successfully to host
// Application can use this to send the next report
// Note: For composite reports, report[0] is report ID
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len)
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len)
{
(void) instance;
(void) len;
Expand Down
31 changes: 25 additions & 6 deletions src/class/hid/hid_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ bool tud_hid_n_ready(uint8_t instance)
return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(TUD_OPT_RHPORT, ep_in);
}

bool tud_hid_n_report(uint8_t instance, 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, uint16_t len)
{
uint8_t const rhport = 0;
hidd_interface_t * p_hid = &_hidd_itf[instance];
Expand All @@ -91,15 +91,15 @@ bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, u
// prepare data
if (report_id)
{
len = tu_min8(len, CFG_TUD_HID_EP_BUFSIZE-1);
len = tu_min16(len, CFG_TUD_HID_EP_BUFSIZE-1);

p_hid->epin_buf[0] = report_id;
memcpy(p_hid->epin_buf+1, report, len);
len++;
}else
{
// If report id = 0, skip ID field
len = tu_min8(len, CFG_TUD_HID_EP_BUFSIZE);
len = tu_min16(len, CFG_TUD_HID_EP_BUFSIZE);
memcpy(p_hid->epin_buf, report, len);
}

Expand Down Expand Up @@ -396,18 +396,37 @@ bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
}
TU_ASSERT(instance < CFG_TUD_HID);

// Check if there was a problem
if (XFER_RESULT_SUCCESS != result)
{
// Inform application about the issue
if (tud_hid_report_issue_cb)
{
tud_hid_report_issue_cb(instance, ep_addr, result, xferred_bytes);
}

// Allow a new transfer to be received if issue happened on an OUT endpoint
if (ep_addr == p_hid->ep_out)
{
// Prepare the OUT endpoint to be able to receive a new transfer
TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
}

return true;
}

// Sent report successfully
if (ep_addr == p_hid->ep_in)
{
if (tud_hid_report_complete_cb)
{
tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint8_t) xferred_bytes);
tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t) xferred_bytes);
}
}
// Received report
// Received report successfully
else if (ep_addr == p_hid->ep_out)
{
tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, xferred_bytes);
tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t) xferred_bytes);
TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
}

Expand Down
10 changes: 6 additions & 4 deletions src/class/hid/hid_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ uint8_t tud_hid_n_interface_protocol(uint8_t instance);
uint8_t tud_hid_n_get_protocol(uint8_t instance);

// Send report to host
bool tud_hid_n_report(uint8_t instance, 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, uint16_t len);

// KEYBOARD: convenient helper to send keyboard report if application
// use template layout report as defined by hid_keyboard_report_t
Expand All @@ -82,7 +82,7 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int
static inline bool tud_hid_ready(void);
static inline uint8_t tud_hid_interface_protocol(void);
static inline uint8_t tud_hid_get_protocol(void);
static inline bool tud_hid_report(uint8_t report_id, void const* report, uint8_t len);
static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len);
static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]);
static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal);
static inline bool tud_hid_gamepad_report(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, uint32_t buttons);
Expand Down Expand Up @@ -116,8 +116,10 @@ TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate);
// Invoked when sent REPORT successfully to host
// Application can use this to send the next report
// Note: For composite reports, report[0] is report ID
TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len);
TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len);

// Invoked when a transfer wasn't successful
TU_ATTR_WEAK void tud_hid_report_issue_cb(uint8_t instance, uint8_t ep_addr, xfer_result_t result, uint16_t xferred_bytes);

//--------------------------------------------------------------------+
// Inline Functions
Expand All @@ -137,7 +139,7 @@ static inline uint8_t tud_hid_get_protocol(void)
return tud_hid_n_get_protocol(0);
}

static inline bool tud_hid_report(uint8_t report_id, void const* report, uint8_t len)
static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len)
{
return tud_hid_n_report(0, report_id, report, len);
}
Expand Down
10 changes: 10 additions & 0 deletions src/common/tusb_compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,16 @@
#define TU_ATTR_BIT_FIELD_ORDER_BEGIN
#define TU_ATTR_BIT_FIELD_ORDER_END

#if __GNUC__ < 5
#define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */
#else
#if __has_attribute(__fallthrough__)
#define TU_ATTR_FALLTHROUGH __attribute__((fallthrough))
#else
#define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */
#endif
#endif

// Endian conversion use well-known host to network (big endian) naming
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define TU_BYTE_ORDER TU_LITTLE_ENDIAN
Expand Down
95 changes: 74 additions & 21 deletions src/device/usbd.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,10 @@ static osal_mutex_t _usbd_mutex;
//--------------------------------------------------------------------+
// Prototypes
//--------------------------------------------------------------------+
static void usbd_set_defaults(void);
static void configuration_reset(uint8_t rhport);
static void usbd_reset(uint8_t rhport);
static bool invoke_class_control(uint8_t rhport, usbd_class_driver_t const * driver, tusb_control_request_t const * request);
static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request);
static bool process_set_config(uint8_t rhport, uint8_t cfg_num);
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request);
Expand Down Expand Up @@ -387,7 +391,7 @@ bool tud_init (uint8_t rhport)
TU_LOG2("USBD init\r\n");
TU_LOG2_INT(sizeof(usbd_device_t));

tu_varclr(&_usbd_dev);
usbd_set_defaults();

#if CFG_TUSB_OS != OPT_OS_NONE
// Init device mutex
Expand Down Expand Up @@ -422,16 +426,25 @@ bool tud_init (uint8_t rhport)
return true;
}

static void usbd_set_defaults(void)
{
tu_varclr(&_usbd_dev);

// Set values to their defaults
memset(_usbd_dev.itf2drv, DRVID_INVALID, sizeof(_usbd_dev.itf2drv)); // invalid mapping
memset(_usbd_dev.ep2drv , DRVID_INVALID, sizeof(_usbd_dev.ep2drv )); // invalid mapping

_usbd_dev.speed = TUSB_SPEED_INVALID; // Unknown initial speed
}

static void configuration_reset(uint8_t rhport)
{
for ( uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++ )
{
get_driver(i)->reset(rhport);
}

tu_varclr(&_usbd_dev);
memset(_usbd_dev.itf2drv, DRVID_INVALID, sizeof(_usbd_dev.itf2drv)); // invalid mapping
memset(_usbd_dev.ep2drv , DRVID_INVALID, sizeof(_usbd_dev.ep2drv )); // invalid mapping
usbd_set_defaults();
}

static void usbd_reset(uint8_t rhport)
Expand Down Expand Up @@ -488,16 +501,41 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr)
{
case DCD_EVENT_BUS_RESET:
TU_LOG2(": %s Speed\r\n", tu_str_speed[event.bus_reset.speed]);
usbd_reset(event.rhport);
_usbd_dev.speed = event.bus_reset.speed;
break;
TU_ATTR_FALLTHROUGH;

case DCD_EVENT_UNPLUGGED:
TU_LOG2("\r\n");

// Only inform application about the unmount if it was mounted before
if ( _usbd_dev.cfg_num )
{
_usbd_dev.cfg_num = 0;

// invoke callback
if (tud_umount_cb) tud_umount_cb();
}

// Inform application about a no longer valid suspend state
if ( _usbd_dev.suspended )
{
_usbd_dev.suspended = 0;

// invoke callback
if (tud_resume_cb) tud_resume_cb();
}

// Completely clear the current USB state
usbd_reset(event.rhport);

// invoke callback
if (tud_umount_cb) tud_umount_cb();
// Recover the intended bus speed
if (DCD_EVENT_BUS_RESET == event.event_id)
{
_usbd_dev.speed = event.bus_reset.speed;
}
else if (DCD_EVENT_UNPLUGGED == event.event_id)
{
_usbd_dev.speed = DCD_EVENT_INVALID;
}
break;

case DCD_EVENT_SETUP_RECEIVED:
Expand Down Expand Up @@ -703,8 +741,18 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
_usbd_dev.speed = speed; // restore speed
}

// switch to new configuration if not zero
if ( cfg_num ) TU_ASSERT( process_set_config(rhport, cfg_num) );
// Handle the new configuration and execute the corresponding callback
if ( cfg_num )
{
// switch to new configuration if not zero
TU_ASSERT( process_set_config(rhport, cfg_num) );

if ( tud_mount_cb ) tud_mount_cb();
}
else
{
if ( tud_umount_cb ) tud_umount_cb();
}
}

_usbd_dev.cfg_num = cfg_num;
Expand Down Expand Up @@ -956,9 +1004,6 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
TU_ASSERT(drv_id < TOTAL_DRIVER_COUNT);
}

// invoke callback
if (tud_mount_cb) tud_mount_cb();

return true;
}

Expand Down Expand Up @@ -1075,20 +1120,28 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
{
switch (event->event_id)
{
case DCD_EVENT_BUS_RESET:
// Skip event if device wasn't connected and speed hasn't changed
if ( _usbd_dev.connected || event->bus_reset.speed != _usbd_dev.speed )
{
osal_queue_send(_usbd_q, event, in_isr);
}
break;

case DCD_EVENT_UNPLUGGED:
_usbd_dev.connected = 0;
_usbd_dev.addressed = 0;
_usbd_dev.cfg_num = 0;
_usbd_dev.suspended = 0;
osal_queue_send(_usbd_q, event, in_isr);
// Skip event if device wasn't connected in the first place
if ( _usbd_dev.connected )
{
osal_queue_send(_usbd_q, event, in_isr);
}
break;

case DCD_EVENT_SUSPEND:
// NOTE: When plugging/unplugging device, the D+/D- state are unstable and
// can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ).
// In addition, some MCUs such as SAMD or boards that haven no VBUS detection cannot distinguish
// suspended vs disconnected. We will skip handling SUSPEND/RESUME event if not currently connected
if ( _usbd_dev.connected )
if ( _usbd_dev.connected && !_usbd_dev.suspended )
{
_usbd_dev.suspended = 1;
osal_queue_send(_usbd_q, event, in_isr);
Expand All @@ -1097,7 +1150,7 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)

case DCD_EVENT_RESUME:
// skip event if not connected (especially required for SAMD)
if ( _usbd_dev.connected )
if ( _usbd_dev.connected && _usbd_dev.suspended )
{
_usbd_dev.suspended = 0;
osal_queue_send(_usbd_q, event, in_isr);
Expand Down

0 comments on commit ac3c2c5

Please sign in to comment.