summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/tusb_common.h71
-rw-r--r--src/common/tusb_compiler.h48
-rw-r--r--src/common/tusb_debug.h45
-rw-r--r--src/common/tusb_fifo.c483
-rw-r--r--src/common/tusb_fifo.h120
-rw-r--r--src/common/tusb_mcu.h218
-rw-r--r--src/common/tusb_private.h114
-rw-r--r--src/common/tusb_timeout.h80
-rw-r--r--src/common/tusb_types.h193
-rw-r--r--src/common/tusb_verify.h58
10 files changed, 877 insertions, 553 deletions
diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h
index b1ee40a1a..1f08ce4ed 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))) )
//--------------------------------------------------------------------+
@@ -73,7 +76,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 ovious 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,14 +99,33 @@
#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)
-{
+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)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u16(uint8_t high, uint8_t low) {
return (uint16_t) ((((uint16_t) high) << 8) | low);
}
@@ -121,16 +156,20 @@ 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; }
@@ -222,11 +261,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..6f07bdd53 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)
@@ -61,6 +61,13 @@
#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__)
@@ -121,7 +128,9 @@
#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))
+ #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 +140,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 +157,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.
@@ -185,11 +207,13 @@
#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))
+ #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
@@ -232,7 +256,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..76696396b 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);
}
@@ -66,23 +67,20 @@ typedef enum
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 +88,22 @@ 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
+//--------------------------------------------------------------------+
// 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 +111,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 +120,49 @@ 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;
}
}
-// 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 +172,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;
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 +192,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 +221,35 @@ 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;
+ 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 +259,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;
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 +277,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 +300,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,7 +308,7 @@ 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;
@@ -317,178 +316,232 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rel, tu
}
}
-// 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))
+ uint16_t new_idx = (uint16_t) (idx + offset);
+ if ( (idx > new_idx) || (new_idx >= 2*depth) )
{
- p = (uint16_t) ((p - offset) - f->non_used_index_space);
+ uint16_t const non_used_index_space = (uint16_t) (UINT16_MAX - (2*depth-1));
+ new_idx = (uint16_t) (new_idx + non_used_index_space);
}
- else
- {
- p -= offset;
- }
- 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 +557,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 +584,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 +602,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 +620,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 +638,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 +664,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 +700,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;
@@ -682,8 +739,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 +797,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;
}
@@ -817,9 +872,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 +911,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 +921,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 +932,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 +942,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 +963,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 +989,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 +1030,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..2d9f5e667 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,70 +42,116 @@ 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
-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;
-}
+#if OSAL_MUTEX_REQUIRED
+ TU_ATTR_ALWAYS_INLINE static inline
+ 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);
@@ -127,13 +173,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 +188,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..308ee713c 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,52 +54,77 @@
* - 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_MIMXRT1XXX)
+ #define TUP_USBIP_CHIPIDEA_HS
+ #define TUP_USBIP_EHCI
+
+ #define TUP_DCD_ENDPOINT_MAX 8
+ #define TUP_RHPORT_HIGHSPEED 1
+
+#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
@@ -116,19 +147,30 @@
#define TUP_DCD_ENDPOINT_MAX 16
#define TUP_DCD_ENDPOINT_EXCLUSIVE_NUMBER
-//------------- 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 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 +181,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 +210,34 @@
#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_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 +247,64 @@
#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)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
- #define TUP_DCD_ENDPOINT_MAX 6
-//------------- Sony -------------//
+ // 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
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32L5)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+//--------------------------------------------------------------------+
+// 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
-//------------- 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_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,47 +315,66 @@
#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
-//------------- Dialog -------------//
+//--------------------------------------------------------------------+
+// 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_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
@@ -271,16 +383,42 @@
#define TUP_DCD_ENDPOINT_MAX 16
#define TUP_RHPORT_HIGHSPEED 1
-//------------ Allwinner -------------//
+//--------------------------------------------------------------------+
+// Allwinner
+//--------------------------------------------------------------------+
#elif TU_CHECK_MCU(OPT_MCU_F1C100S)
#define TUP_DCD_ENDPOINT_MAX 4
+//------------- WCH -------------//
+#elif TU_CHECK_MCU(OPT_MCU_CH32V307)
+ #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_RHPORT_HIGHSPEED 1
+
+#elif TU_CHECK_MCU(OPT_MCU_CH32F20X)
+ #define TUP_DCD_ENDPOINT_MAX 16
+ #define TUP_RHPORT_HIGHSPEED 1
+#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_MCU_MULTIPLE_CORE
+#define TUP_MCU_MULTIPLE_CORE 0
+#endif
+
#ifndef TUP_DCD_ENDPOINT_MAX
#warning "TUP_DCD_ENDPOINT_MAX is not defined for this MCU, default to 8"
#define TUP_DCD_ENDPOINT_MAX 8
diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h
index b34506f65..373a50256 100644
--- a/src/common/tusb_private.h
+++ b/src/common/tusb_private.h
@@ -28,6 +28,8 @@
#ifndef _TUSB_PRIVATE_H_
#define _TUSB_PRIVATE_H_
+// Internal Helper used by Host and Device Stack
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -39,8 +41,31 @@ typedef struct TU_ATTR_PACKED
volatile uint8_t claimed : 1;
}tu_edpt_state_t;
+typedef struct {
+ bool is_host; // host or device most
+ union {
+ uint8_t daddr;
+ uint8_t rhport;
+ uint8_t hwid;
+ };
+ uint8_t ep_addr;
+ uint8_t ep_speed;
+
+ uint16_t ep_packetsize;
+ uint16_t ep_bufsize;
+
+ // TODO xfer_fifo can skip this buffer
+ uint8_t* ep_buf;
+
+ tu_fifo_t ff;
+
+ // mutex: read if ep rx, write if e tx
+ 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,6 +83,93 @@ 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
+// hwid is either device address (host mode) or rhport (device mode)
+TU_ATTR_ALWAYS_INLINE static inline
+void tu_edpt_stream_open(tu_edpt_stream_t* s, uint8_t hwid, tusb_desc_endpoint_t const *desc_ep) {
+ tu_fifo_clear(&s->ff);
+ s->hwid = hwid;
+ s->ep_addr = desc_ep->bEndpointAddress;
+ s->ep_packetsize = tu_edpt_packet_size(desc_ep);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline
+void tu_edpt_stream_close(tu_edpt_stream_t* s) {
+ s->hwid = 0;
+ 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(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(tu_edpt_stream_t* s);
+
+// Start an zero-length packet if needed
+bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes);
+
+// Get the number of bytes available for writing
+TU_ATTR_ALWAYS_INLINE static inline
+uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) {
+ return (uint32_t) tu_fifo_remaining(&s->ff);
+}
+
+//--------------------------------------------------------------------+
+// Stream Read
+//--------------------------------------------------------------------+
+
+// Read from stream
+uint32_t tu_edpt_stream_read(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(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) {
+ 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 (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
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 1f2a38d4c..2c5dce723 100644
--- a/src/common/tusb_types.h
+++ b/src/common/tusb_types.h
@@ -44,34 +44,38 @@
*------------------------------------------------------------------*/
/// 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_INVALID = 0xff,
-}tusb_speed_t;
+} tusb_speed_t;
/// defined base on USB Specs Endpoint's bmAttributes
-typedef enum
-{
+typedef enum {
TUSB_XFER_CONTROL = 0 ,
TUSB_XFER_ISOCHRONOUS ,
TUSB_XFER_BULK ,
TUSB_XFER_INTERRUPT
-}tusb_xfer_type_t;
+} 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 +83,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 +113,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 +129,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 +152,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 +176,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,7 +209,7 @@ 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),
@@ -223,29 +218,28 @@ enum {
#define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2)
-typedef enum
-{
- XFER_RESULT_SUCCESS,
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+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 +251,17 @@ typedef enum
MS_OS_20_FEATURE_VENDOR_REVISION = 0x08
} microsoft_os_20_type_t;
-enum
-{
+enum {
CONTROL_STAGE_IDLE,
CONTROL_STAGE_SETUP,
CONTROL_STAGE_DATA,
CONTROL_STAGE_ACK
};
+enum {
+ TUSB_INDEX_INVALID_8 = 0xFFu
+};
+
//--------------------------------------------------------------------+
// USB Descriptors
//--------------------------------------------------------------------+
@@ -274,8 +271,7 @@ 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.
@@ -298,8 +294,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 +304,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 +319,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 +335,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 +355,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 +368,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 +385,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 +399,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 +418,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 +427,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 +448,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 +471,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,46 +479,64 @@ 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)
-{
+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);
}
+#if CFG_TUSB_DEBUG
+TU_ATTR_ALWAYS_INLINE static inline const char *tu_edpt_dir_str(tusb_dir_t dir) {
+ tu_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) {
+ tu_static const char *str[] = {"control", "isochronous", "bulk", "interrupt"};
+ return str[t];
+}
+#endif
+
//--------------------------------------------------------------------+
// 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
diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h
index a52a6d269..8aa66b4df 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;}
- *
*------------------------------------------------------------------*/
#ifdef __cplusplus
@@ -79,8 +75,8 @@
#define _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__)
+// 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__)
#define TU_BREAKPOINT() do \
{ \
volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
@@ -97,40 +93,23 @@
#define TU_BREAKPOINT() do {} while (0)
#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_DEFINE(_cond, _ret) \
+ do { \
+ if ( !(_cond) ) { return _ret; } \
+ } while(0)
-#define TU_VERIFY(...) _GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, UNUSED)(__VA_ARGS__)
+#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, false)
+#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _ret)
-
-/*------------------------------------------------------------------*/
-/* 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_HDLR(...) _GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_HDLR_3ARGS, TU_VERIFY_HDLR_2ARGS,UNUSED)(__VA_ARGS__)
+#define TU_VERIFY(...) _GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__)
/*------------------------------------------------------------------*/
/* ASSERT
@@ -138,19 +117,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) ) { _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(...) _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