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

Osal queue timeout #1440

Merged
merged 6 commits into from
Apr 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 4 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: TinyUSB Discussion
url: https://github.com/hathach/tinyusb/discussions
about: If you have other questions or need help, post it here.
- name: TinyUSB Docs
url: https://docs.tinyusb.org/
about: Online documentation
14 changes: 9 additions & 5 deletions examples/device/cdc_msc_freertos/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,11 @@ void usb_device_task(void* param)
// RTOS forever loop
while (1)
{
// tinyusb device task
// put this thread to waiting state until there is new events
tud_task();

// following code only run if tud_task() process at least 1 event
tud_cdc_write_flush();
}
}

Expand Down Expand Up @@ -181,7 +184,7 @@ void cdc_task(void* params)
// if ( tud_cdc_connected() )
{
// There are data available
if ( tud_cdc_available() )
while ( tud_cdc_available() )
{
uint8_t buf[64];

Expand All @@ -194,12 +197,13 @@ void cdc_task(void* params)
// for throughput test e.g
// $ dd if=/dev/zero of=/dev/ttyACM0 count=10000
tud_cdc_write(buf, count);
tud_cdc_write_flush();
}

tud_cdc_write_flush();
}

// For ESP32-S2 this delay is essential to allow idle how to run and reset wdt
vTaskDelay(pdMS_TO_TICKS(10));
// For ESP32-Sx this delay is essential to allow idle how to run and reset watchdog
vTaskDelay(1);
}
}

Expand Down
4 changes: 3 additions & 1 deletion examples/device/hid_composite_freertos/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,10 @@ void usb_device_task(void* param)
// RTOS forever loop
while (1)
{
// tinyusb device task
// put this thread to waiting state until there is new events
tud_task();

// following code only run if tud_task() process at least 1 event
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/common/tusb_verify.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@
*------------------------------------------------------------------*/

// Helper to implement optional parameter for TU_VERIFY Macro family
#define GET_3RD_ARG(arg1, arg2, arg3, ...) arg3
#define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
#define _GET_3RD_ARG(arg1, arg2, arg3, ...) arg3
#define _GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4

/*------------- Generator for TU_VERIFY and TU_VERIFY_HDLR -------------*/
#define TU_VERIFY_DEFINE(_cond, _handler, _ret) do \
Expand All @@ -116,7 +116,7 @@
#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, , false)
#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, , _ret)

#define TU_VERIFY(...) GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, UNUSED)(__VA_ARGS__)
#define TU_VERIFY(...) _GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, UNUSED)(__VA_ARGS__)


/*------------------------------------------------------------------*/
Expand All @@ -127,7 +127,7 @@
#define TU_VERIFY_HDLR_2ARGS(_cond, _handler) TU_VERIFY_DEFINE(_cond, _handler, false)
#define TU_VERIFY_HDLR_3ARGS(_cond, _handler, _ret) TU_VERIFY_DEFINE(_cond, _handler, _ret)

#define TU_VERIFY_HDLR(...) GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_HDLR_3ARGS, TU_VERIFY_HDLR_2ARGS,UNUSED)(__VA_ARGS__)
#define TU_VERIFY_HDLR(...) _GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_HDLR_3ARGS, TU_VERIFY_HDLR_2ARGS,UNUSED)(__VA_ARGS__)

/*------------------------------------------------------------------*/
/* ASSERT
Expand All @@ -139,7 +139,7 @@
#define ASSERT_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), _ret)

#ifndef TU_ASSERT
#define TU_ASSERT(...) GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS,UNUSED)(__VA_ARGS__)
#define TU_ASSERT(...) _GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS,UNUSED)(__VA_ARGS__)
#endif

/*------------------------------------------------------------------*/
Expand Down
12 changes: 9 additions & 3 deletions src/device/usbd.c
Original file line number Diff line number Diff line change
Expand Up @@ -466,17 +466,18 @@ bool tud_task_event_ready(void)
}
@endcode
*/
void tud_task (void)
void tud_task_ext(uint32_t timeout_ms, bool in_isr)
{
(void) in_isr; // not implemented yet

// Skip if stack is not initialized
if ( !tusb_inited() ) return;

// Loop until there is no more events in the queue
while (1)
{
dcd_event_t event;

if ( !osal_queue_receive(_usbd_q, &event) ) return;
if ( !osal_queue_receive(_usbd_q, &event, timeout_ms) ) return;

#if CFG_TUSB_DEBUG >= 2
if (event.event_id == DCD_EVENT_SETUP_RECEIVED) TU_LOG2("\r\n"); // extra line for setup
Expand Down Expand Up @@ -593,6 +594,11 @@ void tud_task (void)
TU_BREAKPOINT();
break;
}

#if CFG_TUSB_OS != OPT_OS_NONE && CFG_TUSB_OS != OPT_OS_PICO
// return if there is no more events, for application to run other background
if (osal_queue_empty(_usbd_q)) return;
#endif
}
}

Expand Down
11 changes: 10 additions & 1 deletion src/device/usbd.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,17 @@ bool tud_init (uint8_t rhport);
// Check if device stack is already initialized
bool tud_inited(void);

// Task function should be called in main/rtos loop, extended version of tud_task()
// - timeout_ms: millisecond to wait, zero = no wait, 0xFFFFFFFF = wait forever
// - in_isr: if function is called in ISR
void tud_task_ext(uint32_t timeout_ms, bool in_isr);

// Task function should be called in main/rtos loop
void tud_task (void);
TU_ATTR_ALWAYS_INLINE static inline
void tud_task (void)
{
tud_task_ext(UINT32_MAX, false);
}

// Check if there is pending events need proccessing by tud_task()
bool tud_task_event_ready(void);
Expand Down
11 changes: 9 additions & 2 deletions src/host/usbh.c
Original file line number Diff line number Diff line change
Expand Up @@ -392,16 +392,18 @@ bool tuh_init(uint8_t rhport)
}
@endcode
*/
void tuh_task(void)
void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
{
(void) in_isr; // not implemented yet

// Skip if stack is not initialized
if ( !tusb_inited() ) return;

// Loop until there is no more events in the queue
while (1)
{
hcd_event_t event;
if ( !osal_queue_receive(_usbh_q, &event) ) return;
if ( !osal_queue_receive(_usbh_q, &event, timeout_ms) ) return;

switch (event.event_id)
{
Expand Down Expand Up @@ -497,6 +499,11 @@ void tuh_task(void)

default: break;
}

#if CFG_TUSB_OS != OPT_OS_NONE && CFG_TUSB_OS != OPT_OS_PICO
// return if there is no more events, for application to run other background
if (osal_queue_empty(_usbh_q)) return;
#endif
}
}

Expand Down
19 changes: 14 additions & 5 deletions src/host/usbh.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,17 @@ bool tuh_init(uint8_t rhport);
// Check if host stack is already initialized
bool tuh_inited(void);

// Task function should be called in main/rtos loop, extended version of tuh_task()
// - timeout_ms: millisecond to wait, zero = no wait, 0xFFFFFFFF = wait forever
// - in_isr: if function is called in ISR
void tuh_task_ext(uint32_t timeout_ms, bool in_isr);

// Task function should be called in main/rtos loop
void tuh_task(void);
TU_ATTR_ALWAYS_INLINE static inline
void tuh_task(void)
{
tuh_task_ext(UINT32_MAX, false);
}

// Interrupt handler, name alias to HCD
extern void hcd_int_handler(uint8_t rhport);
Expand All @@ -106,17 +115,17 @@ tusb_speed_t tuh_speed_get(uint8_t daddr);
bool tuh_mounted(uint8_t daddr);

// Check if device is suspended
TU_ATTR_ALWAYS_INLINE
static inline bool tuh_suspended(uint8_t daddr)
TU_ATTR_ALWAYS_INLINE static inline
bool tuh_suspended(uint8_t daddr)
{
// TODO implement suspend & resume on host
(void) daddr;
return false;
}

// Check if device is ready to communicate with
TU_ATTR_ALWAYS_INLINE
static inline bool tuh_ready(uint8_t daddr)
TU_ATTR_ALWAYS_INLINE static inline
bool tuh_ready(uint8_t daddr)
{
return tuh_mounted(daddr) && !tuh_suspended(daddr);
}
Expand Down
22 changes: 11 additions & 11 deletions src/osal/osal.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,19 @@ typedef void (*osal_task_func_t)( void * );
// OSAL Porting API
// Should be implemented as static inline function in osal_port.h header
/*
static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr);
static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec);
static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl); // TODO removed
osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr);
bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec);
void osal_semaphore_reset(osal_semaphore_t sem_hdl); // TODO removed

static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef);
static inline bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec);
static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl);
osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef);
bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec);
bool osal_mutex_unlock(osal_mutex_t mutex_hdl);

static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef);
static inline bool osal_queue_receive(osal_queue_t qhdl, void* data);
static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr);
static inline bool osal_queue_empty(osal_queue_t qhdl);
osal_queue_t osal_queue_create(osal_queue_def_t* qdef);
bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec);
bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr);
bool osal_queue_empty(osal_queue_t qhdl);
*/
//--------------------------------------------------------------------+

Expand Down
45 changes: 29 additions & 16 deletions src/osal/osal_freertos.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,24 @@
extern "C" {
#endif

TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec)
{
if (msec == OSAL_TIMEOUT_WAIT_FOREVER) return portMAX_DELAY;
if (msec == 0) return 0;

uint32_t ticks = pdMS_TO_TICKS(msec);

// configTICK_RATE_HZ is less than 1000 and 1 tick > 1 ms
// we still need to delay at least 1 tick
if (ticks == 0) ticks =1 ;

return ticks;
}

//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
static inline void osal_task_delay(uint32_t msec)
TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec)
{
vTaskDelay( pdMS_TO_TICKS(msec) );
}
Expand All @@ -51,12 +65,12 @@ static inline void osal_task_delay(uint32_t msec)
typedef StaticSemaphore_t osal_semaphore_def_t;
typedef SemaphoreHandle_t osal_semaphore_t;

static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
{
return xSemaphoreCreateBinaryStatic(semdef);
}

static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
{
if ( !in_isr )
{
Expand All @@ -78,13 +92,12 @@ static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
}
}

static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec)
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec)
{
uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? portMAX_DELAY : pdMS_TO_TICKS(msec);
return xSemaphoreTake(sem_hdl, ticks);
return xSemaphoreTake(sem_hdl, _osal_ms2tick(msec));
}

static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl)
TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl)
{
xQueueReset(sem_hdl);
}
Expand All @@ -95,17 +108,17 @@ static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl)
typedef StaticSemaphore_t osal_mutex_def_t;
typedef SemaphoreHandle_t osal_mutex_t;

static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
{
return xSemaphoreCreateMutexStatic(mdef);
}

static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
{
return osal_semaphore_wait(mutex_hdl, msec);
}

static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
{
return xSemaphoreGive(mutex_hdl);
}
Expand All @@ -114,7 +127,7 @@ static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
// QUEUE API
//--------------------------------------------------------------------+

// role device/host is used by OS NONE for mutex (disable usb isr) only
// _int_set is not used with an RTOS
#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
static _type _name##_##buf[_depth];\
osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf };
Expand All @@ -130,17 +143,17 @@ typedef struct

typedef QueueHandle_t osal_queue_t;

static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
{
return xQueueCreateStatic(qdef->depth, qdef->item_sz, (uint8_t*) qdef->buf, &qdef->sq);
}

static inline bool osal_queue_receive(osal_queue_t qhdl, void* data)
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec)
{
return xQueueReceive(qhdl, data, portMAX_DELAY);
return xQueueReceive(qhdl, data, _osal_ms2tick(msec));
}

static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
{
if ( !in_isr )
{
Expand All @@ -162,7 +175,7 @@ static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in
}
}

static inline bool osal_queue_empty(osal_queue_t qhdl)
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl)
{
return uxQueueMessagesWaiting(qhdl) == 0;
}
Expand Down
Loading