summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/tusb_common.h83
-rw-r--r--src/common/tusb_compiler.h62
-rw-r--r--src/common/tusb_debug.h45
-rw-r--r--src/common/tusb_fifo.c515
-rw-r--r--src/common/tusb_fifo.h128
-rw-r--r--src/common/tusb_mcu.h380
-rw-r--r--src/common/tusb_private.h119
-rw-r--r--src/common/tusb_timeout.h80
-rw-r--r--src/common/tusb_types.h289
-rw-r--r--src/common/tusb_verify.h75
10 files changed, 1162 insertions, 614 deletions
diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h
index b1ee40a1a..74cac965d 100644
--- a/src/common/tusb_common.h
+++ b/src/common/tusb_common.h
@@ -37,6 +37,7 @@
#define TU_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) )
#define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) )
#define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) )
+#define TU_DIV_CEIL(n, d) (((n) + (d) - 1) / (d))
#define TU_U16(_high, _low) ((uint16_t) (((_high) << 8) | (_low)))
#define TU_U16_HIGH(_u16) ((uint8_t) (((_u16) >> 8) & 0x00ff))
@@ -53,6 +54,8 @@
#define U32_TO_U8S_LE(_u32) TU_U32_BYTE0(_u32), TU_U32_BYTE1(_u32), TU_U32_BYTE2(_u32), TU_U32_BYTE3(_u32)
#define TU_BIT(n) (1UL << (n))
+
+// Generate a mask with bit from high (31) to low (0) set, e.g TU_GENMASK(3, 0) = 0b1111
#define TU_GENMASK(h, l) ( (UINT32_MAX << (l)) & (UINT32_MAX >> (31 - (h))) )
//--------------------------------------------------------------------+
@@ -62,6 +65,7 @@
// Standard Headers
#include <stdbool.h>
#include <stdint.h>
+#include <inttypes.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
@@ -73,7 +77,20 @@
#include "tusb_types.h"
#include "tusb_debug.h"
-#include "tusb_timeout.h" // TODO remove
+//--------------------------------------------------------------------+
+// Optional API implemented by application if needed
+// TODO move to a more obvious place/file
+//--------------------------------------------------------------------+
+
+// flush data cache
+TU_ATTR_WEAK extern void tusb_app_dcache_flush(uintptr_t addr, uint32_t data_size);
+
+// invalidate data cache
+TU_ATTR_WEAK extern void tusb_app_dcache_invalidate(uintptr_t addr, uint32_t data_size);
+
+// Optional physical <-> virtual address translation
+TU_ATTR_WEAK extern void* tusb_app_virt_to_phys(void *virt_addr);
+TU_ATTR_WEAK extern void* tusb_app_phys_to_virt(void *phys_addr);
//--------------------------------------------------------------------+
// Internal Inline Functions
@@ -83,15 +100,38 @@
#define tu_memclr(buffer, size) memset((buffer), 0, (size))
#define tu_varclr(_var) tu_memclr(_var, sizeof(*(_var)))
+// This is a backport of memset_s from c11
+TU_ATTR_ALWAYS_INLINE static inline int tu_memset_s(void *dest, size_t destsz, int ch, size_t count) {
+ // TODO may check if desst and src is not NULL
+ if ( count > destsz ) {
+ return -1;
+ }
+ memset(dest, ch, count);
+ return 0;
+}
+
+// This is a backport of memcpy_s from c11
+TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, const void *src, size_t count) {
+ // TODO may check if desst and src is not NULL
+ if ( count > destsz ) {
+ return -1;
+ }
+ memcpy(dest, src, count);
+ return 0;
+}
+
+
//------------- Bytes -------------//
-TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0)
-{
- return ( ((uint32_t) b3) << 24) | ( ((uint32_t) b2) << 16) | ( ((uint32_t) b1) << 8) | b0;
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0) {
+ return (((uint32_t)b3) << 24) | (((uint32_t)b2) << 16) | (((uint32_t)b1) << 8) | b0;
}
-TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u16(uint8_t high, uint8_t low)
-{
- return (uint16_t) ((((uint16_t) high) << 8) | low);
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32_from_u16(uint16_t high, uint16_t low) {
+ return (((uint32_t)high) << 16) | low;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u16(uint8_t high, uint8_t low) {
+ return (uint16_t)((((uint16_t)high) << 8) | low);
}
TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u32_byte3(uint32_t ui32) { return TU_U32_BYTE3(ui32); }
@@ -121,18 +161,23 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_max16 (uint16_t x, uint16_t y) {
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_max32 (uint32_t x, uint32_t y) { return (x > y) ? x : y; }
//------------- Align -------------//
-TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align(uint32_t value, uint32_t alignment)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align(uint32_t value, uint32_t alignment) {
return value & ((uint32_t) ~(alignment-1));
}
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4 (uint32_t value) { return (value & 0xFFFFFFFCUL); }
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align8 (uint32_t value) { return (value & 0xFFFFFFF8UL); }
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align16 (uint32_t value) { return (value & 0xFFFFFFF0UL); }
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align32 (uint32_t value) { return (value & 0xFFFFFFE0UL); }
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4k (uint32_t value) { return (value & 0xFFFFF000UL); }
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); }
+TU_ATTR_ALWAYS_INLINE static inline bool tu_is_aligned32(uint32_t value) { return (value & 0x1FUL) == 0; }
+TU_ATTR_ALWAYS_INLINE static inline bool tu_is_aligned64(uint64_t value) { return (value & 0x3FUL) == 0; }
+
//------------- Mathematics -------------//
-TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return (v + d -1)/d; }
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return TU_DIV_CEIL(v, d); }
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_round_up(uint32_t v, uint32_t f) { return tu_div_ceil(v, f) * f; }
// log2 of a value is its MSB's position
// TODO use clz TODO remove
@@ -222,11 +267,21 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void* mem, uint16_
#else
// MCU that could access unaligned memory natively
-TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32 (const void* mem) { return *((uint32_t const *) mem); }
-TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16 (const void* mem) { return *((uint16_t const *) mem); }
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_unaligned_read32(const void *mem) {
+ return *((uint32_t const *) mem);
+}
-TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32 (void* mem, uint32_t value ) { *((uint32_t*) mem) = value; }
-TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16 (void* mem, uint16_t value ) { *((uint16_t*) mem) = value; }
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_unaligned_read16(const void *mem) {
+ return *((uint16_t const *) mem);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write32(void *mem, uint32_t value) {
+ *((uint32_t *) mem) = value;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void *mem, uint16_t value) {
+ *((uint16_t *) mem) = value;
+}
#endif
diff --git a/src/common/tusb_compiler.h b/src/common/tusb_compiler.h
index 2c30daf6f..9b33a6f61 100644
--- a/src/common/tusb_compiler.h
+++ b/src/common/tusb_compiler.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -56,11 +56,18 @@
#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define TU_VERIFY_STATIC _Static_assert
#elif defined(__CCRX__)
- #define TU_VERIFY_STATIC(const_expr, _mess) typedef char TU_XSTRCAT(Line, __LINE__)[(const_expr) ? 1 : 0];
+ #define TU_VERIFY_STATIC(const_expr, _mess) typedef char TU_XSTRCAT(_verify_static_, _TU_COUNTER_)[(const_expr) ? 1 : 0];
#else
#define TU_VERIFY_STATIC(const_expr, _mess) enum { TU_XSTRCAT(_verify_static_, _TU_COUNTER_) = 1/(!!(const_expr)) }
#endif
+/* --------------------- Fuzzing types -------------------------------------- */
+#ifdef _FUZZ
+ #define tu_static static __thread
+#else
+ #define tu_static static
+#endif
+
// for declaration of reserved field, make use of _TU_COUNTER_
#define TU_RESERVED TU_XSTRCAT(reserved, _TU_COUNTER_)
@@ -76,9 +83,9 @@
* - ##__VA_ARGS__ is used to deal with 0 paramerter (swallows comma)
*------------------------------------------------------------------*/
#if !defined(__CCRX__)
-#define TU_ARGS_NUM(...) _TU_NARG(_0, ##__VA_ARGS__,_RSEQ_N())
+#define TU_ARGS_NUM(...) _TU_NARG(_0, ##__VA_ARGS__, _RSEQ_N())
#else
-#define TU_ARGS_NUM(...) _TU_NARG(_0, __VA_ARGS__,_RSEQ_N())
+#define TU_ARGS_NUM(...) _TU_NARG(_0, __VA_ARGS__, _RSEQ_N())
#endif
#define _TU_NARG(...) _GET_NTH_ARG(__VA_ARGS__)
@@ -112,6 +119,14 @@
#define _TU_ARGS_APPLY_8(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8) _X(_a1) _s _TU_ARGS_APPLY_7(_X, _s, _a2, _a3, _a4, _a5, _a6, _a7, _a8)
//--------------------------------------------------------------------+
+// Macro for function default arguments
+//--------------------------------------------------------------------+
+#define TU_GET_3RD_ARG(arg1, arg2, arg3, ...) arg3
+
+// function expand with number of arguments
+#define TU_FUNC_OPTIONAL_ARG(func, ...) TU_XSTRCAT(func##_arg, TU_ARGS_NUM(__VA_ARGS__))(__VA_ARGS__)
+
+//--------------------------------------------------------------------+
// Compiler porting with Attribute and Endian
//--------------------------------------------------------------------+
@@ -121,7 +136,10 @@
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
#define TU_ATTR_PACKED __attribute__ ((packed))
#define TU_ATTR_WEAK __attribute__ ((weak))
- #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
+ // #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f)))
+ #ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug
+ #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
+ #endif
#define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used
#define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused
#define TU_ATTR_USED __attribute__ ((used)) // Function/Variable is meant to be used
@@ -131,10 +149,14 @@
#define TU_ATTR_BIT_FIELD_ORDER_BEGIN
#define TU_ATTR_BIT_FIELD_ORDER_END
- #if __has_attribute(__fallthrough__)
- #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough))
- #else
+ #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
@@ -144,8 +166,17 @@
#define TU_BYTE_ORDER TU_BIG_ENDIAN
#endif
- #define TU_BSWAP16(u16) (__builtin_bswap16(u16))
- #define TU_BSWAP32(u32) (__builtin_bswap32(u32))
+ // Unfortunately XC16 doesn't provide builtins for 32bit endian conversion
+ #if defined(__XC16)
+ #define TU_BSWAP16(u16) (__builtin_swap(u16))
+ #define TU_BSWAP32(u32) ((((u32) & 0xff000000) >> 24) | \
+ (((u32) & 0x00ff0000) >> 8) | \
+ (((u32) & 0x0000ff00) << 8) | \
+ (((u32) & 0x000000ff) << 24))
+ #else
+ #define TU_BSWAP16(u16) (__builtin_bswap16(u16))
+ #define TU_BSWAP32(u32) (__builtin_bswap32(u32))
+ #endif
#ifndef __ARMCC_VERSION
// List of obsolete callback function that is renamed and should not be defined.
@@ -158,6 +189,7 @@
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
#define TU_ATTR_PACKED __attribute__ ((packed))
#define TU_ATTR_WEAK __attribute__ ((weak))
+ // #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f)))
#define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
#define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used
#define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused
@@ -185,11 +217,14 @@
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
#define TU_ATTR_PACKED __attribute__ ((packed))
#define TU_ATTR_WEAK __attribute__ ((weak))
- #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
+ // #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f)))
+ #ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug
+ #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
+ #endif
#define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used
#define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused
#define TU_ATTR_USED __attribute__ ((used)) // Function/Variable is meant to be used
- #define TU_ATTR_FALLTHROUGH __attribute__((fallthrough))
+ #define TU_ATTR_FALLTHROUGH do {} while (0) /* fallthrough */
#define TU_ATTR_PACKED_BEGIN
#define TU_ATTR_PACKED_END
@@ -211,6 +246,7 @@
#define TU_ATTR_SECTION(sec_name)
#define TU_ATTR_PACKED
#define TU_ATTR_WEAK
+ // #define TU_ATTR_WEAK_ALIAS(f)
#define TU_ATTR_ALWAYS_INLINE
#define TU_ATTR_DEPRECATED(mess)
#define TU_ATTR_UNUSED
@@ -232,7 +268,7 @@
#define TU_BSWAP16(u16) ((unsigned short)_builtin_revw((unsigned long)u16))
#define TU_BSWAP32(u32) (_builtin_revl(u32))
-#else
+#else
#error "Compiler attribute porting is required"
#endif
diff --git a/src/common/tusb_debug.h b/src/common/tusb_debug.h
index ac5bee6ec..2e9f1d9cd 100644
--- a/src/common/tusb_debug.h
+++ b/src/common/tusb_debug.h
@@ -43,9 +43,10 @@
#if CFG_TUSB_DEBUG
// Enum to String for debugging purposes
-#if CFG_TUSB_DEBUG >= 2
+#if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL || CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
extern char const* const tu_str_speed[];
extern char const* const tu_str_std_request[];
+extern char const* const tu_str_xfer_result[];
#endif
void tu_print_mem(void const *buf, uint32_t count, uint8_t indent);
@@ -57,16 +58,15 @@ void tu_print_mem(void const *buf, uint32_t count, uint8_t indent);
#define tu_printf printf
#endif
-static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize)
-{
+static inline void tu_print_buf(uint8_t const* buf, uint32_t bufsize) {
for(uint32_t i=0; i<bufsize; i++) tu_printf("%02X ", buf[i]);
+ tu_printf("\r\n");
}
// Log with Level
#define TU_LOG(n, ...) TU_XSTRCAT(TU_LOG, n)(__VA_ARGS__)
#define TU_LOG_MEM(n, ...) TU_XSTRCAT3(TU_LOG, n, _MEM)(__VA_ARGS__)
-#define TU_LOG_ARR(n, ...) TU_XSTRCAT3(TU_LOG, n, _ARR)(__VA_ARGS__)
-#define TU_LOG_VAR(n, ...) TU_XSTRCAT3(TU_LOG, n, _VAR)(__VA_ARGS__)
+#define TU_LOG_BUF(n, ...) TU_XSTRCAT3(TU_LOG, n, _BUF)(__VA_ARGS__)
#define TU_LOG_INT(n, ...) TU_XSTRCAT3(TU_LOG, n, _INT)(__VA_ARGS__)
#define TU_LOG_HEX(n, ...) TU_XSTRCAT3(TU_LOG, n, _HEX)(__VA_ARGS__)
#define TU_LOG_LOCATION() tu_printf("%s: %d:\r\n", __PRETTY_FUNCTION__, __LINE__)
@@ -75,17 +75,15 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize)
// Log Level 1: Error
#define TU_LOG1 tu_printf
#define TU_LOG1_MEM tu_print_mem
-#define TU_LOG1_ARR(_x, _n) tu_print_arr((uint8_t const*)(_x), _n)
-#define TU_LOG1_VAR(_x) tu_print_arr((uint8_t const*)(_x), sizeof(*(_x)))
+#define TU_LOG1_BUF(_x, _n) tu_print_buf((uint8_t const*)(_x), _n)
#define TU_LOG1_INT(_x) tu_printf(#_x " = %ld\r\n", (unsigned long) (_x) )
-#define TU_LOG1_HEX(_x) tu_printf(#_x " = %lX\r\n", (unsigned long) (_x) )
+#define TU_LOG1_HEX(_x) tu_printf(#_x " = 0x%lX\r\n", (unsigned long) (_x) )
// Log Level 2: Warn
#if CFG_TUSB_DEBUG >= 2
#define TU_LOG2 TU_LOG1
#define TU_LOG2_MEM TU_LOG1_MEM
- #define TU_LOG2_ARR TU_LOG1_ARR
- #define TU_LOG2_VAR TU_LOG1_VAR
+ #define TU_LOG2_BUF TU_LOG1_BUF
#define TU_LOG2_INT TU_LOG1_INT
#define TU_LOG2_HEX TU_LOG1_HEX
#endif
@@ -94,30 +92,25 @@ static inline void tu_print_arr(uint8_t const* buf, uint32_t bufsize)
#if CFG_TUSB_DEBUG >= 3
#define TU_LOG3 TU_LOG1
#define TU_LOG3_MEM TU_LOG1_MEM
- #define TU_LOG3_ARR TU_LOG1_ARR
- #define TU_LOG3_VAR TU_LOG1_VAR
+ #define TU_LOG3_BUF TU_LOG1_BUF
#define TU_LOG3_INT TU_LOG1_INT
#define TU_LOG3_HEX TU_LOG1_HEX
#endif
-typedef struct
-{
+typedef struct {
uint32_t key;
const char* data;
} tu_lookup_entry_t;
-typedef struct
-{
+typedef struct {
uint16_t count;
tu_lookup_entry_t const* items;
} tu_lookup_table_t;
-static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key)
-{
- static char not_found[11];
+static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) {
+ tu_static char not_found[11];
- for(uint16_t i=0; i<p_table->count; i++)
- {
+ for(uint16_t i=0; i<p_table->count; i++) {
if (p_table->items[i].key == key) return p_table->items[i].data;
}
@@ -132,7 +125,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3
#ifndef TU_LOG
#define TU_LOG(n, ...)
#define TU_LOG_MEM(n, ...)
- #define TU_LOG_VAR(n, ...)
+ #define TU_LOG_BUF(n, ...)
#define TU_LOG_INT(n, ...)
#define TU_LOG_HEX(n, ...)
#define TU_LOG_LOCATION()
@@ -143,14 +136,14 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3
#define TU_LOG0(...)
#define TU_LOG0_MEM(...)
-#define TU_LOG0_VAR(...)
+#define TU_LOG0_BUF(...)
#define TU_LOG0_INT(...)
#define TU_LOG0_HEX(...)
#ifndef TU_LOG1
#define TU_LOG1(...)
#define TU_LOG1_MEM(...)
- #define TU_LOG1_VAR(...)
+ #define TU_LOG1_BUF(...)
#define TU_LOG1_INT(...)
#define TU_LOG1_HEX(...)
#endif
@@ -158,7 +151,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3
#ifndef TU_LOG2
#define TU_LOG2(...)
#define TU_LOG2_MEM(...)
- #define TU_LOG2_VAR(...)
+ #define TU_LOG2_BUF(...)
#define TU_LOG2_INT(...)
#define TU_LOG2_HEX(...)
#endif
@@ -166,7 +159,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3
#ifndef TU_LOG3
#define TU_LOG3(...)
#define TU_LOG3_MEM(...)
- #define TU_LOG3_VAR(...)
+ #define TU_LOG3_BUF(...)
#define TU_LOG3_INT(...)
#define TU_LOG3_HEX(...)
#endif
diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c
index 895b9208b..5f2dcabad 100644
--- a/src/common/tusb_fifo.c
+++ b/src/common/tusb_fifo.c
@@ -28,21 +28,22 @@
#include "osal/osal.h"
#include "tusb_fifo.h"
-// Supress IAR warning
+#define TU_FIFO_DBG 0
+
+// Suppress IAR warning
// Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement
#if defined(__ICCARM__)
#pragma diag_suppress = Pa082
#endif
-// implement mutex lock and unlock
-#if CFG_FIFO_MUTEX
+#if OSAL_MUTEX_REQUIRED
-static inline void _ff_lock(tu_fifo_mutex_t mutex)
+TU_ATTR_ALWAYS_INLINE static inline void _ff_lock(osal_mutex_t mutex)
{
if (mutex) osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER);
}
-static inline void _ff_unlock(tu_fifo_mutex_t mutex)
+TU_ATTR_ALWAYS_INLINE static inline void _ff_unlock(osal_mutex_t mutex)
{
if (mutex) osal_mutex_unlock(mutex);
}
@@ -61,28 +62,27 @@ static inline void _ff_unlock(tu_fifo_mutex_t mutex)
typedef enum
{
TU_FIFO_COPY_INC, ///< Copy from/to an increasing source/destination address - default mode
+#ifdef TUP_MEM_CONST_ADDR
TU_FIFO_COPY_CST_FULL_WORDS, ///< Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardware FIFO
+#endif
} tu_fifo_copy_mode_t;
bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable)
{
- if (depth > 0x8000) return false; // Maximum depth is 2^15 items
+ // Limit index space to 2*depth - this allows for a fast "modulo" calculation
+ // but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable
+ // only if overflow happens once (important for unsupervised DMA applications)
+ if (depth > 0x8000) return false;
_ff_lock(f->mutex_wr);
_ff_lock(f->mutex_rd);
- f->buffer = (uint8_t*) buffer;
- f->depth = depth;
- f->item_size = item_size;
+ f->buffer = (uint8_t*) buffer;
+ f->depth = depth;
+ f->item_size = (uint16_t) (item_size & 0x7FFF);
f->overwritable = overwritable;
-
- // Limit index space to 2*depth - this allows for a fast "modulo" calculation
- // but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable
- // only if overflow happens once (important for unsupervised DMA applications)
- f->max_pointer_idx = (uint16_t) (2*depth - 1);
- f->non_used_index_space = UINT16_MAX - f->max_pointer_idx;
-
- f->rd_idx = f->wr_idx = 0;
+ f->rd_idx = 0;
+ f->wr_idx = 0;
_ff_unlock(f->mutex_wr);
_ff_unlock(f->mutex_rd);
@@ -90,25 +90,23 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si
return true;
}
-// Static functions are intended to work on local variables
-static inline uint16_t _ff_mod(uint16_t idx, uint16_t depth)
-{
- while ( idx >= depth) idx -= depth;
- return idx;
-}
+//--------------------------------------------------------------------+
+// Pull & Push
+//--------------------------------------------------------------------+
+#ifdef TUP_MEM_CONST_ADDR
// Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address
-// Code adapted from dcd_synopsis.c
+// Code adapted from dcd_synopsys.c
// TODO generalize with configurable 1 byte or 4 byte each read
static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t len)
{
- volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf;
+ volatile const uint32_t * reg_rx = (volatile const uint32_t *) app_buf;
// Reading full available 32 bit words from const app address
uint16_t full_words = len >> 2;
while(full_words--)
{
- tu_unaligned_write32(ff_buf, *rx_fifo);
+ tu_unaligned_write32(ff_buf, *reg_rx);
ff_buf += 4;
}
@@ -116,7 +114,7 @@ static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t
uint8_t const bytes_rem = len & 0x03;
if ( bytes_rem )
{
- uint32_t tmp32 = *rx_fifo;
+ uint32_t tmp32 = *reg_rx;
memcpy(ff_buf, &tmp32, bytes_rem);
}
}
@@ -125,49 +123,50 @@ static void _ff_push_const_addr(uint8_t * ff_buf, const void * app_buf, uint16_t
// where all data is written to a constant address in full word copies
static void _ff_pull_const_addr(void * app_buf, const uint8_t * ff_buf, uint16_t len)
{
- volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf;
+ volatile uint32_t * reg_tx = (volatile uint32_t *) app_buf;
- // Pushing full available 32 bit words to const app address
+ // Write full available 32 bit words to const address
uint16_t full_words = len >> 2;
while(full_words--)
{
- *tx_fifo = tu_unaligned_read32(ff_buf);
+ *reg_tx = tu_unaligned_read32(ff_buf);
ff_buf += 4;
}
- // Write the remaining 1-3 bytes into const app address
+ // Write the remaining 1-3 bytes into const address
uint8_t const bytes_rem = len & 0x03;
if ( bytes_rem )
{
uint32_t tmp32 = 0;
memcpy(&tmp32, ff_buf, bytes_rem);
- *tx_fifo = tmp32;
+ *reg_tx = tmp32;
}
}
+#endif
-// send one item to FIFO WITHOUT updating write pointer
+// send one item to fifo WITHOUT updating write pointer
static inline void _ff_push(tu_fifo_t* f, void const * app_buf, uint16_t rel)
{
memcpy(f->buffer + (rel * f->item_size), app_buf, f->item_size);
}
-// send n items to FIFO WITHOUT updating write pointer
-static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode)
+// send n items to fifo WITHOUT updating write pointer
+static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t wr_ptr, tu_fifo_copy_mode_t copy_mode)
{
- uint16_t const nLin = f->depth - rel;
- uint16_t const nWrap = n - nLin;
+ uint16_t const lin_count = f->depth - wr_ptr;
+ uint16_t const wrap_count = n - lin_count;
- uint16_t nLin_bytes = nLin * f->item_size;
- uint16_t nWrap_bytes = nWrap * f->item_size;
+ uint16_t lin_bytes = lin_count * f->item_size;
+ uint16_t wrap_bytes = wrap_count * f->item_size;
// current buffer of fifo
- uint8_t* ff_buf = f->buffer + (rel * f->item_size);
+ uint8_t* ff_buf = f->buffer + (wr_ptr * f->item_size);
switch (copy_mode)
{
case TU_FIFO_COPY_INC:
- if(n <= nLin)
+ if(n <= lin_count)
{
// Linear only
memcpy(ff_buf, app_buf, n*f->item_size);
@@ -177,16 +176,17 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t
// Wrap around
// Write data to linear part of buffer
- memcpy(ff_buf, app_buf, nLin_bytes);
+ memcpy(ff_buf, app_buf, lin_bytes);
// Write data wrapped around
- memcpy(f->buffer, ((uint8_t const*) app_buf) + nLin_bytes, nWrap_bytes);
+ // TU_ASSERT(nWrap_bytes <= f->depth, );
+ memcpy(f->buffer, ((uint8_t const*) app_buf) + lin_bytes, wrap_bytes);
}
break;
-
+#ifdef TUP_MEM_CONST_ADDR
case TU_FIFO_COPY_CST_FULL_WORDS:
// Intended for hardware buffers from which it can be read word by word only
- if(n <= nLin)
+ if(n <= lin_count)
{
// Linear only
_ff_push_const_addr(ff_buf, app_buf, n*f->item_size);
@@ -196,17 +196,18 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t
// Wrap around case
// Write full words to linear part of buffer
- uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC;
+ uint16_t nLin_4n_bytes = lin_bytes & 0xFFFC;
_ff_push_const_addr(ff_buf, app_buf, nLin_4n_bytes);
ff_buf += nLin_4n_bytes;
// There could be odd 1-3 bytes before the wrap-around boundary
- volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf;
- uint8_t rem = nLin_bytes & 0x03;
+ uint8_t rem = lin_bytes & 0x03;
if (rem > 0)
{
- uint8_t remrem = (uint8_t) tu_min16(nWrap_bytes, 4-rem);
- nWrap_bytes -= remrem;
+ volatile const uint32_t * rx_fifo = (volatile const uint32_t *) app_buf;
+
+ uint8_t remrem = (uint8_t) tu_min16(wrap_bytes, 4-rem);
+ wrap_bytes -= remrem;
uint32_t tmp32 = *rx_fifo;
uint8_t * src_u8 = ((uint8_t *) &tmp32);
@@ -224,34 +225,36 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t
}
// Write data wrapped part
- if (nWrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, nWrap_bytes);
+ if (wrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, wrap_bytes);
}
break;
+#endif
+ default: break;
}
}
-// get one item from FIFO WITHOUT updating read pointer
+// get one item from fifo WITHOUT updating read pointer
static inline void _ff_pull(tu_fifo_t* f, void * app_buf, uint16_t rel)
{
memcpy(app_buf, f->buffer + (rel * f->item_size), f->item_size);
}
-// get n items from FIFO WITHOUT updating read pointer
-static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu_fifo_copy_mode_t copy_mode)
+// get n items from fifo WITHOUT updating read pointer
+static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rd_ptr, tu_fifo_copy_mode_t copy_mode)
{
- uint16_t const nLin = f->depth - rel;
- uint16_t const nWrap = n - nLin; // only used if wrapped
+ uint16_t const lin_count = f->depth - rd_ptr;
+ uint16_t const wrap_count = n - lin_count; // only used if wrapped
- uint16_t nLin_bytes = nLin * f->item_size;
- uint16_t nWrap_bytes = nWrap * f->item_size;
+ uint16_t lin_bytes = lin_count * f->item_size;
+ uint16_t wrap_bytes = wrap_count * f->item_size;
// current buffer of fifo
- uint8_t* ff_buf = f->buffer + (rel * f->item_size);
+ uint8_t* ff_buf = f->buffer + (rd_ptr * f->item_size);
switch (copy_mode)
{
case TU_FIFO_COPY_INC:
- if ( n <= nLin )
+ if ( n <= lin_count )
{
// Linear only
memcpy(app_buf, ff_buf, n*f->item_size);
@@ -261,15 +264,15 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu
// Wrap around
// Read data from linear part of buffer
- memcpy(app_buf, ff_buf, nLin_bytes);
+ memcpy(app_buf, ff_buf, lin_bytes);
// Read data wrapped part
- memcpy((uint8_t*) app_buf + nLin_bytes, f->buffer, nWrap_bytes);
+ memcpy((uint8_t*) app_buf + lin_bytes, f->buffer, wrap_bytes);
}
break;
-
+#ifdef TUP_MEM_CONST_ADDR
case TU_FIFO_COPY_CST_FULL_WORDS:
- if ( n <= nLin )
+ if ( n <= lin_count )
{
// Linear only
_ff_pull_const_addr(app_buf, ff_buf, n*f->item_size);
@@ -279,17 +282,18 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu
// Wrap around case
// Read full words from linear part of buffer
- uint16_t nLin_4n_bytes = nLin_bytes & 0xFFFC;
- _ff_pull_const_addr(app_buf, ff_buf, nLin_4n_bytes);
- ff_buf += nLin_4n_bytes;
+ uint16_t lin_4n_bytes = lin_bytes & 0xFFFC;
+ _ff_pull_const_addr(app_buf, ff_buf, lin_4n_bytes);
+ ff_buf += lin_4n_bytes;
// There could be odd 1-3 bytes before the wrap-around boundary
- volatile uint32_t * tx_fifo = (volatile uint32_t *) app_buf;
- uint8_t rem = nLin_bytes & 0x03;
+ uint8_t rem = lin_bytes & 0x03;
if (rem > 0)
{
- uint8_t remrem = (uint8_t) tu_min16(nWrap_bytes, 4-rem);
- nWrap_bytes -= remrem;
+ volatile uint32_t * reg_tx = (volatile uint32_t *) app_buf;
+
+ uint8_t remrem = (uint8_t) tu_min16(wrap_bytes, 4-rem);
+ wrap_bytes -= remrem;
uint32_t tmp32=0;
uint8_t * dst_u8 = (uint8_t *)&tmp32;
@@ -301,7 +305,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu
ff_buf = f->buffer;
while(remrem--) *dst_u8++ = *ff_buf++;
- *tx_fifo = tmp32;
+ *reg_tx = tmp32;
}
else
{
@@ -309,186 +313,240 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu
}
// Read data wrapped part
- if (nWrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, nWrap_bytes);
+ if (wrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, wrap_bytes);
}
break;
-
+#endif
default: break;
}
}
-// Advance an absolute pointer
-static uint16_t advance_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
+//--------------------------------------------------------------------+
+// Helper
+//--------------------------------------------------------------------+
+
+// return only the index difference and as such can be used to determine an overflow i.e overflowable count
+TU_ATTR_ALWAYS_INLINE static inline
+uint16_t _ff_count(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx)
{
- // We limit the index space of p such that a correct wrap around happens
- // Check for a wrap around or if we are in unused index space - This has to be checked first!!
- // We are exploiting the wrap around to the correct index
- if ((p > (uint16_t)(p + offset)) || ((uint16_t)(p + offset) > f->max_pointer_idx))
+ // In case we have non-power of two depth we need a further modification
+ if (wr_idx >= rd_idx)
{
- p = (uint16_t) ((p + offset) + f->non_used_index_space);
- }
- else
+ return (uint16_t) (wr_idx - rd_idx);
+ } else
{
- p += offset;
+ return (uint16_t) (2*depth - (rd_idx - wr_idx));
}
- return p;
}
-// Backward an absolute pointer
-static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
+// return remaining slot in fifo
+TU_ATTR_ALWAYS_INLINE static inline
+uint16_t _ff_remaining(uint16_t depth, uint16_t wr_idx, uint16_t rd_idx)
+{
+ uint16_t const count = _ff_count(depth, wr_idx, rd_idx);
+ return (depth > count) ? (depth - count) : 0;
+}
+
+//--------------------------------------------------------------------+
+// Index Helper
+//--------------------------------------------------------------------+
+
+// Advance an absolute index
+// "absolute" index is only in the range of [0..2*depth)
+static uint16_t advance_index(uint16_t depth, uint16_t idx, uint16_t offset)
{
// We limit the index space of p such that a correct wrap around happens
// Check for a wrap around or if we are in unused index space - This has to be checked first!!
// We are exploiting the wrap around to the correct index
- if ((p < (uint16_t)(p - offset)) || ((uint16_t)(p - offset) > f->max_pointer_idx))
- {
- p = (uint16_t) ((p - offset) - f->non_used_index_space);
- }
- else
+ uint16_t new_idx = (uint16_t) (idx + offset);
+ if ( (idx > new_idx) || (new_idx >= 2*depth) )
{
- p -= offset;
+ uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*depth-1));
+ new_idx = (uint16_t) (new_idx + non_used_index_space);
}
- return p;
-}
-// get relative from absolute pointer
-static uint16_t get_relative_pointer(tu_fifo_t* f, uint16_t p)
-{
- return _ff_mod(p, f->depth);
+ return new_idx;
}
-// Works on local copies of w and r - return only the difference and as such can be used to determine an overflow
-static inline uint16_t _tu_fifo_count(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs)
+#if 0 // not used but
+// Backward an absolute index
+static uint16_t backward_index(uint16_t depth, uint16_t idx, uint16_t offset)
{
- uint16_t cnt = wAbs-rAbs;
-
- // In case we have non-power of two depth we need a further modification
- if (rAbs > wAbs) cnt -= f->non_used_index_space;
+ // We limit the index space of p such that a correct wrap around happens
+ // Check for a wrap around or if we are in unused index space - This has to be checked first!!
+ // We are exploiting the wrap around to the correct index
+ uint16_t new_idx = (uint16_t) (idx - offset);
+ if ( (idx < new_idx) || (new_idx >= 2*depth) )
+ {
+ uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*depth-1));
+ new_idx = (uint16_t) (new_idx - non_used_index_space);
+ }
- return cnt;
+ return new_idx;
}
+#endif
-// Works on local copies of w and r
-static inline bool _tu_fifo_empty(uint16_t wAbs, uint16_t rAbs)
+// index to pointer, simply an modulo with minus.
+TU_ATTR_ALWAYS_INLINE static inline
+uint16_t idx2ptr(uint16_t depth, uint16_t idx)
{
- return wAbs == rAbs;
+ // Only run at most 3 times since index is limit in the range of [0..2*depth)
+ while ( idx >= depth ) idx -= depth;
+ return idx;
}
-// Works on local copies of w and r
-static inline bool _tu_fifo_full(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs)
+// Works on local copies of w
+// When an overwritable fifo is overflowed, rd_idx will be re-index so that it forms
+// an full fifo i.e _ff_count() = depth
+TU_ATTR_ALWAYS_INLINE static inline
+uint16_t _ff_correct_read_index(tu_fifo_t* f, uint16_t wr_idx)
{
- return (_tu_fifo_count(f, wAbs, rAbs) == f->depth);
-}
+ uint16_t rd_idx;
+ if ( wr_idx >= f->depth )
+ {
+ rd_idx = wr_idx - f->depth;
+ }else
+ {
+ rd_idx = wr_idx + f->depth;
+ }
-// Works on local copies of w and r
-// BE AWARE - THIS FUNCTION MIGHT NOT GIVE A CORRECT ANSWERE IN CASE WRITE POINTER "OVERFLOWS"
-// Only one overflow is allowed for this function to work e.g. if depth = 100, you must not
-// write more than 2*depth-1 items in one rush without updating write pointer. Otherwise
-// write pointer wraps and you pointer states are messed up. This can only happen if you
-// use DMAs, write functions do not allow such an error.
-static inline bool _tu_fifo_overflowed(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs)
-{
- return (_tu_fifo_count(f, wAbs, rAbs) > f->depth);
-}
+ f->rd_idx = rd_idx;
-// Works on local copies of w
-// For more details see _tu_fifo_overflow()!
-static inline void _tu_fifo_correct_read_pointer(tu_fifo_t* f, uint16_t wAbs)
-{
- f->rd_idx = backward_pointer(f, wAbs, f->depth);
+ return rd_idx;
}
// Works on local copies of w and r
// Must be protected by mutexes since in case of an overflow read pointer gets modified
-static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wAbs, uint16_t rAbs)
+static bool _tu_fifo_peek(tu_fifo_t* f, void * p_buffer, uint16_t wr_idx, uint16_t rd_idx)
{
- uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs);
+ uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx);
+
+ // nothing to peek
+ if ( cnt == 0 ) return false;
// Check overflow and correct if required
- if (cnt > f->depth)
+ if ( cnt > f->depth )
{
- _tu_fifo_correct_read_pointer(f, wAbs);
+ rd_idx = _ff_correct_read_index(f, wr_idx);
cnt = f->depth;
}
- // Skip beginning of buffer
- if (cnt == 0) return false;
-
- uint16_t rRel = get_relative_pointer(f, rAbs);
+ uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
// Peek data
- _ff_pull(f, p_buffer, rRel);
+ _ff_pull(f, p_buffer, rd_ptr);
return true;
}
// Works on local copies of w and r
// Must be protected by mutexes since in case of an overflow read pointer gets modified
-static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t wAbs, uint16_t rAbs, tu_fifo_copy_mode_t copy_mode)
+static uint16_t _tu_fifo_peek_n(tu_fifo_t* f, void * p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx, tu_fifo_copy_mode_t copy_mode)
{
- uint16_t cnt = _tu_fifo_count(f, wAbs, rAbs);
+ uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx);
+
+ // nothing to peek
+ if ( cnt == 0 ) return 0;
// Check overflow and correct if required
- if (cnt > f->depth)
+ if ( cnt > f->depth )
{
- _tu_fifo_correct_read_pointer(f, wAbs);
- rAbs = f->rd_idx;
+ rd_idx = _ff_correct_read_index(f, wr_idx);
cnt = f->depth;
}
- // Skip beginning of buffer
- if (cnt == 0) return 0;
-
// Check if we can read something at and after offset - if too less is available we read what remains
- if (cnt < n) n = cnt;
+ if ( cnt < n ) n = cnt;
- uint16_t rRel = get_relative_pointer(f, rAbs);
+ uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
// Peek data
- _ff_pull_n(f, p_buffer, n, rRel, copy_mode);
+ _ff_pull_n(f, p_buffer, n, rd_ptr, copy_mode);
return n;
}
-// Works on local copies of w and r
-static inline uint16_t _tu_fifo_remaining(tu_fifo_t* f, uint16_t wAbs, uint16_t rAbs)
-{
- return f->depth - _tu_fifo_count(f, wAbs, rAbs);
-}
-
static uint16_t _tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n, tu_fifo_copy_mode_t copy_mode)
{
if ( n == 0 ) return 0;
_ff_lock(f->mutex_wr);
- uint16_t w = f->wr_idx, r = f->rd_idx;
+ uint16_t wr_idx = f->wr_idx;
+ uint16_t rd_idx = f->rd_idx;
+
uint8_t const* buf8 = (uint8_t const*) data;
- if (!f->overwritable)
+ TU_LOG(TU_FIFO_DBG, "rd = %3u, wr = %3u, count = %3u, remain = %3u, n = %3u: ",
+ rd_idx, wr_idx, _ff_count(f->depth, wr_idx, rd_idx), _ff_remaining(f->depth, wr_idx, rd_idx), n);
+
+ if ( !f->overwritable )
{
- // Not overwritable limit up to full
- n = tu_min16(n, _tu_fifo_remaining(f, w, r));
+ // limit up to full
+ uint16_t const remain = _ff_remaining(f->depth, wr_idx, rd_idx);
+ n = tu_min16(n, remain);
}
- else if (n >= f->depth)
+ else
{
- // Only copy last part
- buf8 = buf8 + (n - f->depth) * f->item_size;
- n = f->depth;
+ // In over-writable mode, fifo_write() is allowed even when fifo is full. In such case,
+ // oldest data in fifo i.e at read pointer data will be overwritten
+ // Note: we can modify read buffer contents but we must not modify the read index itself within a write function!
+ // Since it would end up in a race condition with read functions!
+ if ( n >= f->depth )
+ {
+ // Only copy last part
+ if ( copy_mode == TU_FIFO_COPY_INC )
+ {
+ buf8 += (n - f->depth) * f->item_size;
+ }else
+ {
+ // TODO should read from hw fifo to discard data, however reading an odd number could
+ // accidentally discard data.
+ }
+
+ n = f->depth;
- // We start writing at the read pointer's position since we fill the complete
- // buffer and we do not want to modify the read pointer within a write function!
- // This would end up in a race condition with read functions!
- w = r;
+ // We start writing at the read pointer's position since we fill the whole buffer
+ wr_idx = rd_idx;
+ }
+ else
+ {
+ uint16_t const overflowable_count = _ff_count(f->depth, wr_idx, rd_idx);
+ if (overflowable_count + n >= 2*f->depth)
+ {
+ // Double overflowed
+ // Index is bigger than the allowed range [0,2*depth)
+ // re-position write index to have a full fifo after pushed
+ wr_idx = advance_index(f->depth, rd_idx, f->depth - n);
+
+ // TODO we should also shift out n bytes from read index since we avoid changing rd index !!
+ // However memmove() is expensive due to actual copying + wrapping consideration.
+ // Also race condition could happen anyway if read() is invoke while moving result in corrupted memory
+ // currently deliberately not implemented --> result in incorrect data read back
+ }else
+ {
+ // normal + single overflowed:
+ // Index is in the range of [0,2*depth) and thus detect and recoverable. Recovering is handled in read()
+ // Therefore we just increase write index
+ // we will correct (re-position) read index later on in fifo_read() function
+ }
+ }
}
- uint16_t wRel = get_relative_pointer(f, w);
+ if (n)
+ {
+ uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
- // Write data
- _ff_push_n(f, buf8, n, wRel, copy_mode);
+ TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_ptr = %u", n, wr_ptr);
- // Advance pointer
- f->wr_idx = advance_pointer(f, w, n);
+ // Write data
+ _ff_push_n(f, buf8, n, wr_ptr, copy_mode);
+
+ // Advance index
+ f->wr_idx = advance_index(f->depth, wr_idx, n);
+
+ TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\r\n", f->wr_idx);
+ }
_ff_unlock(f->mutex_wr);
@@ -504,12 +562,16 @@ static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo
n = _tu_fifo_peek_n(f, buffer, n, f->wr_idx, f->rd_idx, copy_mode);
// Advance read pointer
- f->rd_idx = advance_pointer(f, f->rd_idx, n);
+ f->rd_idx = advance_index(f->depth, f->rd_idx, n);
_ff_unlock(f->mutex_rd);
return n;
}
+//--------------------------------------------------------------------+
+// Application API
+//--------------------------------------------------------------------+
+
/******************************************************************************/
/*!
@brief Get number of items in FIFO.
@@ -527,7 +589,7 @@ static uint16_t _tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n, tu_fifo
/******************************************************************************/
uint16_t tu_fifo_count(tu_fifo_t* f)
{
- return tu_min16(_tu_fifo_count(f, f->wr_idx, f->rd_idx), f->depth);
+ return tu_min16(_ff_count(f->depth, f->wr_idx, f->rd_idx), f->depth);
}
/******************************************************************************/
@@ -545,7 +607,7 @@ uint16_t tu_fifo_count(tu_fifo_t* f)
/******************************************************************************/
bool tu_fifo_empty(tu_fifo_t* f)
{
- return _tu_fifo_empty(f->wr_idx, f->rd_idx);
+ return f->wr_idx == f->rd_idx;
}
/******************************************************************************/
@@ -563,7 +625,7 @@ bool tu_fifo_empty(tu_fifo_t* f)
/******************************************************************************/
bool tu_fifo_full(tu_fifo_t* f)
{
- return _tu_fifo_full(f, f->wr_idx, f->rd_idx);
+ return _ff_count(f->depth, f->wr_idx, f->rd_idx) >= f->depth;
}
/******************************************************************************/
@@ -581,7 +643,7 @@ bool tu_fifo_full(tu_fifo_t* f)
/******************************************************************************/
uint16_t tu_fifo_remaining(tu_fifo_t* f)
{
- return _tu_fifo_remaining(f, f->wr_idx, f->rd_idx);
+ return _ff_remaining(f->depth, f->wr_idx, f->rd_idx);
}
/******************************************************************************/
@@ -607,14 +669,14 @@ uint16_t tu_fifo_remaining(tu_fifo_t* f)
/******************************************************************************/
bool tu_fifo_overflowed(tu_fifo_t* f)
{
- return _tu_fifo_overflowed(f, f->wr_idx, f->rd_idx);
+ return _ff_count(f->depth, f->wr_idx, f->rd_idx) > f->depth;
}
// Only use in case tu_fifo_overflow() returned true!
void tu_fifo_correct_read_pointer(tu_fifo_t* f)
{
_ff_lock(f->mutex_rd);
- _tu_fifo_correct_read_pointer(f, f->wr_idx);
+ _ff_correct_read_index(f, f->wr_idx);
_ff_unlock(f->mutex_rd);
}
@@ -643,7 +705,7 @@ bool tu_fifo_read(tu_fifo_t* f, void * buffer)
bool ret = _tu_fifo_peek(f, buffer, f->wr_idx, f->rd_idx);
// Advance pointer
- f->rd_idx = advance_pointer(f, f->rd_idx, ret);
+ f->rd_idx = advance_index(f->depth, f->rd_idx, ret);
_ff_unlock(f->mutex_rd);
return ret;
@@ -670,10 +732,29 @@ uint16_t tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n)
return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_INC);
}
+#ifdef TUP_MEM_CONST_ADDR
+/******************************************************************************/
+/*!
+ @brief This function will read n elements from the array index specified by
+ the read pointer and increment the read index.
+ This function checks for an overflow and corrects read pointer if required.
+ The dest address will not be incremented which is useful for writing to registers.
+
+ @param[in] f
+ Pointer to the FIFO buffer to manipulate
+ @param[in] buffer
+ The pointer to data location
+ @param[in] n
+ Number of element that buffer can afford
+
+ @returns number of items read from the FIFO
+ */
+/******************************************************************************/
uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t* f, void * buffer, uint16_t n)
{
return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_CST_FULL_WORDS);
}
+#endif
/******************************************************************************/
/*!
@@ -682,8 +763,6 @@ uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t* f, void * buffer, uint1
@param[in] f
Pointer to the FIFO buffer to manipulate
- @param[in] offset
- Position to read from in the FIFO buffer with respect to read pointer
@param[in] p_buffer
Pointer to the place holder for data read from the buffer
@@ -742,20 +821,20 @@ bool tu_fifo_write(tu_fifo_t* f, const void * data)
_ff_lock(f->mutex_wr);
bool ret;
- uint16_t const w = f->wr_idx;
+ uint16_t const wr_idx = f->wr_idx;
- if ( _tu_fifo_full(f, w, f->rd_idx) && !f->overwritable )
+ if ( tu_fifo_full(f) && !f->overwritable )
{
ret = false;
}else
{
- uint16_t wRel = get_relative_pointer(f, w);
+ uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
// Write data
- _ff_push(f, data, wRel);
+ _ff_push(f, data, wr_ptr);
// Advance pointer
- f->wr_idx = advance_pointer(f, w, 1);
+ f->wr_idx = advance_index(f->depth, wr_idx, 1);
ret = true;
}
@@ -784,6 +863,7 @@ uint16_t tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n)
return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_INC);
}
+#ifdef TUP_MEM_CONST_ADDR
/******************************************************************************/
/*!
@brief This function will write n elements into the array index specified by
@@ -803,6 +883,7 @@ uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t* f, const void * data,
{
return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_CST_FULL_WORDS);
}
+#endif
/******************************************************************************/
/*!
@@ -817,9 +898,8 @@ bool tu_fifo_clear(tu_fifo_t *f)
_ff_lock(f->mutex_wr);
_ff_lock(f->mutex_rd);
- f->rd_idx = f->wr_idx = 0;
- f->max_pointer_idx = (uint16_t) (2*f->depth-1);
- f->non_used_index_space = UINT16_MAX - f->max_pointer_idx;
+ f->rd_idx = 0;
+ f->wr_idx = 0;
_ff_unlock(f->mutex_wr);
_ff_unlock(f->mutex_rd);
@@ -857,7 +937,7 @@ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable)
As long as the DMA is the only process writing into the FIFO this is safe
to use.
- USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE!
+ USE WITH CARE - WE DO NOT CONDUCT SAFETY CHECKS HERE!
@param[in] f
Pointer to the FIFO buffer to manipulate
@@ -867,7 +947,7 @@ bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable)
/******************************************************************************/
void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n)
{
- f->wr_idx = advance_pointer(f, f->wr_idx, n);
+ f->wr_idx = advance_index(f->depth, f->wr_idx, n);
}
/******************************************************************************/
@@ -878,7 +958,7 @@ void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n)
FIFO. As long as the DMA is the only process reading from the FIFO this is
safe to use.
- USE WITH CARE - WE DO NOT CONDUCT SAFTY CHECKS HERE!
+ USE WITH CARE - WE DO NOT CONDUCT SAFETY CHECKS HERE!
@param[in] f
Pointer to the FIFO buffer to manipulate
@@ -888,7 +968,7 @@ void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n)
/******************************************************************************/
void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n)
{
- f->rd_idx = advance_pointer(f, f->rd_idx, n);
+ f->rd_idx = advance_index(f->depth, f->rd_idx, n);
}
/******************************************************************************/
@@ -909,17 +989,18 @@ void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n)
void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info)
{
// Operate on temporary values in case they change in between
- uint16_t w = f->wr_idx, r = f->rd_idx;
+ uint16_t wr_idx = f->wr_idx;
+ uint16_t rd_idx = f->rd_idx;
- uint16_t cnt = _tu_fifo_count(f, w, r);
+ uint16_t cnt = _ff_count(f->depth, wr_idx, rd_idx);
// Check overflow and correct if required - may happen in case a DMA wrote too fast
if (cnt > f->depth)
{
_ff_lock(f->mutex_rd);
- _tu_fifo_correct_read_pointer(f, w);
+ rd_idx = _ff_correct_read_index(f, wr_idx);
_ff_unlock(f->mutex_rd);
- r = f->rd_idx;
+
cnt = f->depth;
}
@@ -934,22 +1015,25 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info)
}
// Get relative pointers
- w = get_relative_pointer(f, w);
- r = get_relative_pointer(f, r);
+ uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
+ uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
// Copy pointer to buffer to start reading from
- info->ptr_lin = &f->buffer[r];
+ info->ptr_lin = &f->buffer[rd_ptr];
// Check if there is a wrap around necessary
- if (w > r) {
+ if (wr_ptr > rd_ptr)
+ {
// Non wrapping case
info->len_lin = cnt;
+
info->len_wrap = 0;
info->ptr_wrap = NULL;
}
else
{
- info->len_lin = f->depth - r; // Also the case if FIFO was full
+ info->len_lin = f->depth - rd_ptr; // Also the case if FIFO was full
+
info->len_wrap = cnt - info->len_lin;
info->ptr_wrap = f->buffer;
}
@@ -972,36 +1056,37 @@ void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info)
/******************************************************************************/
void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info)
{
- uint16_t w = f->wr_idx, r = f->rd_idx;
- uint16_t free = _tu_fifo_remaining(f, w, r);
+ uint16_t wr_idx = f->wr_idx;
+ uint16_t rd_idx = f->rd_idx;
+ uint16_t remain = _ff_remaining(f->depth, wr_idx, rd_idx);
- if (free == 0)
+ if (remain == 0)
{
- info->len_lin = 0;
+ info->len_lin = 0;
info->len_wrap = 0;
- info->ptr_lin = NULL;
+ info->ptr_lin = NULL;
info->ptr_wrap = NULL;
return;
}
// Get relative pointers
- w = get_relative_pointer(f, w);
- r = get_relative_pointer(f, r);
+ uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
+ uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
// Copy pointer to buffer to start writing to
- info->ptr_lin = &f->buffer[w];
+ info->ptr_lin = &f->buffer[wr_ptr];
- if (w < r)
+ if (wr_ptr < rd_ptr)
{
// Non wrapping case
- info->len_lin = r-w;
+ info->len_lin = rd_ptr-wr_ptr;
info->len_wrap = 0;
info->ptr_wrap = NULL;
}
else
{
- info->len_lin = f->depth - w;
- info->len_wrap = free - info->len_lin; // Remaining length - n already was limited to free or FIFO depth
- info->ptr_wrap = f->buffer; // Always start of buffer
+ info->len_lin = f->depth - wr_ptr;
+ info->len_wrap = remain - info->len_lin; // Remaining length - n already was limited to remain or FIFO depth
+ info->ptr_wrap = f->buffer; // Always start of buffer
}
}
diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h
index 18db289a1..879acda4f 100644
--- a/src/common/tusb_fifo.h
+++ b/src/common/tusb_fifo.h
@@ -32,7 +32,7 @@
extern "C" {
#endif
-// Due to the use of unmasked pointers, this FIFO does not suffer from loosing
+// Due to the use of unmasked pointers, this FIFO does not suffer from losing
// one item slice. Furthermore, write and read operations are completely
// decoupled as write and read functions do not modify a common state. Henceforth,
// writing or reading from the FIFO within an ISR is safe as long as no other
@@ -42,79 +42,129 @@ extern "C" {
// within a certain number (see tu_fifo_overflow()).
#include "common/tusb_common.h"
+#include "osal/osal.h"
// mutex is only needed for RTOS
// for OS None, we don't get preempted
-#define CFG_FIFO_MUTEX (CFG_TUSB_OS != OPT_OS_NONE)
+#define CFG_FIFO_MUTEX OSAL_MUTEX_REQUIRED
-#if CFG_FIFO_MUTEX
-#include "osal/osal.h"
-#define tu_fifo_mutex_t osal_mutex_t
-#endif
-
-typedef struct
-{
- uint8_t* buffer ; ///< buffer pointer
- uint16_t depth ; ///< max items
- uint16_t item_size ; ///< size of each item
- bool overwritable ;
+/* Write/Read index is always in the range of:
+ * 0 .. 2*depth-1
+ * The extra window allow us to determine the fifo state of empty or full with only 2 indices
+ * Following are examples with depth = 3
+ *
+ * - empty: W = R
+ * |
+ * -------------------------
+ * | 0 | RW| 2 | 3 | 4 | 5 |
+ *
+ * - full 1: W > R
+ * |
+ * -------------------------
+ * | 0 | R | 2 | 3 | W | 5 |
+ *
+ * - full 2: W < R
+ * |
+ * -------------------------
+ * | 0 | 1 | W | 3 | 4 | R |
+ *
+ * - Number of items in the fifo can be determined in either cases:
+ * - case W >= R: Count = W - R
+ * - case W < R: Count = 2*depth - (R - W)
+ *
+ * In non-overwritable mode, computed Count (in above 2 cases) is at most equal to depth.
+ * However, in over-writable mode, write index can be repeatedly increased and count can be
+ * temporarily larger than depth (overflowed condition) e.g
+ *
+ * - Overflowed 1: write(3), write(1)
+ * In this case we will adjust Read index when read()/peek() is called so that count = depth.
+ * |
+ * -------------------------
+ * | R | 1 | 2 | 3 | W | 5 |
+ *
+ * - Double Overflowed i.e index is out of allowed range [0,2*depth)
+ * This occurs when we continue to write after 1st overflowed to 2nd overflowed. e.g:
+ * write(3), write(1), write(2)
+ * This must be prevented since it will cause unrecoverable state, in above example
+ * if not handled the fifo will be empty instead of continue-to-be full. Since we must not modify
+ * read index in write() function, which cause race condition. We will re-position write index so that
+ * after data is written it is a full fifo i.e W = depth - R
+ *
+ * re-position W = 1 before write(2)
+ * Note: we should also move data from mem[3] to read index as well, but deliberately skipped here
+ * since it is an expensive operation !!!
+ * |
+ * -------------------------
+ * | R | W | 2 | 3 | 4 | 5 |
+ *
+ * perform write(2), result is still a full fifo.
+ *
+ * |
+ * -------------------------
+ * | R | 1 | 2 | W | 4 | 5 |
+ */
+typedef struct {
+ uint8_t* buffer ; // buffer pointer
+ uint16_t depth ; // max items
- uint16_t non_used_index_space ; ///< required for non-power-of-two buffer length
- uint16_t max_pointer_idx ; ///< maximum absolute pointer index
+ struct TU_ATTR_PACKED {
+ uint16_t item_size : 15; // size of each item
+ bool overwritable : 1 ; // ovwerwritable when full
+ };
- volatile uint16_t wr_idx ; ///< write pointer
- volatile uint16_t rd_idx ; ///< read pointer
+ volatile uint16_t wr_idx ; // write index
+ volatile uint16_t rd_idx ; // read index
-#if CFG_FIFO_MUTEX
- tu_fifo_mutex_t mutex_wr;
- tu_fifo_mutex_t mutex_rd;
+#if OSAL_MUTEX_REQUIRED
+ osal_mutex_t mutex_wr;
+ osal_mutex_t mutex_rd;
#endif
} tu_fifo_t;
-typedef struct
-{
+typedef struct {
uint16_t len_lin ; ///< linear length in item size
uint16_t len_wrap ; ///< wrapped length in item size
void * ptr_lin ; ///< linear part start pointer
void * ptr_wrap ; ///< wrapped part start pointer
} tu_fifo_buffer_info_t;
-#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \
-{ \
+#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable){\
.buffer = _buffer, \
.depth = _depth, \
.item_size = sizeof(_type), \
.overwritable = _overwritable, \
- .non_used_index_space = UINT16_MAX - (2*(_depth)-1), \
- .max_pointer_idx = 2*(_depth)-1, \
}
#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \
uint8_t _name##_buf[_depth*sizeof(_type)]; \
tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _type, _overwritable)
-
bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable);
bool tu_fifo_clear(tu_fifo_t *f);
bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable);
-#if CFG_FIFO_MUTEX
+#if OSAL_MUTEX_REQUIRED
TU_ATTR_ALWAYS_INLINE static inline
-void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t write_mutex_hdl, tu_fifo_mutex_t read_mutex_hdl)
-{
- f->mutex_wr = write_mutex_hdl;
- f->mutex_rd = read_mutex_hdl;
+void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_mutex) {
+ f->mutex_wr = wr_mutex;
+ f->mutex_rd = rd_mutex;
}
+#else
+#define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex)
#endif
-bool tu_fifo_write (tu_fifo_t* f, void const * p_data);
-uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t n);
+bool tu_fifo_write (tu_fifo_t* f, void const * data);
+uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * data, uint16_t n);
+#ifdef TUP_MEM_CONST_ADDR
uint16_t tu_fifo_write_n_const_addr_full_words (tu_fifo_t* f, const void * data, uint16_t n);
+#endif
-bool tu_fifo_read (tu_fifo_t* f, void * p_buffer);
-uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t n);
+bool tu_fifo_read (tu_fifo_t* f, void * buffer);
+uint16_t tu_fifo_read_n (tu_fifo_t* f, void * buffer, uint16_t n);
+#ifdef TUP_MEM_CONST_ADDR
uint16_t tu_fifo_read_n_const_addr_full_words (tu_fifo_t* f, void * buffer, uint16_t n);
+#endif
bool tu_fifo_peek (tu_fifo_t* f, void * p_buffer);
uint16_t tu_fifo_peek_n (tu_fifo_t* f, void * p_buffer, uint16_t n);
@@ -127,13 +177,12 @@ bool tu_fifo_overflowed (tu_fifo_t* f);
void tu_fifo_correct_read_pointer (tu_fifo_t* f);
TU_ATTR_ALWAYS_INLINE static inline
-uint16_t tu_fifo_depth(tu_fifo_t* f)
-{
+uint16_t tu_fifo_depth(tu_fifo_t* f) {
return f->depth;
}
// Pointer modifications intended to be used in combinations with DMAs.
-// USE WITH CARE - NO SAFTY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED!
+// USE WITH CARE - NO SAFETY CHECKS CONDUCTED HERE! NOT MUTEX PROTECTED!
void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n);
void tu_fifo_advance_read_pointer (tu_fifo_t *f, uint16_t n);
@@ -143,7 +192,6 @@ void tu_fifo_advance_read_pointer (tu_fifo_t *f, uint16_t n);
void tu_fifo_get_read_info (tu_fifo_t *f, tu_fifo_buffer_info_t *info);
void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
-
#ifdef __cplusplus
}
#endif
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index 86c68baf8..a0175d664 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -28,16 +28,22 @@
#define TUSB_MCU_H_
//--------------------------------------------------------------------+
-// Port Specific
-// TUP stand for TinyUSB Port (can be renamed)
+// Port/Platform Specific
+// TUP stand for TinyUSB Port/Platform (can be renamed)
//--------------------------------------------------------------------+
//------------- Unaligned Memory Access -------------//
-// ARMv7+ (M3-M7, M23-M33) can access unaligned memory
-#if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7))
- #define TUP_ARCH_STRICT_ALIGN 0
+#ifdef __ARM_ARCH
+ // ARM Architecture set __ARM_FEATURE_UNALIGNED to 1 for mcu supports unaligned access
+ #if defined(__ARM_FEATURE_UNALIGNED) && __ARM_FEATURE_UNALIGNED == 1
+ #define TUP_ARCH_STRICT_ALIGN 0
+ #else
+ #define TUP_ARCH_STRICT_ALIGN 1
+ #endif
#else
+ // TODO default to strict align for others
+ // Should investigate other architecture such as risv, xtensa, mips for optimal setting
#define TUP_ARCH_STRICT_ALIGN 1
#endif
@@ -48,87 +54,139 @@
* - RHPORT_HIGHSPEED: support highspeed with on-chip PHY
*/
-//------------- NXP -------------//
+//--------------------------------------------------------------------+
+// NXP
+//--------------------------------------------------------------------+
#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX)
+ #define TUP_USBIP_IP3511
#define TUP_DCD_ENDPOINT_MAX 5
#elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX)
#define TUP_DCD_ENDPOINT_MAX 16
#define TUP_USBIP_OHCI
-
-#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
- // TODO USB0 has 6, USB1 has 4
- #define TUP_USBIP_CHIPIDEA_HS
- #define TUP_USBIP_EHCI
-
- #define TUP_DCD_ENDPOINT_MAX 6
- #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 FS
+ #define TUP_OHCI_RHPORTS 2
#elif TU_CHECK_MCU(OPT_MCU_LPC51UXX)
+ #define TUP_USBIP_IP3511
#define TUP_DCD_ENDPOINT_MAX 5
-#elif TU_CHECK_MCU(OPT_MCU_LPC54XXX)
+#elif TU_CHECK_MCU(OPT_MCU_LPC54)
// TODO USB0 has 5, USB1 has 6
+ #define TUP_USBIP_IP3511
#define TUP_DCD_ENDPOINT_MAX 6
-#elif TU_CHECK_MCU(OPT_MCU_LPC55XX)
+#elif TU_CHECK_MCU(OPT_MCU_LPC55)
// TODO USB0 has 5, USB1 has 6
+ #define TUP_USBIP_IP3511
#define TUP_DCD_ENDPOINT_MAX 6
-#elif TU_CHECK_MCU(OPT_MCU_MIMXRT)
+#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
+ // USB0 has 6 with HS PHY, USB1 has 4 only FS
+ #define TUP_USBIP_CHIPIDEA_HS
+ #define TUP_USBIP_EHCI
+
+ #define TUP_DCD_ENDPOINT_MAX 6
+ #define TUP_RHPORT_HIGHSPEED 1
+
+#elif TU_CHECK_MCU(OPT_MCU_MCXN9)
+ // USB0 is chipidea FS
+ #define TUP_USBIP_CHIPIDEA_FS
+ #define TUP_USBIP_CHIPIDEA_FS_MCX
+
+ // USB1 is chipidea HS
#define TUP_USBIP_CHIPIDEA_HS
#define TUP_USBIP_EHCI
#define TUP_DCD_ENDPOINT_MAX 8
- #define TUP_RHPORT_HIGHSPEED 1 // Port0 HS, Port1 HS
+ #define TUP_RHPORT_HIGHSPEED 1
-#elif TU_CHECK_MCU(OPT_MCU_MKL25ZXX, OPT_MCU_K32L2BXX)
+#elif TU_CHECK_MCU(OPT_MCU_MCXA15)
+ // USB0 is chipidea FS
+ #define TUP_USBIP_CHIPIDEA_FS
+ #define TUP_USBIP_CHIPIDEA_FS_MCX
+
+ #define TUP_DCD_ENDPOINT_MAX 16
+
+#elif TU_CHECK_MCU(OPT_MCU_MIMXRT1XXX)
+ #include "fsl_device_registers.h"
+
+ #define TUP_USBIP_CHIPIDEA_HS
+ #define TUP_USBIP_EHCI
+
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_RHPORT_HIGHSPEED 1
+
+ #if __CORTEX_M == 7
+ #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT 1
+ #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT 1
+ #define CFG_TUSB_MEM_DCACHE_LINE_SIZE 32
+ #endif
+
+#elif TU_CHECK_MCU(OPT_MCU_KINETIS_KL, OPT_MCU_KINETIS_K32L, OPT_MCU_KINETIS_K)
+ #define TUP_USBIP_CHIPIDEA_FS
+ #define TUP_USBIP_CHIPIDEA_FS_KINETIS
#define TUP_DCD_ENDPOINT_MAX 16
#elif TU_CHECK_MCU(OPT_MCU_MM32F327X)
#define TUP_DCD_ENDPOINT_MAX 16
-//------------- Nordic -------------//
+//--------------------------------------------------------------------+
+// Nordic
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_NRF5X)
// 8 CBI + 1 ISO
#define TUP_DCD_ENDPOINT_MAX 9
-//------------- Microchip -------------//
+//--------------------------------------------------------------------+
+// Microchip
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAMD51, OPT_MCU_SAME5X) || \
TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAML21, OPT_MCU_SAML22)
#define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_SAMG)
#define TUP_DCD_ENDPOINT_MAX 6
- #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER
+ #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
#elif TU_CHECK_MCU(OPT_MCU_SAMX7X)
#define TUP_DCD_ENDPOINT_MAX 10
#define TUP_RHPORT_HIGHSPEED 1
- #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER
+ #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
#elif TU_CHECK_MCU(OPT_MCU_PIC32MZ)
#define TUP_DCD_ENDPOINT_MAX 8
- #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER
+ #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
#elif TU_CHECK_MCU(OPT_MCU_PIC32MX, OPT_MCU_PIC32MM, OPT_MCU_PIC32MK) || \
TU_CHECK_MCU(OPT_MCU_PIC24, OPT_MCU_DSPIC33)
#define TUP_DCD_ENDPOINT_MAX 16
- #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER
+ #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
-//------------- ST -------------//
+//--------------------------------------------------------------------+
+// ST
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_STM32F0)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
#define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_STM32F1)
+ // - F102, F103 use fsdev
+ // - F105, F107 use dwc2
#if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \
defined (STM32F107xB) || defined (STM32F107xC)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
+ #define CFG_TUH_DWC2_DMA_ENABLE_DEFAULT 0
#define TUP_DCD_ENDPOINT_MAX 4
- #else
+ #elif defined(STM32F102x6) || defined(STM32F102xB) || \
+ defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
#define TUP_DCD_ENDPOINT_MAX 8
+ #else
+ #error "Unsupported STM32F1 mcu"
#endif
#elif TU_CHECK_MCU(OPT_MCU_STM32F2)
@@ -139,6 +197,8 @@
#define TUP_DCD_ENDPOINT_MAX 6
#elif TU_CHECK_MCU(OPT_MCU_STM32F3)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
#define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_STM32F4)
@@ -166,13 +226,39 @@
#define TUP_DCD_ENDPOINT_MAX 9
+#elif TU_CHECK_MCU(OPT_MCU_STM32H5)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define TUP_DCD_ENDPOINT_MAX 8
+
#elif TU_CHECK_MCU(OPT_MCU_STM32G4)
+ // Device controller
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+
+ // TypeC controller
+ #define TUP_USBIP_TYPEC_STM32
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_TYPEC_RHPORTS_NUM 1
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32G0)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32C0)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
#define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_STM32L0, OPT_MCU_STM32L1)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
#define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_STM32L4)
+ // - L4x2, L4x3 use fsdev
+ // - L4x4, L4x6, L4x7, L4x9 use dwc2
#if defined (STM32L475xx) || defined (STM32L476xx) || \
defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \
defined (STM32L4A6xx) || defined (STM32L4P5xx) || defined (STM32L4Q5xx) || \
@@ -182,36 +268,88 @@
#define TUP_USBIP_DWC2_STM32
#define TUP_DCD_ENDPOINT_MAX 6
- #else
+ #elif defined(STM32L412xx) || defined(STM32L422xx) || defined(STM32L432xx) || defined(STM32L433xx) || \
+ defined(STM32L442xx) || defined(STM32L443xx) || defined(STM32L452xx) || defined(STM32L462xx)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
#define TUP_DCD_ENDPOINT_MAX 8
+ #else
+ #error "Unsupported STM32L4 mcu"
#endif
#elif TU_CHECK_MCU(OPT_MCU_STM32WB)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
#define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_STM32U5)
+ #if defined (STM32U535xx) || defined (STM32U545xx)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+ #else
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_STM32
+
+ // U59x/5Ax/5Fx/5Gx are highspeed with built-in HS PHY
+ #if defined(STM32U595xx) || defined(STM32U599xx) || defined(STM32U5A5xx) || defined(STM32U5A9xx) || \
+ defined(STM32U5F7xx) || defined(STM32U5F9xx) || defined(STM32U5G7xx) || defined(STM32U5G9xx)
+ #define TUP_DCD_ENDPOINT_MAX 9
+ #define TUP_RHPORT_HIGHSPEED 1
+ #else
+ #define TUP_DCD_ENDPOINT_MAX 6
+ #endif
+ #endif
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32L5)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32U0)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32H7RS)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
- #define TUP_DCD_ENDPOINT_MAX 6
-//------------- Sony -------------//
+ // FS has 6, HS has 9
+ #define TUP_DCD_ENDPOINT_MAX 9
+
+ // MCU with on-chip HS Phy
+ #define TUP_RHPORT_HIGHSPEED 1
+
+//--------------------------------------------------------------------+
+// Sony
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_CXD56)
#define TUP_DCD_ENDPOINT_MAX 7
#define TUP_RHPORT_HIGHSPEED 1
- #define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER
+ #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
-//------------- TI -------------//
+//--------------------------------------------------------------------+
+// TI
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_MSP430x5xx)
#define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
+ #define TUP_USBIP_MUSB
+ #define TUP_USBIP_MUSB_TI
#define TUP_DCD_ENDPOINT_MAX 8
-//------------- ValentyUSB -------------//
+//--------------------------------------------------------------------+
+// ValentyUSB (Litex)
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_VALENTYUSB_EPTRI)
#define TUP_DCD_ENDPOINT_MAX 16
-//------------- Nuvoton -------------//
+//--------------------------------------------------------------------+
+// Nuvoton
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_NUC121, OPT_MCU_NUC126)
#define TUP_DCD_ENDPOINT_MAX 8
@@ -222,66 +360,205 @@
#define TUP_DCD_ENDPOINT_MAX 12
#define TUP_RHPORT_HIGHSPEED 1
-//------------- Espressif -------------//
+//--------------------------------------------------------------------+
+// Espressif
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
#define TUP_USBIP_DWC2
- #define TUP_DCD_ENDPOINT_MAX 6
+ #define TUP_USBIP_DWC2_ESP32
+ #define TUP_DCD_ENDPOINT_MAX 7 // only 5 TX FIFO for endpoint IN
+ #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
+
+ // Disable slave if DMA is enabled
+ #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
+ #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE
+
+#elif TU_CHECK_MCU(OPT_MCU_ESP32P4)
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_ESP32
+ #define TUP_RHPORT_HIGHSPEED 1 // port0 FS, port1 HS
+ #define TUP_DCD_ENDPOINT_MAX 16 // FS 7 ep, HS 16 ep
+
+ #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
+
+ // Disable slave if DMA is enabled
+ #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
+ #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE
-//------------- Dialog -------------//
+ // Enable dcache if DMA is enabled
+ #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
+ #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
+ #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 64
+
+#elif TU_CHECK_MCU(OPT_MCU_ESP32, OPT_MCU_ESP32C2, OPT_MCU_ESP32C3, OPT_MCU_ESP32C6, OPT_MCU_ESP32H2)
+ #if (CFG_TUD_ENABLED || !(defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421))
+ #error "MCUs are only supported with CFG_TUH_MAX3421 enabled"
+ #endif
+
+ #define TUP_DCD_ENDPOINT_MAX 0
+ #define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
+
+//--------------------------------------------------------------------+
+// Dialog
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_DA1469X)
#define TUP_DCD_ENDPOINT_MAX 4
-//------------- Raspberry Pi -------------//
+//--------------------------------------------------------------------+
+// Raspberry Pi
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_RP2040)
+ #define TUP_DCD_EDPT_ISO_ALLOC
#define TUP_DCD_ENDPOINT_MAX 16
#define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb")))
-//------------- Silabs -------------//
+//--------------------------------------------------------------------+
+// Silabs
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_EFM32GG)
#define TUP_USBIP_DWC2
#define TUP_DCD_ENDPOINT_MAX 7
-//------------- Renesas -------------//
-#elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
+//--------------------------------------------------------------------+
+// Renesas
+//--------------------------------------------------------------------+
+#elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N, OPT_MCU_RAXXX)
+ #define TUP_USBIP_RUSB2
#define TUP_DCD_ENDPOINT_MAX 10
-//------------- GigaDevice -------------//
+//--------------------------------------------------------------------+
+// GigaDevice
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_GD32VF103)
#define TUP_USBIP_DWC2
#define TUP_DCD_ENDPOINT_MAX 4
-//------------- Broadcom -------------//
+//--------------------------------------------------------------------+
+// Broadcom
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837)
#define TUP_USBIP_DWC2
#define TUP_DCD_ENDPOINT_MAX 8
#define TUP_RHPORT_HIGHSPEED 1
-//------------- Broadcom -------------//
+//--------------------------------------------------------------------+
+// Infineon
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_XMC4000)
#define TUP_USBIP_DWC2
#define TUP_DCD_ENDPOINT_MAX 8
-//------------- BridgeTek -------------//
+//--------------------------------------------------------------------+
+// BridgeTek
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_FT90X)
#define TUP_DCD_ENDPOINT_MAX 8
#define TUP_RHPORT_HIGHSPEED 1
+ #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
#elif TU_CHECK_MCU(OPT_MCU_FT93X)
#define TUP_DCD_ENDPOINT_MAX 16
#define TUP_RHPORT_HIGHSPEED 1
+ #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
-//------------ Allwinner -------------//
+//--------------------------------------------------------------------+
+// Allwinner
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_F1C100S)
#define TUP_DCD_ENDPOINT_MAX 4
+//--------------------------------------------------------------------+
+// WCH
+//--------------------------------------------------------------------+
+#elif TU_CHECK_MCU(OPT_MCU_CH32F20X)
+ #define TUP_USBIP_WCH_USBHS
+ #define TUP_USBIP_WCH_USBFS
+
+ #if !defined(CFG_TUD_WCH_USBIP_USBFS)
+ #define CFG_TUD_WCH_USBIP_USBFS 0
+ #endif
+
+ #if !defined(CFG_TUD_WCH_USBIP_USBHS)
+ #define CFG_TUD_WCH_USBIP_USBHS (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1)
+ #endif
+
+ #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS
+ #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8)
+
+#elif TU_CHECK_MCU(OPT_MCU_CH32V103)
+ #define TUP_USBIP_WCH_USBFS
+
+ #if !defined(CFG_TUD_WCH_USBIP_USBFS)
+ #define CFG_TUD_WCH_USBIP_USBFS 1
+ #endif
+
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_CH32V20X)
+ // v20x support both FSDEV (USBD) and USBFS, default to FSDEV
+ #define TUP_USBIP_WCH_USBFS
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_CH32
+
+ #if !defined(CFG_TUD_WCH_USBIP_USBFS)
+ #define CFG_TUD_WCH_USBIP_USBFS 0
+ #endif
+
+ #if !defined(CFG_TUD_WCH_USBIP_FSDEV)
+ #define CFG_TUD_WCH_USBIP_FSDEV (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1)
+ #endif
+
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_CH32V307)
+ // v307 support both FS and HS, default to HS
+ #define TUP_USBIP_WCH_USBHS
+ #define TUP_USBIP_WCH_USBFS
+
+ #if !defined(CFG_TUD_WCH_USBIP_USBFS)
+ #define CFG_TUD_WCH_USBIP_USBFS 0
+ #endif
+
+ #if !defined(CFG_TUD_WCH_USBIP_USBHS)
+ #define CFG_TUD_WCH_USBIP_USBHS (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1)
+ #endif
+
+ #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS
+ #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8)
+
+//--------------------------------------------------------------------+
+// Analog Devices
+//--------------------------------------------------------------------+
+#elif TU_CHECK_MCU(OPT_MCU_MAX32650, OPT_MCU_MAX32666, OPT_MCU_MAX32690, OPT_MCU_MAX78002)
+ #define TUP_USBIP_MUSB
+ #define TUP_USBIP_MUSB_ADI
+ #define TUP_DCD_ENDPOINT_MAX 12
+ #define TUP_RHPORT_HIGHSPEED 1
+ #define TUD_ENDPOINT_ONE_DIRECTION_ONLY
+
+#endif
+
+//--------------------------------------------------------------------+
+// External USB controller
+//--------------------------------------------------------------------+
+
+#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
+ #ifndef CFG_TUH_MAX3421_ENDPOINT_TOTAL
+ #define CFG_TUH_MAX3421_ENDPOINT_TOTAL (8 + 4*(CFG_TUH_DEVICE_MAX-1))
+ #endif
#endif
+
//--------------------------------------------------------------------+
// Default Values
//--------------------------------------------------------------------+
-#ifndef TUP_DCD_ENDPOINT_MAX
+#ifndef TUP_MCU_MULTIPLE_CORE
+#define TUP_MCU_MULTIPLE_CORE 0
+#endif
+
+#if !defined(TUP_DCD_ENDPOINT_MAX) && defined(CFG_TUD_ENABLED) && CFG_TUD_ENABLED
#warning "TUP_DCD_ENDPOINT_MAX is not defined for this MCU, default to 8"
#define TUP_DCD_ENDPOINT_MAX 8
#endif
@@ -296,4 +573,13 @@
#define TU_ATTR_FAST_FUNC
#endif
+// USBIP that support ISO alloc & activate API
+#if defined(TUP_USBIP_DWC2) || defined(TUP_USBIP_FSDEV) || defined(TUP_USBIP_MUSB)
+ #define TUP_DCD_EDPT_ISO_ALLOC
+#endif
+
+#if defined(TUP_USBIP_DWC2) // && CFG_TUD_DWC2_DMA_ENABLE == 0
+ #define TUP_MEM_CONST_ADDR
+#endif
+
#endif
diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h
index b34506f65..c71775abb 100644
--- a/src/common/tusb_private.h
+++ b/src/common/tusb_private.h
@@ -24,23 +24,46 @@
* This file is part of the TinyUSB stack.
*/
+#ifndef TUSB_PRIVATE_H_
+#define TUSB_PRIVATE_H_
-#ifndef _TUSB_PRIVATE_H_
-#define _TUSB_PRIVATE_H_
+// Internal Helper used by Host and Device Stack
#ifdef __cplusplus
extern "C" {
#endif
-typedef struct TU_ATTR_PACKED
-{
+#define TUP_USBIP_CONTROLLER_NUM 2
+extern tusb_role_t _tusb_rhport_role[TUP_USBIP_CONTROLLER_NUM];
+
+//--------------------------------------------------------------------+
+// Endpoint
+//--------------------------------------------------------------------+
+
+typedef struct TU_ATTR_PACKED {
volatile uint8_t busy : 1;
volatile uint8_t stalled : 1;
volatile uint8_t claimed : 1;
}tu_edpt_state_t;
+typedef struct {
+ struct TU_ATTR_PACKED {
+ uint8_t is_host : 1; // 1: host, 0: device
+ uint8_t is_mps512 : 1; // 1: 512, 0: 64 since stream is used for Bulk only
+ };
+ uint8_t ep_addr;
+ uint16_t ep_bufsize;
+
+ uint8_t* ep_buf; // TODO xfer_fifo can skip this buffer
+ tu_fifo_t ff;
+
+ // mutex: read if rx, otherwise write
+ OSAL_MUTEX_DEF(ff_mutexdef);
+
+}tu_edpt_stream_t;
+
//--------------------------------------------------------------------+
-// Internal Helper used by Host and Device Stack
+// Endpoint
//--------------------------------------------------------------------+
// Check if endpoint descriptor is valid per USB specs
@@ -58,8 +81,92 @@ bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex);
// Release an endpoint with provided mutex
bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex);
+//--------------------------------------------------------------------+
+// Endpoint Stream
+//--------------------------------------------------------------------+
+
+// Init an endpoint stream
+bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable,
+ void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize);
+
+// Deinit an endpoint stream
+bool tu_edpt_stream_deinit(tu_edpt_stream_t* s);
+
+// Open an stream for an endpoint
+TU_ATTR_ALWAYS_INLINE static inline
+void tu_edpt_stream_open(tu_edpt_stream_t* s, tusb_desc_endpoint_t const *desc_ep) {
+ tu_fifo_clear(&s->ff);
+ s->ep_addr = desc_ep->bEndpointAddress;
+ s->is_mps512 = (tu_edpt_packet_size(desc_ep) == 512) ? 1 : 0;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline
+void tu_edpt_stream_close(tu_edpt_stream_t* s) {
+ s->ep_addr = 0;
+}
+
+// Clear fifo
+TU_ATTR_ALWAYS_INLINE static inline
+bool tu_edpt_stream_clear(tu_edpt_stream_t* s) {
+ return tu_fifo_clear(&s->ff);
+}
+
+//--------------------------------------------------------------------+
+// Stream Write
+//--------------------------------------------------------------------+
+
+// Write to stream
+uint32_t tu_edpt_stream_write(uint8_t hwid, tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize);
+
+// Start an usb transfer if endpoint is not busy
+uint32_t tu_edpt_stream_write_xfer(uint8_t hwid, tu_edpt_stream_t* s);
+
+// Start an zero-length packet if needed
+bool tu_edpt_stream_write_zlp_if_needed(uint8_t hwid, tu_edpt_stream_t* s, uint32_t last_xferred_bytes);
+
+// Get the number of bytes available for writing to FIFO
+// Note: if no fifo, return endpoint size if not busy, 0 otherwise
+uint32_t tu_edpt_stream_write_available(uint8_t hwid, tu_edpt_stream_t* s);
+
+//--------------------------------------------------------------------+
+// Stream Read
+//--------------------------------------------------------------------+
+
+// Read from stream
+uint32_t tu_edpt_stream_read(uint8_t hwid, tu_edpt_stream_t* s, void* buffer, uint32_t bufsize);
+
+// Start an usb transfer if endpoint is not busy
+uint32_t tu_edpt_stream_read_xfer(uint8_t hwid, tu_edpt_stream_t* s);
+
+// Must be called in the transfer complete callback
+TU_ATTR_ALWAYS_INLINE static inline
+void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) {
+ if (tu_fifo_depth(&s->ff)) {
+ tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t) xferred_bytes);
+ }
+}
+
+// Same as tu_edpt_stream_read_xfer_complete but skip the first n bytes
+TU_ATTR_ALWAYS_INLINE static inline
+void tu_edpt_stream_read_xfer_complete_offset(tu_edpt_stream_t* s, uint32_t xferred_bytes, uint32_t skip_offset) {
+ if (tu_fifo_depth(&s->ff) && (skip_offset < xferred_bytes)) {
+ tu_fifo_write_n(&s->ff, s->ep_buf + skip_offset, (uint16_t) (xferred_bytes - skip_offset));
+ }
+}
+
+// Get the number of bytes available for reading
+TU_ATTR_ALWAYS_INLINE static inline
+uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t* s) {
+ return (uint32_t) tu_fifo_count(&s->ff);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline
+bool tu_edpt_stream_peek(tu_edpt_stream_t* s, uint8_t* ch) {
+ return tu_fifo_peek(&s->ff, ch);
+}
+
#ifdef __cplusplus
}
#endif
-#endif /* _TUSB_PRIVATE_H_ */
+#endif
diff --git a/src/common/tusb_timeout.h b/src/common/tusb_timeout.h
deleted file mode 100644
index ce53955f0..000000000
--- a/src/common/tusb_timeout.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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.
- */
-
-/** \ingroup Group_Common Common Files
- * \defgroup Group_TimeoutTimer timeout timer
- * @{ */
-
-#ifndef _TUSB_TIMEOUT_H_
-#define _TUSB_TIMEOUT_H_
-
-#include <stdbool.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct {
- uint32_t start;
- uint32_t interval;
-}tu_timeout_t;
-
-#if 0
-
-extern uint32_t tusb_hal_millis(void);
-
-static inline void tu_timeout_set(tu_timeout_t* tt, uint32_t msec)
-{
- tt->interval = msec;
- tt->start = tusb_hal_millis();
-}
-
-static inline bool tu_timeout_expired(tu_timeout_t* tt)
-{
- return ( tusb_hal_millis() - tt->start ) >= tt->interval;
-}
-
-// For used with periodic event to prevent drift
-static inline void tu_timeout_reset(tu_timeout_t* tt)
-{
- tt->start += tt->interval;
-}
-
-static inline void tu_timeout_restart(tu_timeout_t* tt)
-{
- tt->start = tusb_hal_millis();
-}
-
-#endif
-
-#ifdef __cplusplus
- }
-#endif
-
-#endif /* _TUSB_TIMEOUT_H_ */
-
-/** @} */
diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h
index e11f08dd1..9e4d9380c 100644
--- a/src/common/tusb_types.h
+++ b/src/common/tusb_types.h
@@ -24,12 +24,8 @@
* This file is part of the TinyUSB stack.
*/
-/** \ingroup group_usb_definitions
- * \defgroup USBDef_Type USB Types
- * @{ */
-
-#ifndef _TUSB_TYPES_H_
-#define _TUSB_TYPES_H_
+#ifndef TUSB_TYPES_H_
+#define TUSB_TYPES_H_
#include <stdbool.h>
#include <stdint.h>
@@ -39,39 +35,87 @@
extern "C" {
#endif
+//------------- Device DCache declaration -------------//
+#define TUD_EPBUF_DCACHE_SIZE(_size) (CFG_TUD_MEM_DCACHE_ENABLE ? \
+ (TU_DIV_CEIL(_size, CFG_TUD_MEM_DCACHE_LINE_SIZE) * CFG_TUD_MEM_DCACHE_LINE_SIZE) : (_size))
+
+// Declare an endpoint buffer with uint8_t[size]
+#define TUD_EPBUF_DEF(_name, _size) \
+ union { \
+ CFG_TUD_MEM_ALIGN uint8_t _name[_size]; \
+ uint8_t _name##_dcache_padding[TUD_EPBUF_DCACHE_SIZE(_size)]; \
+ }
+
+// Declare an endpoint buffer with a type
+#define TUD_EPBUF_TYPE_DEF(_type, _name) \
+ union { \
+ CFG_TUD_MEM_ALIGN _type _name; \
+ uint8_t _name##_dcache_padding[TUD_EPBUF_DCACHE_SIZE(sizeof(_type))]; \
+ }
+
+//------------- Host DCache declaration -------------//
+#define TUH_EPBUF_DCACHE_SIZE(_size) (CFG_TUH_MEM_DCACHE_ENABLE ? \
+ (TU_DIV_CEIL(_size, CFG_TUH_MEM_DCACHE_LINE_SIZE) * CFG_TUH_MEM_DCACHE_LINE_SIZE) : (_size))
+
+// Declare an endpoint buffer with uint8_t[size]
+#define TUH_EPBUF_DEF(_name, _size) \
+ union { \
+ CFG_TUH_MEM_ALIGN uint8_t _name[_size]; \
+ uint8_t _name##_dcache_padding[TUH_EPBUF_DCACHE_SIZE(_size)]; \
+ }
+
+// Declare an endpoint buffer with a type
+#define TUH_EPBUF_TYPE_DEF(_type, _name) \
+ union { \
+ CFG_TUH_MEM_ALIGN _type _name; \
+ uint8_t _name##_dcache_padding[TUH_EPBUF_DCACHE_SIZE(sizeof(_type))]; \
+ }
+
+
/*------------------------------------------------------------------*/
/* CONSTANTS
*------------------------------------------------------------------*/
+typedef enum {
+ TUSB_ROLE_INVALID = 0,
+ TUSB_ROLE_DEVICE = 0x1,
+ TUSB_ROLE_HOST = 0x2,
+} tusb_role_t;
+
/// defined base on EHCI specs value for Endpoint Speed
-typedef enum
-{
+typedef enum {
TUSB_SPEED_FULL = 0,
TUSB_SPEED_LOW = 1,
TUSB_SPEED_HIGH = 2,
+ TUSB_SPEED_AUTO = 0xaa,
TUSB_SPEED_INVALID = 0xff,
-}tusb_speed_t;
+} tusb_speed_t;
/// defined base on USB Specs Endpoint's bmAttributes
-typedef enum
-{
- TUSB_XFER_CONTROL = 0 ,
- TUSB_XFER_ISOCHRONOUS ,
- TUSB_XFER_BULK ,
- TUSB_XFER_INTERRUPT
-}tusb_xfer_type_t;
+typedef enum {
+ TUSB_XFER_CONTROL = 0,
+ TUSB_XFER_ISOCHRONOUS = 1,
+ TUSB_XFER_BULK = 2,
+ TUSB_XFER_INTERRUPT = 3
+} tusb_xfer_type_t;
-typedef enum
-{
+typedef enum {
TUSB_DIR_OUT = 0,
TUSB_DIR_IN = 1,
TUSB_DIR_IN_MASK = 0x80
-}tusb_dir_t;
+} tusb_dir_t;
-/// Isochronous End Point Attributes
-typedef enum
-{
+enum {
+ TUSB_EPSIZE_BULK_FS = 64,
+ TUSB_EPSIZE_BULK_HS = 512,
+
+ TUSB_EPSIZE_ISO_FS_MAX = 1023,
+ TUSB_EPSIZE_ISO_HS_MAX = 1024,
+};
+
+/// Isochronous Endpoint Attributes
+typedef enum {
TUSB_ISO_EP_ATT_NO_SYNC = 0x00,
TUSB_ISO_EP_ATT_ASYNCHRONOUS = 0x04,
TUSB_ISO_EP_ATT_ADAPTIVE = 0x08,
@@ -79,11 +123,10 @@ typedef enum
TUSB_ISO_EP_ATT_DATA = 0x00, ///< Data End Point
TUSB_ISO_EP_ATT_EXPLICIT_FB = 0x10, ///< Feedback End Point
TUSB_ISO_EP_ATT_IMPLICIT_FB = 0x20, ///< Data endpoint that also serves as an implicit feedback
-}tusb_iso_ep_attribute_t;
+} tusb_iso_ep_attribute_t;
/// USB Descriptor Types
-typedef enum
-{
+typedef enum {
TUSB_DESC_DEVICE = 0x01,
TUSB_DESC_CONFIGURATION = 0x02,
TUSB_DESC_STRING = 0x03,
@@ -110,10 +153,9 @@ typedef enum
TUSB_DESC_SUPERSPEED_ENDPOINT_COMPANION = 0x30,
TUSB_DESC_SUPERSPEED_ISO_ENDPOINT_COMPANION = 0x31
-}tusb_desc_type_t;
+} tusb_desc_type_t;
-typedef enum
-{
+typedef enum {
TUSB_REQ_GET_STATUS = 0 ,
TUSB_REQ_CLEAR_FEATURE = 1 ,
TUSB_REQ_RESERVED = 2 ,
@@ -127,25 +169,22 @@ typedef enum
TUSB_REQ_GET_INTERFACE = 10 ,
TUSB_REQ_SET_INTERFACE = 11 ,
TUSB_REQ_SYNCH_FRAME = 12
-}tusb_request_code_t;
+} tusb_request_code_t;
-typedef enum
-{
+typedef enum {
TUSB_REQ_FEATURE_EDPT_HALT = 0,
TUSB_REQ_FEATURE_REMOTE_WAKEUP = 1,
TUSB_REQ_FEATURE_TEST_MODE = 2
-}tusb_request_feature_selector_t;
+} tusb_request_feature_selector_t;
-typedef enum
-{
+typedef enum {
TUSB_REQ_TYPE_STANDARD = 0,
TUSB_REQ_TYPE_CLASS,
TUSB_REQ_TYPE_VENDOR,
TUSB_REQ_TYPE_INVALID
} tusb_request_type_t;
-typedef enum
-{
+typedef enum {
TUSB_REQ_RCPT_DEVICE =0,
TUSB_REQ_RCPT_INTERFACE,
TUSB_REQ_RCPT_ENDPOINT,
@@ -153,8 +192,7 @@ typedef enum
} tusb_request_recipient_t;
// https://www.usb.org/defined-class-codes
-typedef enum
-{
+typedef enum {
TUSB_CLASS_UNSPECIFIED = 0 ,
TUSB_CLASS_AUDIO = 1 ,
TUSB_CLASS_CDC = 2 ,
@@ -178,26 +216,23 @@ typedef enum
TUSB_CLASS_MISC = 0xEF ,
TUSB_CLASS_APPLICATION_SPECIFIC = 0xFE ,
TUSB_CLASS_VENDOR_SPECIFIC = 0xFF
-}tusb_class_code_t;
+} tusb_class_code_t;
typedef enum
{
MISC_SUBCLASS_COMMON = 2
}misc_subclass_type_t;
-typedef enum
-{
+typedef enum {
MISC_PROTOCOL_IAD = 1
-}misc_protocol_type_t;
+} misc_protocol_type_t;
-typedef enum
-{
+typedef enum {
APP_SUBCLASS_USBTMC = 0x03,
APP_SUBCLASS_DFU_RUNTIME = 0x01
} app_subclass_type_t;
-typedef enum
-{
+typedef enum {
DEVICE_CAPABILITY_WIRELESS_USB = 0x01,
DEVICE_CAPABILITY_USB20_EXTENSION = 0x02,
DEVICE_CAPABILITY_SUPERSPEED_USB = 0x03,
@@ -214,38 +249,46 @@ typedef enum
DEVICE_CAPABILITY_AUTHENTICATION = 0x0E,
DEVICE_CAPABILITY_BILLBOARD_EX = 0x0F,
DEVICE_CAPABILITY_CONFIGURATION_SUMMARY = 0x10
-}device_capability_type_t;
+} device_capability_type_t;
enum {
- TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = TU_BIT(5),
- TUSB_DESC_CONFIG_ATT_SELF_POWERED = TU_BIT(6),
+ TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = 1u << 5,
+ TUSB_DESC_CONFIG_ATT_SELF_POWERED = 1u << 6,
};
#define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2)
-typedef enum
-{
- XFER_RESULT_SUCCESS,
+// USB 2.0 Spec Table 9-7: Test Mode Selectors
+typedef enum {
+ TUSB_FEATURE_TEST_J = 1,
+ TUSB_FEATURE_TEST_K = 2,
+ TUSB_FEATURE_TEST_SE0_NAK = 3,
+ TUSB_FEATURE_TEST_PACKET = 4,
+ TUSB_FEATURE_TEST_FORCE_ENABLE = 5,
+} tusb_feature_test_mode_t;
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+typedef enum {
+ XFER_RESULT_SUCCESS = 0,
XFER_RESULT_FAILED,
XFER_RESULT_STALLED,
XFER_RESULT_TIMEOUT,
XFER_RESULT_INVALID
-}xfer_result_t;
+} xfer_result_t;
-enum // TODO remove
-{
+// TODO remove
+enum {
DESC_OFFSET_LEN = 0,
DESC_OFFSET_TYPE = 1
};
-enum
-{
+enum {
INTERFACE_INVALID_NUMBER = 0xff
};
-
-typedef enum
-{
+typedef enum {
MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00,
MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01,
MS_OS_20_SUBSET_HEADER_FUNCTION = 0x02,
@@ -257,14 +300,25 @@ typedef enum
MS_OS_20_FEATURE_VENDOR_REVISION = 0x08
} microsoft_os_20_type_t;
-enum
-{
- CONTROL_STAGE_IDLE,
+enum {
+ CONTROL_STAGE_IDLE = 0,
CONTROL_STAGE_SETUP,
CONTROL_STAGE_DATA,
CONTROL_STAGE_ACK
};
+enum {
+ TUSB_INDEX_INVALID_8 = 0xFFu
+};
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+typedef struct {
+ tusb_role_t role;
+ tusb_speed_t speed;
+} tusb_rhport_init_t;
+
//--------------------------------------------------------------------+
// USB Descriptors
//--------------------------------------------------------------------+
@@ -274,15 +328,14 @@ TU_ATTR_PACKED_BEGIN
TU_ATTR_BIT_FIELD_ORDER_BEGIN
/// USB Device Descriptor
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes.
uint8_t bDescriptorType ; ///< DEVICE Descriptor Type.
- uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). This field identifies the release of the USB Specification with which the device and its descriptors are compliant.
+ uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H).
- uint8_t bDeviceClass ; ///< Class code (assigned by the USB-IF). \li If this field is reset to zero, each interface within a configuration specifies its own class information and the various interfaces operate independently. \li If this field is set to a value between 1 and FEH, the device supports different class specifications on different interfaces and the interfaces may not operate independently. This value identifies the class definition used for the aggregate interfaces. \li If this field is set to FFH, the device class is vendor-specific.
- uint8_t bDeviceSubClass ; ///< Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass field. \li If the bDeviceClass field is reset to zero, this field must also be reset to zero. \li If the bDeviceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
- uint8_t bDeviceProtocol ; ///< Protocol code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass and the bDeviceSubClass fields. If a device supports class-specific protocols on a device basis as opposed to an interface basis, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use class-specific protocols on a device basis. However, it may use classspecific protocols on an interface basis. \li If this field is set to FFH, the device uses a vendor-specific protocol on a device basis.
+ uint8_t bDeviceClass ; ///< Class code (assigned by the USB-IF).
+ uint8_t bDeviceSubClass ; ///< Subclass code (assigned by the USB-IF).
+ uint8_t bDeviceProtocol ; ///< Protocol code (assigned by the USB-IF).
uint8_t bMaxPacketSize0 ; ///< Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid). For HS devices is fixed to 64.
uint16_t idVendor ; ///< Vendor ID (assigned by the USB-IF).
@@ -298,8 +351,7 @@ typedef struct TU_ATTR_PACKED
TU_VERIFY_STATIC( sizeof(tusb_desc_device_t) == 18, "size is not correct");
// USB Binary Device Object Store (BOS) Descriptor
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes
uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type
uint16_t wTotalLength ; ///< Total length of data returned for this descriptor
@@ -309,8 +361,7 @@ typedef struct TU_ATTR_PACKED
TU_VERIFY_STATIC( sizeof(tusb_desc_bos_t) == 5, "size is not correct");
/// USB Configuration Descriptor
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes
uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type
uint16_t wTotalLength ; ///< Total length of data returned for this configuration. Includes the combined length of all descriptors (configuration, interface, endpoint, and class- or vendor-specific) returned for this configuration.
@@ -325,8 +376,7 @@ typedef struct TU_ATTR_PACKED
TU_VERIFY_STATIC( sizeof(tusb_desc_configuration_t) == 9, "size is not correct");
/// USB Interface Descriptor
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes
uint8_t bDescriptorType ; ///< INTERFACE Descriptor Type
@@ -342,8 +392,7 @@ typedef struct TU_ATTR_PACKED
TU_VERIFY_STATIC( sizeof(tusb_desc_interface_t) == 9, "size is not correct");
/// USB Endpoint Descriptor
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength ; // Size of this descriptor in bytes
uint8_t bDescriptorType ; // ENDPOINT Descriptor Type
@@ -363,8 +412,7 @@ typedef struct TU_ATTR_PACKED
TU_VERIFY_STATIC( sizeof(tusb_desc_endpoint_t) == 7, "size is not correct");
/// USB Other Speed Configuration Descriptor
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of descriptor
uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
uint16_t wTotalLength ; ///< Total length of data returned
@@ -377,8 +425,7 @@ typedef struct TU_ATTR_PACKED
} tusb_desc_other_speed_t;
/// USB Device Qualifier Descriptor
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of descriptor
uint8_t bDescriptorType ; ///< Device Qualifier Type
uint16_t bcdUSB ; ///< USB specification version number (e.g., 0200H for V2.00)
@@ -395,8 +442,7 @@ typedef struct TU_ATTR_PACKED
TU_VERIFY_STATIC( sizeof(tusb_desc_device_qualifier_t) == 10, "size is not correct");
/// USB Interface Association Descriptor (IAD ECN)
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of descriptor
uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
@@ -410,17 +456,17 @@ typedef struct TU_ATTR_PACKED
uint8_t iFunction ; ///< Index of the string descriptor describing the interface association.
} tusb_desc_interface_assoc_t;
+TU_VERIFY_STATIC( sizeof(tusb_desc_interface_assoc_t) == 8, "size is not correct");
+
// USB String Descriptor
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength ; ///< Size of this descriptor in bytes
uint8_t bDescriptorType ; ///< Descriptor Type
uint16_t unicode_string[];
} tusb_desc_string_t;
// USB Binary Device Object Store (BOS)
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength;
uint8_t bDescriptorType ;
uint8_t bDevCapabilityType;
@@ -429,9 +475,8 @@ typedef struct TU_ATTR_PACKED
uint8_t CapabilityData[];
} tusb_desc_bos_platform_t;
-// USB WebuSB URL Descriptor
-typedef struct TU_ATTR_PACKED
-{
+// USB WebUSB URL Descriptor
+typedef struct TU_ATTR_PACKED {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bScheme;
@@ -439,8 +484,7 @@ typedef struct TU_ATTR_PACKED
} tusb_desc_webusb_url_t;
// DFU Functional Descriptor
-typedef struct TU_ATTR_PACKED
-{
+typedef struct TU_ATTR_PACKED {
uint8_t bLength;
uint8_t bDescriptorType;
@@ -461,10 +505,11 @@ typedef struct TU_ATTR_PACKED
uint16_t bcdDFUVersion;
} tusb_desc_dfu_functional_t;
-/*------------------------------------------------------------------*/
-/* Types
- *------------------------------------------------------------------*/
-typedef struct TU_ATTR_PACKED{
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+typedef struct TU_ATTR_PACKED {
union {
struct TU_ATTR_PACKED {
uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t.
@@ -483,7 +528,6 @@ typedef struct TU_ATTR_PACKED{
TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "size is not correct");
-
TU_ATTR_PACKED_END // End of all packed definitions
TU_ATTR_BIT_FIELD_ORDER_END
@@ -492,37 +536,26 @@ TU_ATTR_BIT_FIELD_ORDER_END
//--------------------------------------------------------------------+
// Get direction from Endpoint address
-TU_ATTR_ALWAYS_INLINE static inline tusb_dir_t tu_edpt_dir(uint8_t addr)
-{
+TU_ATTR_ALWAYS_INLINE static inline tusb_dir_t tu_edpt_dir(uint8_t addr) {
return (addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
}
// Get Endpoint number from address
-TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr) {
return (uint8_t)(addr & (~TUSB_DIR_IN_MASK));
}
-TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir) {
return (uint8_t)(num | (dir ? TUSB_DIR_IN_MASK : 0));
}
-TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep)
-{
- return tu_le16toh(desc_ep->wMaxPacketSize) & TU_GENMASK(10, 0);
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep) {
+ return tu_le16toh(desc_ep->wMaxPacketSize) & 0x7FF;
}
#if CFG_TUSB_DEBUG
-TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_dir_str(tusb_dir_t dir)
-{
- static const char *str[] = {"out", "in"};
- return str[dir];
-}
-
-TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_t t)
-{
- static const char *str[] = {"control", "isochronous", "bulk", "interrupt"};
+TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_t t) {
+ tu_static const char *str[] = {"control", "isochronous", "bulk", "interrupt"};
return str[t];
}
#endif
@@ -530,26 +563,34 @@ TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_type_str(tusb_xfer_type_
//--------------------------------------------------------------------+
// Descriptor helper
//--------------------------------------------------------------------+
-TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* desc)
-{
+
+// return next descriptor
+TU_ATTR_ALWAYS_INLINE static inline uint8_t const * tu_desc_next(void const* desc) {
uint8_t const* desc8 = (uint8_t const*) desc;
return desc8 + desc8[DESC_OFFSET_LEN];
}
-TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc)
-{
+// get descriptor type
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_type(void const* desc) {
return ((uint8_t const*) desc)[DESC_OFFSET_TYPE];
}
-TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc)
-{
+// get descriptor length
+TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_desc_len(void const* desc) {
return ((uint8_t const*) desc)[DESC_OFFSET_LEN];
}
+// find descriptor that match byte1 (type)
+uint8_t const * tu_desc_find(uint8_t const* desc, uint8_t const* end, uint8_t byte1);
+
+// find descriptor that match byte1 (type) and byte2
+uint8_t const * tu_desc_find2(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2);
+
+// find descriptor that match byte1 (type) and byte2
+uint8_t const * tu_desc_find3(uint8_t const* desc, uint8_t const* end, uint8_t byte1, uint8_t byte2, uint8_t byte3);
+
#ifdef __cplusplus
}
#endif
-#endif /* _TUSB_TYPES_H_ */
-
-/** @} */
+#endif // TUSB_TYPES_H_
diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h
index a52a6d269..6d02d3572 100644
--- a/src/common/tusb_verify.h
+++ b/src/common/tusb_verify.h
@@ -1,4 +1,4 @@
-/*
+/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
@@ -56,12 +56,8 @@
* #define TU_VERIFY(cond) if(cond) return false;
* #define TU_VERIFY(cond,ret) if(cond) return ret;
*
- * #define TU_VERIFY_HDLR(cond,handler) if(cond) {handler; return false;}
- * #define TU_VERIFY_HDLR(cond,ret,handler) if(cond) {handler; return ret;}
- *
- * #define TU_ASSERT(cond) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return false;}
- * #define TU_ASSERT(cond,ret) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return ret;}
- *
+ * #define TU_ASSERT(cond) if(cond) {TU_MESS_FAILED(); TU_BREAKPOINT(), return false;}
+ * #define TU_ASSERT(cond,ret) if(cond) {TU_MESS_FAILED(); TU_BREAKPOINT(), return ret;}
*------------------------------------------------------------------*/
#ifdef __cplusplus
@@ -74,20 +70,20 @@
#if CFG_TUSB_DEBUG
#include <stdio.h>
- #define _MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__)
+ #define TU_MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__)
#else
- #define _MESS_FAILED() do {} while (0)
+ #define TU_MESS_FAILED() do {} while (0)
#endif
-// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7, M33
-#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__)
- #define TU_BREAKPOINT() do \
- { \
+// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7, M33. M55
+#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8_1M_MAIN__) || \
+ defined(__ARM7M__) || defined (__ARM7EM__) || defined(__ARM8M_MAINLINE__) || defined(__ARM8EM_MAINLINE__)
+ #define TU_BREAKPOINT() do { \
volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
if ( (*ARM_CM_DHCSR) & 1UL ) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */ \
} while(0)
-#elif defined(__riscv)
+#elif defined(__riscv) && !TUSB_MCU_VENDOR_ESPRESSIF
#define TU_BREAKPOINT() do { __asm("ebreak\n"); } while(0)
#elif defined(_mips)
@@ -98,39 +94,19 @@
#endif
/*------------------------------------------------------------------*/
-/* Macro Generator
- *------------------------------------------------------------------*/
-
-// 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
-
-/*------------- Generator for TU_VERIFY and TU_VERIFY_HDLR -------------*/
-#define TU_VERIFY_DEFINE(_cond, _handler, _ret) do \
-{ \
- if ( !(_cond) ) { _handler; return _ret; } \
-} while(0)
-
-/*------------------------------------------------------------------*/
/* TU_VERIFY
* - TU_VERIFY_1ARGS : return false if failed
* - TU_VERIFY_2ARGS : return provided value if failed
*------------------------------------------------------------------*/
-#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_DEFINE(_cond, _ret) \
+ do { \
+ if ( !(_cond) ) { return _ret; } \
+ } while(0)
-/*------------------------------------------------------------------*/
-/* TU_VERIFY WITH HANDLER
- * - TU_VERIFY_HDLR_2ARGS : execute handler, return false if failed
- * - TU_VERIFY_HDLR_3ARGS : execute handler, return provided error if failed
- *------------------------------------------------------------------*/
-#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_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, false)
+#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _ret)
-#define TU_VERIFY_HDLR(...) _GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_HDLR_3ARGS, TU_VERIFY_HDLR_2ARGS,UNUSED)(__VA_ARGS__)
+#define TU_VERIFY(...) TU_GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__)
/*------------------------------------------------------------------*/
/* ASSERT
@@ -138,19 +114,20 @@
* - 1 arg : return false if failed
* - 2 arg : return error if failed
*------------------------------------------------------------------*/
-#define ASSERT_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), false)
-#define ASSERT_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), _ret)
+#define TU_ASSERT_DEFINE(_cond, _ret) \
+ do { \
+ if ( !(_cond) ) { TU_MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
+ } while(0)
+
+#define TU_ASSERT_1ARGS(_cond) TU_ASSERT_DEFINE(_cond, false)
+#define TU_ASSERT_2ARGS(_cond, _ret) TU_ASSERT_DEFINE(_cond, _ret)
#ifndef TU_ASSERT
-#define TU_ASSERT(...) _GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS,UNUSED)(__VA_ARGS__)
+#define TU_ASSERT(...) TU_GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
#endif
-/*------------------------------------------------------------------*/
-/* ASSERT HDLR
- *------------------------------------------------------------------*/
-
#ifdef __cplusplus
}
#endif
-#endif /* TUSB_VERIFY_H_ */
+#endif