Skip to content

Commit 55a5fd5

Browse files
authored
Merge pull request #1440 from hathach/osal-queue-timeout
Osal queue timeout
2 parents 9c8c5c1 + 8757287 commit 55a5fd5

File tree

17 files changed

+184
-122
lines changed

17 files changed

+184
-122
lines changed

.github/ISSUE_TEMPLATE/config.yml

+4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
blank_issues_enabled: false
12
contact_links:
23
- name: TinyUSB Discussion
34
url: https://github.com/hathach/tinyusb/discussions
45
about: If you have other questions or need help, post it here.
6+
- name: TinyUSB Docs
7+
url: https://docs.tinyusb.org/
8+
about: Online documentation

examples/device/cdc_msc_freertos/src/main.c

+9-5
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,11 @@ void usb_device_task(void* param)
130130
// RTOS forever loop
131131
while (1)
132132
{
133-
// tinyusb device task
133+
// put this thread to waiting state until there is new events
134134
tud_task();
135+
136+
// following code only run if tud_task() process at least 1 event
137+
tud_cdc_write_flush();
135138
}
136139
}
137140

@@ -181,7 +184,7 @@ void cdc_task(void* params)
181184
// if ( tud_cdc_connected() )
182185
{
183186
// There are data available
184-
if ( tud_cdc_available() )
187+
while ( tud_cdc_available() )
185188
{
186189
uint8_t buf[64];
187190

@@ -194,12 +197,13 @@ void cdc_task(void* params)
194197
// for throughput test e.g
195198
// $ dd if=/dev/zero of=/dev/ttyACM0 count=10000
196199
tud_cdc_write(buf, count);
197-
tud_cdc_write_flush();
198200
}
201+
202+
tud_cdc_write_flush();
199203
}
200204

201-
// For ESP32-S2 this delay is essential to allow idle how to run and reset wdt
202-
vTaskDelay(pdMS_TO_TICKS(10));
205+
// For ESP32-Sx this delay is essential to allow idle how to run and reset watchdog
206+
vTaskDelay(1);
203207
}
204208
}
205209

examples/device/hid_composite_freertos/src/main.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,10 @@ void usb_device_task(void* param)
132132
// RTOS forever loop
133133
while (1)
134134
{
135-
// tinyusb device task
135+
// put this thread to waiting state until there is new events
136136
tud_task();
137+
138+
// following code only run if tud_task() process at least 1 event
137139
}
138140
}
139141

src/common/tusb_verify.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@
9999
*------------------------------------------------------------------*/
100100

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

105105
/*------------- Generator for TU_VERIFY and TU_VERIFY_HDLR -------------*/
106106
#define TU_VERIFY_DEFINE(_cond, _handler, _ret) do \
@@ -116,7 +116,7 @@
116116
#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, , false)
117117
#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, , _ret)
118118

119-
#define TU_VERIFY(...) GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, UNUSED)(__VA_ARGS__)
119+
#define TU_VERIFY(...) _GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, UNUSED)(__VA_ARGS__)
120120

121121

122122
/*------------------------------------------------------------------*/
@@ -127,7 +127,7 @@
127127
#define TU_VERIFY_HDLR_2ARGS(_cond, _handler) TU_VERIFY_DEFINE(_cond, _handler, false)
128128
#define TU_VERIFY_HDLR_3ARGS(_cond, _handler, _ret) TU_VERIFY_DEFINE(_cond, _handler, _ret)
129129

130-
#define TU_VERIFY_HDLR(...) GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_HDLR_3ARGS, TU_VERIFY_HDLR_2ARGS,UNUSED)(__VA_ARGS__)
130+
#define TU_VERIFY_HDLR(...) _GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_HDLR_3ARGS, TU_VERIFY_HDLR_2ARGS,UNUSED)(__VA_ARGS__)
131131

132132
/*------------------------------------------------------------------*/
133133
/* ASSERT
@@ -139,7 +139,7 @@
139139
#define ASSERT_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), _ret)
140140

141141
#ifndef TU_ASSERT
142-
#define TU_ASSERT(...) GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS,UNUSED)(__VA_ARGS__)
142+
#define TU_ASSERT(...) _GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS,UNUSED)(__VA_ARGS__)
143143
#endif
144144

145145
/*------------------------------------------------------------------*/

src/device/usbd.c

+9-3
Original file line numberDiff line numberDiff line change
@@ -466,17 +466,18 @@ bool tud_task_event_ready(void)
466466
}
467467
@endcode
468468
*/
469-
void tud_task (void)
469+
void tud_task_ext(uint32_t timeout_ms, bool in_isr)
470470
{
471+
(void) in_isr; // not implemented yet
472+
471473
// Skip if stack is not initialized
472474
if ( !tusb_inited() ) return;
473475

474476
// Loop until there is no more events in the queue
475477
while (1)
476478
{
477479
dcd_event_t event;
478-
479-
if ( !osal_queue_receive(_usbd_q, &event) ) return;
480+
if ( !osal_queue_receive(_usbd_q, &event, timeout_ms) ) return;
480481

481482
#if CFG_TUSB_DEBUG >= 2
482483
if (event.event_id == DCD_EVENT_SETUP_RECEIVED) TU_LOG2("\r\n"); // extra line for setup
@@ -593,6 +594,11 @@ void tud_task (void)
593594
TU_BREAKPOINT();
594595
break;
595596
}
597+
598+
#if CFG_TUSB_OS != OPT_OS_NONE && CFG_TUSB_OS != OPT_OS_PICO
599+
// return if there is no more events, for application to run other background
600+
if (osal_queue_empty(_usbd_q)) return;
601+
#endif
596602
}
597603
}
598604

src/device/usbd.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,17 @@ bool tud_init (uint8_t rhport);
4343
// Check if device stack is already initialized
4444
bool tud_inited(void);
4545

46+
// Task function should be called in main/rtos loop, extended version of tud_task()
47+
// - timeout_ms: millisecond to wait, zero = no wait, 0xFFFFFFFF = wait forever
48+
// - in_isr: if function is called in ISR
49+
void tud_task_ext(uint32_t timeout_ms, bool in_isr);
50+
4651
// Task function should be called in main/rtos loop
47-
void tud_task (void);
52+
TU_ATTR_ALWAYS_INLINE static inline
53+
void tud_task (void)
54+
{
55+
tud_task_ext(UINT32_MAX, false);
56+
}
4857

4958
// Check if there is pending events need proccessing by tud_task()
5059
bool tud_task_event_ready(void);

src/host/usbh.c

+9-2
Original file line numberDiff line numberDiff line change
@@ -392,16 +392,18 @@ bool tuh_init(uint8_t rhport)
392392
}
393393
@endcode
394394
*/
395-
void tuh_task(void)
395+
void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
396396
{
397+
(void) in_isr; // not implemented yet
398+
397399
// Skip if stack is not initialized
398400
if ( !tusb_inited() ) return;
399401

400402
// Loop until there is no more events in the queue
401403
while (1)
402404
{
403405
hcd_event_t event;
404-
if ( !osal_queue_receive(_usbh_q, &event) ) return;
406+
if ( !osal_queue_receive(_usbh_q, &event, timeout_ms) ) return;
405407

406408
switch (event.event_id)
407409
{
@@ -497,6 +499,11 @@ void tuh_task(void)
497499

498500
default: break;
499501
}
502+
503+
#if CFG_TUSB_OS != OPT_OS_NONE && CFG_TUSB_OS != OPT_OS_PICO
504+
// return if there is no more events, for application to run other background
505+
if (osal_queue_empty(_usbh_q)) return;
506+
#endif
500507
}
501508
}
502509

src/host/usbh.h

+14-5
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,17 @@ bool tuh_init(uint8_t rhport);
9191
// Check if host stack is already initialized
9292
bool tuh_inited(void);
9393

94+
// Task function should be called in main/rtos loop, extended version of tuh_task()
95+
// - timeout_ms: millisecond to wait, zero = no wait, 0xFFFFFFFF = wait forever
96+
// - in_isr: if function is called in ISR
97+
void tuh_task_ext(uint32_t timeout_ms, bool in_isr);
98+
9499
// Task function should be called in main/rtos loop
95-
void tuh_task(void);
100+
TU_ATTR_ALWAYS_INLINE static inline
101+
void tuh_task(void)
102+
{
103+
tuh_task_ext(UINT32_MAX, false);
104+
}
96105

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

108117
// Check if device is suspended
109-
TU_ATTR_ALWAYS_INLINE
110-
static inline bool tuh_suspended(uint8_t daddr)
118+
TU_ATTR_ALWAYS_INLINE static inline
119+
bool tuh_suspended(uint8_t daddr)
111120
{
112121
// TODO implement suspend & resume on host
113122
(void) daddr;
114123
return false;
115124
}
116125

117126
// Check if device is ready to communicate with
118-
TU_ATTR_ALWAYS_INLINE
119-
static inline bool tuh_ready(uint8_t daddr)
127+
TU_ATTR_ALWAYS_INLINE static inline
128+
bool tuh_ready(uint8_t daddr)
120129
{
121130
return tuh_mounted(daddr) && !tuh_suspended(daddr);
122131
}

src/osal/osal.h

+11-11
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,19 @@ typedef void (*osal_task_func_t)( void * );
6666
// OSAL Porting API
6767
// Should be implemented as static inline function in osal_port.h header
6868
/*
69-
static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
70-
static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr);
71-
static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec);
72-
static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl); // TODO removed
69+
osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
70+
bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr);
71+
bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec);
72+
void osal_semaphore_reset(osal_semaphore_t sem_hdl); // TODO removed
7373
74-
static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef);
75-
static inline bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec);
76-
static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl);
74+
osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef);
75+
bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec);
76+
bool osal_mutex_unlock(osal_mutex_t mutex_hdl);
7777
78-
static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef);
79-
static inline bool osal_queue_receive(osal_queue_t qhdl, void* data);
80-
static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr);
81-
static inline bool osal_queue_empty(osal_queue_t qhdl);
78+
osal_queue_t osal_queue_create(osal_queue_def_t* qdef);
79+
bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec);
80+
bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr);
81+
bool osal_queue_empty(osal_queue_t qhdl);
8282
*/
8383
//--------------------------------------------------------------------+
8484

src/osal/osal_freertos.h

+29-16
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,24 @@
3737
extern "C" {
3838
#endif
3939

40+
TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec)
41+
{
42+
if (msec == OSAL_TIMEOUT_WAIT_FOREVER) return portMAX_DELAY;
43+
if (msec == 0) return 0;
44+
45+
uint32_t ticks = pdMS_TO_TICKS(msec);
46+
47+
// configTICK_RATE_HZ is less than 1000 and 1 tick > 1 ms
48+
// we still need to delay at least 1 tick
49+
if (ticks == 0) ticks =1 ;
50+
51+
return ticks;
52+
}
53+
4054
//--------------------------------------------------------------------+
4155
// TASK API
4256
//--------------------------------------------------------------------+
43-
static inline void osal_task_delay(uint32_t msec)
57+
TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec)
4458
{
4559
vTaskDelay( pdMS_TO_TICKS(msec) );
4660
}
@@ -51,12 +65,12 @@ static inline void osal_task_delay(uint32_t msec)
5165
typedef StaticSemaphore_t osal_semaphore_def_t;
5266
typedef SemaphoreHandle_t osal_semaphore_t;
5367

54-
static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
68+
TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef)
5569
{
5670
return xSemaphoreCreateBinaryStatic(semdef);
5771
}
5872

59-
static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
73+
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
6074
{
6175
if ( !in_isr )
6276
{
@@ -78,13 +92,12 @@ static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
7892
}
7993
}
8094

81-
static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec)
95+
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec)
8296
{
83-
uint32_t const ticks = (msec == OSAL_TIMEOUT_WAIT_FOREVER) ? portMAX_DELAY : pdMS_TO_TICKS(msec);
84-
return xSemaphoreTake(sem_hdl, ticks);
97+
return xSemaphoreTake(sem_hdl, _osal_ms2tick(msec));
8598
}
8699

87-
static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl)
100+
TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl)
88101
{
89102
xQueueReset(sem_hdl);
90103
}
@@ -95,17 +108,17 @@ static inline void osal_semaphore_reset(osal_semaphore_t const sem_hdl)
95108
typedef StaticSemaphore_t osal_mutex_def_t;
96109
typedef SemaphoreHandle_t osal_mutex_t;
97110

98-
static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
111+
TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef)
99112
{
100113
return xSemaphoreCreateMutexStatic(mdef);
101114
}
102115

103-
static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
116+
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock (osal_mutex_t mutex_hdl, uint32_t msec)
104117
{
105118
return osal_semaphore_wait(mutex_hdl, msec);
106119
}
107120

108-
static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
121+
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
109122
{
110123
return xSemaphoreGive(mutex_hdl);
111124
}
@@ -114,7 +127,7 @@ static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl)
114127
// QUEUE API
115128
//--------------------------------------------------------------------+
116129

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

131144
typedef QueueHandle_t osal_queue_t;
132145

133-
static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
146+
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
134147
{
135148
return xQueueCreateStatic(qdef->depth, qdef->item_sz, (uint8_t*) qdef->buf, &qdef->sq);
136149
}
137150

138-
static inline bool osal_queue_receive(osal_queue_t qhdl, void* data)
151+
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec)
139152
{
140-
return xQueueReceive(qhdl, data, portMAX_DELAY);
153+
return xQueueReceive(qhdl, data, _osal_ms2tick(msec));
141154
}
142155

143-
static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
156+
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in_isr)
144157
{
145158
if ( !in_isr )
146159
{
@@ -162,7 +175,7 @@ static inline bool osal_queue_send(osal_queue_t qhdl, void const * data, bool in
162175
}
163176
}
164177

165-
static inline bool osal_queue_empty(osal_queue_t qhdl)
178+
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl)
166179
{
167180
return uxQueueMessagesWaiting(qhdl) == 0;
168181
}

0 commit comments

Comments
 (0)