summaryrefslogtreecommitdiff
path: root/src/osal
diff options
context:
space:
mode:
authorHiFiPhile <[email protected]>2026-06-22 21:30:58 +0200
committerHiFiPhile <[email protected]>2026-06-22 21:30:58 +0200
commit693cdce08e14833f26f4e8a1f26e4fd546be4c35 (patch)
tree7667d2223dc32d9f21b5b60ab200e64ed46e3e20 /src/osal
parent41e9eaa65a935136085d78ec4b99c81ff991b560 (diff)
parentcd3561bf158afd5a5718904b8139a338d1e3b67c (diff)
Merge remote-tracking branch 'tinyusb/master' into pr-osal-spin-deinit
Signed-off-by: HiFiPhile <[email protected]>
Diffstat (limited to 'src/osal')
-rw-r--r--src/osal/osal.h62
-rw-r--r--src/osal/osal_freertos.h47
-rw-r--r--src/osal/osal_mynewt.h37
-rw-r--r--src/osal/osal_none.h59
-rw-r--r--src/osal/osal_pico.h66
-rw-r--r--src/osal/osal_rtthread.h10
-rw-r--r--src/osal/osal_rtx4.h10
-rw-r--r--src/osal/osal_threadx.h206
-rw-r--r--src/osal/osal_zephyr.h10
9 files changed, 419 insertions, 88 deletions
diff --git a/src/osal/osal.h b/src/osal/osal.h
index 3fa1ff6bf..2114c0a61 100644
--- a/src/osal/osal.h
+++ b/src/osal/osal.h
@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_OSAL_H_
-#define _TUSB_OSAL_H_
+#ifndef TUSB_OSAL_H_
+#define TUSB_OSAL_H_
#ifdef __cplusplus
extern "C" {
@@ -33,7 +33,7 @@
#include "common/tusb_common.h"
-typedef void (*osal_task_func_t)( void * );
+typedef void (*osal_task_func_t)(void* param);
// Timeout
#define OSAL_TIMEOUT_NOTIMEOUT (0) // Return immediately
@@ -65,42 +65,48 @@ typedef void (*osal_task_func_t)( void * );
#include "osal_rtx4.h"
#elif CFG_TUSB_OS == OPT_OS_ZEPHYR
#include "osal_zephyr.h"
+#elif CFG_TUSB_OS == OPT_OS_THREADX
+ #include "osal_threadx.h"
#elif CFG_TUSB_OS == OPT_OS_CUSTOM
#include "tusb_os_custom.h" // implemented by application
#else
#error OS is not supported yet
#endif
-//--------------------------------------------------------------------+
-// OSAL Porting API
-// Should be implemented as static inline function in osal_port.h header
-/*
- void osal_spin_init(osal_spinlock_t *ctx);
- void osal_spin_deinit(osal_spinlock_t *ctx);
- void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr);
- void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr);
+/*--------------------------------------------------------------------
+ OSAL Porting API
+ Should be implemented as static inline function in osal_port.h header
+ uint32_t osal_time_millis(void);
+
+ void osal_task_delay(uint32_t msec);
+ osal_task_handle_t osal_task_get_current_handle(void);
+
+ void osal_spin_init(osal_spinlock_t *ctx);
+ void osal_spin_deinit(osal_spinlock_t *ctx);
+ void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr);
+ void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr);
- osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
- bool osal_semaphore_delete(osal_semaphore_t semd_hdl);
- 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
+ osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef);
+ bool osal_semaphore_delete(osal_semaphore_t semd_hdl);
+ 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);
- osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef);
- bool osal_mutex_delete(osal_mutex_t mutex_hdl)
- bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec);
- bool osal_mutex_unlock(osal_mutex_t mutex_hdl);
+ osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef);
+ bool osal_mutex_delete(osal_mutex_t mutex_hdl)
+ bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec);
+ bool osal_mutex_unlock(osal_mutex_t mutex_hdl);
+
+ osal_queue_t osal_queue_create(osal_queue_def_t* qdef);
+ bool osal_queue_delete(osal_queue_t qhdl);
+ 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);
+--------------------------------------------------------------------------*/
- osal_queue_t osal_queue_create(osal_queue_def_t* qdef);
- bool osal_queue_delete(osal_queue_t qhdl);
- 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);
-*/
-//--------------------------------------------------------------------+
#ifdef __cplusplus
}
#endif
-#endif /* _TUSB_OSAL_H_ */
+#endif
diff --git a/src/osal/osal_freertos.h b/src/osal/osal_freertos.h
index d9e084241..128626159 100644
--- a/src/osal/osal_freertos.h
+++ b/src/osal/osal_freertos.h
@@ -70,19 +70,32 @@ typedef struct {
} osal_queue_def_t;
#if defined(configQUEUE_REGISTRY_SIZE) && (configQUEUE_REGISTRY_SIZE>0)
- #define _OSAL_Q_NAME(_name) .name = #_name
+ #define OSAL_Q_NAME(_name) .name = #_name
#else
- #define _OSAL_Q_NAME(_name)
+ #define OSAL_Q_NAME(_name)
#endif
// _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, _OSAL_Q_NAME(_name) }
+ osal_queue_def_t _name = { .depth = _depth, .item_sz = sizeof(_type), .buf = _name##_##buf, OSAL_Q_NAME(_name) }
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
+typedef TaskHandle_t osal_task_handle_t;
+
+// Requires INCLUDE_xTaskGetCurrentTaskHandle == 1 in FreeRTOSConfig.h. FreeRTOS
+// also exposes the symbol when configUSE_MUTEXES == 1, so accept either.
+#if !defined(INCLUDE_xTaskGetCurrentTaskHandle) || (INCLUDE_xTaskGetCurrentTaskHandle == 0)
+ #if !defined(configUSE_MUTEXES) || (configUSE_MUTEXES == 0)
+ #error "TinyUSB host stack requires INCLUDE_xTaskGetCurrentTaskHandle or configUSE_MUTEXES to be enabled in FreeRTOSConfig.h"
+ #endif
+#endif
+TU_ATTR_ALWAYS_INLINE static inline osal_task_handle_t osal_task_get_current_handle(void) {
+ return xTaskGetCurrentTaskHandle();
+}
+
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; }
@@ -99,13 +112,17 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
vTaskDelay(pdMS_TO_TICKS(msec));
}
+TU_ATTR_ALWAYS_INLINE static inline uint32_t osal_time_millis(void) {
+ return pdTICKS_TO_MS(xTaskGetTickCount());
+}
+
//--------------------------------------------------------------------+
// Spinlock API
//--------------------------------------------------------------------+
#define OSAL_SPINLOCK_DEF(_name, _int_set) \
osal_spinlock_t _name
-#if TUSB_MCU_VENDOR_ESPRESSIF
+#ifdef ESP_PLATFORM
// Espressif critical take spinlock as argument and does not use in_isr
typedef portMUX_TYPE osal_spinlock_t;
@@ -145,11 +162,12 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_spin_deinit(osal_spinlock_t *ctx)
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
if (in_isr) {
- if (!TUP_MCU_MULTIPLE_CORE) {
- (void) ctx;
- return; // single core MCU does not need to lock in ISR
- }
+ #if TUP_MCU_MULTIPLE_CORE
*ctx = taskENTER_CRITICAL_FROM_ISR();
+ #else
+ (void) ctx;
+ return; // single core MCU does not need to lock in ISR
+ #endif
} else {
taskENTER_CRITICAL();
}
@@ -157,11 +175,12 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bo
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
if (in_isr) {
- if (!TUP_MCU_MULTIPLE_CORE) {
- (void) ctx;
- return; // single core MCU does not need to lock in ISR
- }
+ #if TUP_MCU_MULTIPLE_CORE
taskEXIT_CRITICAL_FROM_ISR(*ctx);
+ #else
+ (void) ctx;
+ return; // single core MCU does not need to lock in ISR
+ #endif
} else {
taskEXIT_CRITICAL();
}
@@ -174,7 +193,7 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx,
//--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t *semdef) {
#if configSUPPORT_STATIC_ALLOCATION
- return xSemaphoreCreateBinaryStatic(semdef);
+ return xSemaphoreCreateBinaryStatic((StaticSemaphore_t*) semdef);
#else
(void) semdef;
return xSemaphoreCreateBinary();
@@ -182,7 +201,7 @@ TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl) {
- vSemaphoreDelete(semd_hdl);
+ vSemaphoreDelete((SemaphoreHandle_t) semd_hdl);
return true;
}
diff --git a/src/osal/osal_mynewt.h b/src/osal/osal_mynewt.h
index 86279f56e..5dd275cc4 100644
--- a/src/osal/osal_mynewt.h
+++ b/src/osal/osal_mynewt.h
@@ -36,10 +36,20 @@
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
+typedef struct os_task* osal_task_handle_t;
+
+TU_ATTR_ALWAYS_INLINE static inline osal_task_handle_t osal_task_get_current_handle(void) {
+ return os_sched_get_current_task();
+}
+
TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
os_time_delay( os_time_ms_to_ticks32(msec) );
}
+TU_ATTR_ALWAYS_INLINE static inline uint32_t osal_time_millis(void) {
+ return os_time_ticks_to_ms32(os_time_get());
+}
+
//--------------------------------------------------------------------+
// Spinlock API
//--------------------------------------------------------------------+
@@ -123,6 +133,24 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd
return os_mutex_release(mutex_hdl) == OS_OK;
}
+TU_ATTR_ALWAYS_INLINE static inline os_time_t _osal_ms2tick(uint32_t msec) {
+ if (msec == OSAL_TIMEOUT_WAIT_FOREVER) {
+ return OS_TIMEOUT_NEVER;
+ }
+ if (msec == 0) {
+ return 0;
+ }
+
+ os_time_t ticks = os_time_ms_to_ticks32(msec);
+
+ // If 1 tick > 1 ms, still wait at least 1 tick for non-zero timeout.
+ if (ticks == 0) {
+ ticks = 1;
+ }
+
+ return ticks;
+}
+
//--------------------------------------------------------------------+
// QUEUE API
//--------------------------------------------------------------------+
@@ -161,10 +189,11 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) {
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) {
- (void) msec; // os_eventq_get() does not take timeout, always behave as msec = WAIT_FOREVER
-
- struct os_event* ev;
- ev = os_eventq_get(&qhdl->evq);
+ struct os_eventq* evq = &qhdl->evq;
+ struct os_event* ev = os_eventq_poll(&evq, 1, _osal_ms2tick(msec));
+ if (!ev) {
+ return false;
+ }
memcpy(data, ev->ev_arg, qhdl->item_sz); // copy message
os_memblock_put(&qhdl->mpool, ev->ev_arg); // put back mem block
diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h
index 0893bb55c..49439cef0 100644
--- a/src/osal/osal_none.h
+++ b/src/osal/osal_none.h
@@ -31,16 +31,40 @@
extern "C" {
#endif
+// osal_time_millis() is not provided, tusb_time_millis_api() must be implemented by user application
+
+//--------------------------------------------------------------------+
+// TASK API
+//--------------------------------------------------------------------+
+// Bare-metal single context: return a non-NULL sentinel so equality compares true.
+typedef void* osal_task_handle_t;
+
+TU_ATTR_ALWAYS_INLINE static inline osal_task_handle_t osal_task_get_current_handle(void) {
+ return (osal_task_handle_t) 1;
+}
+
+// Bare-metal has no scheduler to yield to; this is dead code in practice because
+// callers gate it on running outside the host task, which can't happen here.
+TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
+ (void) msec;
+}
+
//--------------------------------------------------------------------+
// Spinlock API
//--------------------------------------------------------------------+
+// Note: This implementation is designed for bare-metal single-core systems without RTOS.
+// - Supports nested locking within the same execution context
+// - NOT suitable for true SMP (Symmetric Multi-Processing) systems
+// - NOT thread-safe for multi-threaded environments
+// - Primarily manages interrupt enable/disable state for critical sections
typedef struct {
- void (* interrupt_set)(bool);
+ void (* interrupt_set)(bool enabled);
+ uint32_t nested_count;
} osal_spinlock_t;
// For SMP, spinlock must be locked by hardware, cannot just use interrupt
#define OSAL_SPINLOCK_DEF(_name, _int_set) \
- osal_spinlock_t _name = { .interrupt_set = _int_set }
+ osal_spinlock_t _name = { .interrupt_set = _int_set, .nested_count = 0 }
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
(void) ctx;
@@ -51,13 +75,22 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_spin_deinit(osal_spinlock_t *ctx)
}
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
- if (!in_isr) {
+ // Disable interrupts first to make nested_count increment atomic
+ if (!in_isr && ctx->nested_count == 0) {
ctx->interrupt_set(false);
}
+ ctx->nested_count++;
}
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
- if (!in_isr) {
+ if (ctx->nested_count == 0) {
+ return; // spin is not locked to begin with
+ }
+
+ ctx->nested_count--;
+
+ // Only re-enable interrupts when fully unlocked
+ if (!in_isr && ctx->nested_count == 0) {
ctx->interrupt_set(true);
}
}
@@ -145,19 +178,19 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd
#include "common/tusb_fifo.h"
typedef struct {
- void (* interrupt_set)(bool);
+ void (* interrupt_set)(bool enabled);
+ uint16_t item_size;
tu_fifo_t ff;
} osal_queue_def_t;
typedef osal_queue_def_t* osal_queue_t;
// _int_set is used as mutex in OS NONE (disable/enable USB ISR)
-#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
- uint8_t _name##_buf[_depth*sizeof(_type)]; \
- osal_queue_def_t _name = { \
- .interrupt_set = _int_set, \
- .ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \
- }
+#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
+ uint8_t _name##_buf[_depth * sizeof(_type)]; \
+ osal_queue_def_t _name = {.interrupt_set = _int_set, \
+ .item_size = sizeof(_type), \
+ .ff = TU_FIFO_INIT(_name##_buf, _depth * sizeof(_type), false)}
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
tu_fifo_clear(&qdef->ff);
@@ -173,7 +206,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, v
(void) msec; // not used, always behave as msec = 0
qhdl->interrupt_set(false);
- const bool success = tu_fifo_read(&qhdl->ff, data);
+ const bool success = (tu_fifo_read_n(&qhdl->ff, data, qhdl->item_size) > 0);
qhdl->interrupt_set(true);
return success;
@@ -184,7 +217,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void
qhdl->interrupt_set(false);
}
- const bool success = tu_fifo_write(&qhdl->ff, data);
+ const bool success = (tu_fifo_write_n(&qhdl->ff, data, qhdl->item_size) > 0);
if (!in_isr) {
qhdl->interrupt_set(true);
diff --git a/src/osal/osal_pico.h b/src/osal/osal_pico.h
index f1b48f172..a2fd470e4 100644
--- a/src/osal/osal_pico.h
+++ b/src/osal/osal_pico.h
@@ -39,16 +39,26 @@ extern "C" {
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
+// Bare-metal single context: return a non-NULL sentinel so equality compares true.
+typedef void* osal_task_handle_t;
+
+TU_ATTR_ALWAYS_INLINE static inline osal_task_handle_t osal_task_get_current_handle(void) {
+ return (osal_task_handle_t) 1;
+}
+
TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
sleep_ms(msec);
}
+TU_ATTR_ALWAYS_INLINE static inline uint32_t osal_time_millis(void) {
+ return to_ms_since_boot(get_absolute_time());
+}
+
//--------------------------------------------------------------------+
// Spinlock API
//--------------------------------------------------------------------+
typedef critical_section_t osal_spinlock_t; // pico implement critical section with spinlock
-#define OSAL_SPINLOCK_DEF(_name, _int_set) \
- osal_spinlock_t _name
+#define OSAL_SPINLOCK_DEF(_name, _int_set) osal_spinlock_t _name
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
critical_section_init(ctx);
@@ -62,34 +72,33 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_spin_deinit(osal_spinlock_t *ctx)
}
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
- (void) in_isr;
+ (void)in_isr;
critical_section_enter_blocking(ctx);
}
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
- (void) in_isr;
+ (void)in_isr;
critical_section_exit(ctx);
}
//--------------------------------------------------------------------+
// Binary Semaphore API
//--------------------------------------------------------------------+
-typedef struct semaphore osal_semaphore_def_t, * osal_semaphore_t;
+typedef struct semaphore osal_semaphore_def_t, *osal_semaphore_t;
-TU_ATTR_ALWAYS_INLINE 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) {
sem_init(semdef, 0, 255);
return semdef;
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl) {
- (void) semd_hdl;
+ (void)semd_hdl;
return true; // nothing to do
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
- (void) in_isr;
- sem_release(sem_hdl);
- return true;
+ (void)in_isr;
+ return sem_release(sem_hdl);
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) {
@@ -104,15 +113,15 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t s
// MUTEX API
// Within tinyusb, mutex is never used in ISR context
//--------------------------------------------------------------------+
-typedef struct mutex osal_mutex_def_t, * osal_mutex_t;
+typedef struct mutex osal_mutex_def_t, *osal_mutex_t;
-TU_ATTR_ALWAYS_INLINE 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) {
mutex_init(mdef);
return mdef;
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) {
- (void) mutex_hdl;
+ (void)mutex_hdl;
return true; // nothing to do
}
@@ -131,46 +140,45 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd
#include "common/tusb_fifo.h"
typedef struct {
- tu_fifo_t ff;
+ uint16_t item_size;
+ tu_fifo_t ff;
struct critical_section critsec; // osal_queue may be used in IRQs, so need critical section
} osal_queue_def_t;
-typedef osal_queue_def_t* osal_queue_t;
+typedef osal_queue_def_t *osal_queue_t;
// role device/host is used by OS NONE for mutex (disable usb isr) only
-#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
- uint8_t _name##_buf[_depth*sizeof(_type)]; \
- osal_queue_def_t _name = { \
- .ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \
- }
+#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
+ uint8_t _name##_buf[_depth * sizeof(_type)]; \
+ osal_queue_def_t _name = {.item_size = sizeof(_type), .ff = TU_FIFO_INIT(_name##_buf, _depth * sizeof(_type), false)}
-TU_ATTR_ALWAYS_INLINE 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) {
critical_section_init(&qdef->critsec);
tu_fifo_clear(&qdef->ff);
- return (osal_queue_t) qdef;
+ return (osal_queue_t)qdef;
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) {
- osal_queue_def_t* qdef = (osal_queue_def_t*) qhdl;
+ osal_queue_def_t *qdef = (osal_queue_def_t *)qhdl;
critical_section_deinit(&qdef->critsec);
return true;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) {
- (void) msec; // not used, always behave as msec = 0
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void *data, uint32_t msec) {
+ (void)msec; // not used, always behave as msec = 0
critical_section_enter_blocking(&qhdl->critsec);
- bool success = tu_fifo_read(&qhdl->ff, data);
+ bool success = tu_fifo_read_n(&qhdl->ff, data, qhdl->item_size);
critical_section_exit(&qhdl->critsec);
return success;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const* data, bool in_isr) {
- (void) in_isr;
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, const void *data, bool in_isr) {
+ (void)in_isr;
critical_section_enter_blocking(&qhdl->critsec);
- bool success = tu_fifo_write(&qhdl->ff, data);
+ bool success = tu_fifo_write_n(&qhdl->ff, data, qhdl->item_size);
critical_section_exit(&qhdl->critsec);
return success;
diff --git a/src/osal/osal_rtthread.h b/src/osal/osal_rtthread.h
index e126a2907..d65a2a783 100644
--- a/src/osal/osal_rtthread.h
+++ b/src/osal/osal_rtthread.h
@@ -38,10 +38,20 @@ extern "C" {
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
+typedef rt_thread_t osal_task_handle_t;
+
+TU_ATTR_ALWAYS_INLINE static inline osal_task_handle_t osal_task_get_current_handle(void) {
+ return rt_thread_self();
+}
+
TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
rt_thread_mdelay(msec);
}
+TU_ATTR_ALWAYS_INLINE static inline uint32_t osal_time_millis(void) {
+ return (uint32_t)((((uint64_t)rt_tick_get()) * 1000) / RT_TICK_PER_SECOND);
+}
+
//--------------------------------------------------------------------+
// Spinlock API
//--------------------------------------------------------------------+
diff --git a/src/osal/osal_rtx4.h b/src/osal/osal_rtx4.h
index 813b351ff..ba082998a 100644
--- a/src/osal/osal_rtx4.h
+++ b/src/osal/osal_rtx4.h
@@ -37,6 +37,12 @@ extern "C" {
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
+typedef OS_TID osal_task_handle_t;
+
+TU_ATTR_ALWAYS_INLINE static inline osal_task_handle_t osal_task_get_current_handle(void) {
+ return os_tsk_self();
+}
+
TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
uint16_t hi = msec >> 16;
uint16_t lo = msec;
@@ -46,6 +52,10 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
os_dly_wait(lo);
}
+TU_ATTR_ALWAYS_INLINE static inline uint32_t osal_time_millis(void) {
+ return os_time_get();
+}
+
TU_ATTR_ALWAYS_INLINE static inline uint16_t msec2wait(uint32_t msec) {
if (msec == OSAL_TIMEOUT_WAIT_FOREVER) {
return 0xFFFF;
diff --git a/src/osal/osal_threadx.h b/src/osal/osal_threadx.h
new file mode 100644
index 000000000..cca4eb487
--- /dev/null
+++ b/src/osal/osal_threadx.h
@@ -0,0 +1,206 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef TUSB_OSAL_THREADX_H_
+#define TUSB_OSAL_THREADX_H_
+
+// ThreadX Headers
+#include "tx_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// TASK API
+//--------------------------------------------------------------------+
+typedef TX_THREAD* osal_task_handle_t;
+
+TU_ATTR_ALWAYS_INLINE static inline osal_task_handle_t osal_task_get_current_handle(void) {
+ return tx_thread_identify();
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t _osal_ms2tick(uint32_t msec) {
+ if ( msec == TX_WAIT_FOREVER ) {
+ return TX_WAIT_FOREVER;
+ }
+ if ( msec == 0 ) {
+ return 0;
+ }
+
+ uint32_t ticks = msec * TX_TIMER_TICKS_PER_SECOND / 1000;
+
+ // TX_TIMER_TICKS_PER_SECOND 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;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t osal_time_millis(void) {
+ return (uint32_t)((uint64_t) tx_time_get() * 1000u / TX_TIMER_TICKS_PER_SECOND);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
+ tx_thread_sleep(_osal_ms2tick(msec));
+}
+
+//--------------------------------------------------------------------+
+// Spinlock API
+//--------------------------------------------------------------------+
+//--------------------------------------------------------------------+
+// Spinlock API
+//--------------------------------------------------------------------+
+typedef struct {
+ void (* interrupt_set)(bool);
+} osal_spinlock_t;
+
+// For SMP, spinlock must be locked by hardware, cannot just use interrupt
+#define OSAL_SPINLOCK_DEF(_name, _int_set) \
+ osal_spinlock_t _name = { .interrupt_set = _int_set }
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
+ (void) ctx;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
+ if (!in_isr) {
+ ctx->interrupt_set(false);
+ }
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
+ if (!in_isr) {
+ ctx->interrupt_set(true);
+ }
+}
+
+
+//--------------------------------------------------------------------+
+// Binary Semaphore API (act)
+//--------------------------------------------------------------------+
+// Note: semaphores are not used in tinyusb for now, and their API has not been tested
+
+typedef TX_SEMAPHORE osal_semaphore_def_t, * osal_semaphore_t;
+
+TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t *semdef) {
+ tx_semaphore_create(semdef, TX_NULL, 0);
+ return semdef;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t sem_hdl) {
+ (void) sem_hdl;
+ return TX_SUCCESS == tx_semaphore_delete(sem_hdl);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
+ (void) in_isr;
+ return TX_SUCCESS == tx_semaphore_put(sem_hdl);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) {
+ return TX_SUCCESS == tx_semaphore_get(sem_hdl, _osal_ms2tick(msec));
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) {
+ (void) sem_hdl;
+}
+
+//--------------------------------------------------------------------+
+// MUTEX API
+//--------------------------------------------------------------------+
+typedef TX_MUTEX osal_mutex_def_t, *osal_mutex_t;
+
+TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) {
+ if (TX_SUCCESS == tx_mutex_create(mdef, mdef->tx_mutex_name, TX_NO_INHERIT)) {
+ return mdef;
+ } else {
+ return NULL;
+ }
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) {
+ (void) mutex_hdl;
+ return true; // nothing to do
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) {
+ return TX_SUCCESS == tx_mutex_get(mutex_hdl, _osal_ms2tick(msec));
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) {
+ return TX_SUCCESS == tx_mutex_put(mutex_hdl);
+}
+
+//--------------------------------------------------------------------+
+// QUEUE API
+//--------------------------------------------------------------------+
+
+typedef TX_QUEUE osal_queue_def_t, * osal_queue_t;
+
+// _int_set is not used with an RTOS _usbd_qdef
+
+#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
+static _type _name##_buf[_depth]; \
+osal_queue_def_t _name = { \
+ .tx_queue_name = (CHAR*)(uintptr_t)#_name, \
+ .tx_queue_message_size = (sizeof(_type) + 3) / 4, \
+ .tx_queue_capacity = _depth, \
+ .tx_queue_start = (ULONG *) _name##_buf }
+
+
+TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
+ return TX_SUCCESS ==
+ tx_queue_create(qdef, qdef->tx_queue_name, qdef->tx_queue_message_size, qdef->tx_queue_start, qdef->tx_queue_capacity * qdef->tx_queue_message_size * 4)
+ ? qdef : 0;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) {
+ (void) qhdl;
+ return true;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) {
+ return 0 == tx_queue_receive(qhdl, data, _osal_ms2tick(msec));
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const *data, bool in_isr) {
+ return 0 == tx_queue_send(qhdl, (VOID *)(uintptr_t) data, in_isr ? TX_NO_WAIT : TX_WAIT_FOREVER);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) {
+ ULONG enqueued;
+ tx_queue_info_get(qhdl, 0, &enqueued, 0, 0, 0, 0);
+ return enqueued == 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/osal/osal_zephyr.h b/src/osal/osal_zephyr.h
index f0e1a6a2e..c84ce3970 100644
--- a/src/osal/osal_zephyr.h
+++ b/src/osal/osal_zephyr.h
@@ -31,10 +31,20 @@
//--------------------------------------------------------------------+
// TASK API
//--------------------------------------------------------------------+
+typedef k_tid_t osal_task_handle_t;
+
+TU_ATTR_ALWAYS_INLINE static inline osal_task_handle_t osal_task_get_current_handle(void) {
+ return k_current_get();
+}
+
TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
k_msleep(msec);
}
+TU_ATTR_ALWAYS_INLINE static inline uint32_t osal_time_millis(void) {
+ return k_uptime_get_32();
+}
+
//--------------------------------------------------------------------+
// Spinlock API
//--------------------------------------------------------------------+