diff --git a/tinyusb/common/fifo.c b/tinyusb/common/fifo.c index b0f82218..dd7a6629 100644 --- a/tinyusb/common/fifo.c +++ b/tinyusb/common/fifo.c @@ -7,7 +7,7 @@ Software License Agreement (BSD License) - Copyright (c) 2013, hathach (tinyusb.org) + Copyright (c) 2018, hathach (tinyusb.org) All rights reserved. Redistribution and use in source and binary forms, with or without @@ -35,18 +35,36 @@ This file is part of the tinyusb stack. */ /**************************************************************************/ -#include + #include "fifo.h" -//static inline void mutex_lock (fifo_t* f) ATTR_ALWAYS_INLINE; -//static inline void mutex_unlock (fifo_t* f) ATTR_ALWAYS_INLINE; -#define mutex_lock(f) -#define mutex_unlock(f) +/*------------------------------------------------------------------*/ +/* + *------------------------------------------------------------------*/ +#if CFG_FIFO_MUTEX -static inline bool is_fifo_initalized(fifo_t* f) ATTR_ALWAYS_INLINE; +#define mutex_lock_if_needed(_ff) if (_ff->mutex) fifo_mutex_lock(_ff->mutex) +#define mutex_unlock_if_needed(_ff) if (_ff->mutex) fifo_mutex_unlock(_ff->mutex) + +#else + +#define mutex_lock_if_needed(_ff) +#define mutex_unlock_if_needed(_ff) + +#endif + +static inline uint16_t min16_of(uint16_t x, uint16_t y) +{ + return (x < y) ? x : y; +} + +static inline bool fifo_initalized(fifo_t* f) +{ + return (f->buffer != NULL) && (f->depth > 0) && (f->item_size > 0); +} -/**************************************************************************/ +/******************************************************************************/ /*! @brief Read one byte out of the RX buffer. @@ -56,20 +74,18 @@ static inline bool is_fifo_initalized(fifo_t* f) ATTR_ALWAYS_INLINE; @param[in] f Pointer to the FIFO buffer to manipulate - @param[in] data + @param[in] p_buffer Pointer to the place holder for data read from the buffer @returns TRUE if the queue is not empty */ -/**************************************************************************/ +/******************************************************************************/ bool fifo_read(fifo_t* f, void * p_buffer) { - if( !is_fifo_initalized(f) || fifo_is_empty(f) ) - { - return false; - } + if( !fifo_initalized(f) ) return false; + if( fifo_is_empty(f) ) return false; - mutex_lock(f); + mutex_lock_if_needed(f); memcpy(p_buffer, f->buffer + (f->rd_idx * f->item_size), @@ -77,36 +93,108 @@ bool fifo_read(fifo_t* f, void * p_buffer) f->rd_idx = (f->rd_idx + 1) % f->depth; f->count--; - mutex_unlock(f); + mutex_unlock_if_needed(f); return true; } -/**************************************************************************/ +/******************************************************************************/ /*! - @brief Write one byte into the RX buffer. - - This function will write one byte into the array index specified by + @brief This function will read n elements into the array index specified by the write pointer and increment the write index. If the write index exceeds the max buffer size, then it will roll over to zero. @param[in] f Pointer to the FIFO buffer to manipulate - @param[in] data + @param[in] p_data + The pointer to data location + @param[in] count + Number of element that buffer can afford + + @returns number of bytes read from the FIFO +*/ +/******************************************************************************/ +uint16_t fifo_read_n (fifo_t* f, void * p_buffer, uint16_t count) +{ + if( !fifo_initalized(f) ) return false; + if( fifo_is_empty(f) ) return false; + + /* Limit up to fifo's count */ + count = min16_of(count, f->count); + if( count == 0 ) return 0; + + mutex_lock_if_needed(f); + + /* Could copy up to 2 portions marked as 'x' if queue is wrapped around + * case 1: ....RxxxxW....... + * case 2: xxxxxW....Rxxxxxx + */ +// uint16_t index2upper = min16_of(count, f->count-f->rd_idx); + + uint8_t* p_buf = (uint8_t*) p_buffer; + uint16_t len = 0; + while( (len < count) && fifo_read(f, p_buf) ) + { + len++; + p_buf += f->item_size; + } + + mutex_unlock_if_needed(f); + + return len; +} + +/******************************************************************************/ +/*! + @brief Reads one item without removing it from the FIFO + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] position + Position to read from in the FIFO buffer + @param[in] p_buffer + Pointer to the place holder for data read from the buffer + + @returns TRUE if the queue is not empty +*/ +/******************************************************************************/ +bool fifo_peek_at(fifo_t* f, uint16_t position, void * p_buffer) +{ + if ( !fifo_initalized(f) ) return false; + if ( position >= f->count ) return false; + + // rd_idx is position=0 + uint16_t index = (f->rd_idx + position) % f->depth; + memcpy(p_buffer, + f->buffer + (index * f->item_size), + f->item_size); + + return true; +} + +/******************************************************************************/ +/*! + @brief Write one element into the RX buffer. + + This function will write one element into the array index specified by + the write pointer and increment the write index. If the write index + exceeds the max buffer size, then it will roll over to zero. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] p_data The byte to add to the FIFO @returns TRUE if the data was written to the FIFO (overwrittable FIFO will always return TRUE) */ -/**************************************************************************/ +/******************************************************************************/ bool fifo_write(fifo_t* f, void const * p_data) { - if ( !is_fifo_initalized(f) || (fifo_is_full(f) && !f->overwritable) ) - { - return false; - } + if ( !fifo_initalized(f) ) return false; + if ( fifo_is_full(f) && !f->overwritable ) return false; - mutex_lock(f); + mutex_lock_if_needed(f); memcpy( f->buffer + (f->wr_idx * f->item_size), p_data, @@ -117,75 +205,61 @@ bool fifo_write(fifo_t* f, void const * p_data) if (fifo_is_full(f)) { f->rd_idx = f->wr_idx; // keep the full state (rd == wr && len = size) - }else + } + else { f->count++; } - mutex_unlock(f); + mutex_unlock_if_needed(f); return true; } -/**************************************************************************/ +/******************************************************************************/ +/*! + @brief This function will write n elements into the array index specified by + the write pointer and increment the write index. If the write index + exceeds the max buffer size, then it will roll over to zero. + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] p_data + The pointer to data to add to the FIFO + @param[in] count + Number of element + @return Number of written elements +*/ +/******************************************************************************/ +uint16_t fifo_write_n(fifo_t* f, void const * p_data, uint16_t count) +{ + if ( count == 0 ) return 0; + + uint8_t* p_buf = (uint8_t*) p_data; + + uint16_t len = 0; + while( (len < count) && fifo_write(f, p_buf) ) + { + len++; + p_buf += f->item_size; + } + + return len; +} + +/******************************************************************************/ /*! @brief Clear the fifo read and write pointers and set length to zero @param[in] f Pointer to the FIFO buffer to manipulate */ -/**************************************************************************/ +/******************************************************************************/ void fifo_clear(fifo_t *f) { - mutex_lock(f); + mutex_lock_if_needed(f); f->rd_idx = f->wr_idx = f->count = 0; - mutex_unlock(f); -} - -//--------------------------------------------------------------------+ -// HELPER FUNCTIONS -//--------------------------------------------------------------------+ - -/**************************************************************************/ -/*! - @brief Disables the IRQ specified in the FIFO's 'irq' field - to prevent reads/write issues with interrupts - - @param[in] f - Pointer to the FIFO that should be protected -*/ -/**************************************************************************/ -//static inline void mutex_lock (fifo_t* f) -//{ -// if (f->irq > 0) -// { -// #if !defined (_TEST_) -// NVIC_DisableIRQ(f->irq); -// #endif -// } -//} - -/**************************************************************************/ -/*! - @brief Re-enables the IRQ specified in the FIFO's 'irq' field - - @param[in] f - Pointer to the FIFO that should be protected -*/ -/**************************************************************************/ -//static inline void mutex_unlock (fifo_t* f) -//{ -// if (f->irq > 0) -// { -// #if !defined (_TEST_) -// NVIC_EnableIRQ(f->irq); -// #endif -// } -//} - -static inline bool is_fifo_initalized(fifo_t* f) -{ - return !( f->buffer == NULL || f->depth == 0 || f->item_size == 0); + mutex_unlock_if_needed(f); } diff --git a/tinyusb/common/fifo.h b/tinyusb/common/fifo.h index 113c21a5..f069c54a 100644 --- a/tinyusb/common/fifo.h +++ b/tinyusb/common/fifo.h @@ -7,7 +7,7 @@ Software License Agreement (BSD License) - Copyright (c) 2013, hathach (tinyusb.org) + Copyright (c) 2018, hathach (tinyusb.org) All rights reserved. Redistribution and use in source and binary forms, with or without @@ -43,12 +43,36 @@ #ifndef _TUSB_FIFO_H_ #define _TUSB_FIFO_H_ -#include "common/common.h" +#define CFG_FIFO_MUTEX 0 + +#include +#include +#include #ifdef __cplusplus extern "C" { #endif +#if CFG_FIFO_MUTEX + +/*Mutex port for newt*/ +#include "os/os_mutex.h" + +#define fifo_mutex_t struct os_mutex + +#define fifo_mutex_lock(m) os_mutex_pend(m, OS_TIMEOUT_NEVER) +#define fifo_mutex_unlock(m) os_mutex_release(m) + +/* Internal use only */ +#define _mutex_declare(m) .mutex = m + +#else + +#define _mutex_declare(m) + +#endif + + /** \struct fifo_t * \brief Simple Circular FIFO */ @@ -61,7 +85,11 @@ typedef struct volatile uint16_t wr_idx ; ///< write pointer volatile uint16_t rd_idx ; ///< read pointer bool overwritable ; - // IRQn_Type irq; + +#if CFG_FIFO_MUTEX + fifo_mutex_t * const mutex; +#endif + } fifo_t; #define FIFO_DEF(name, ff_depth, type, is_overwritable) /*, irq_mutex)*/ \ @@ -72,30 +100,49 @@ typedef struct .item_size = sizeof(type),\ .overwritable = is_overwritable,\ /*.irq = irq_mutex*/\ + _mutex_declare(_mutex)\ } -bool fifo_write(fifo_t* f, void const * p_data); -bool fifo_read(fifo_t* f, void * p_buffer); void fifo_clear(fifo_t *f); -static inline bool fifo_is_empty(fifo_t* f) ATTR_PURE ATTR_ALWAYS_INLINE; +bool fifo_write (fifo_t* f, void const * p_data); +uint16_t fifo_write_n (fifo_t* f, void const * p_data, uint16_t count); + +bool fifo_read (fifo_t* f, void * p_buffer); +uint16_t fifo_read_n (fifo_t* f, void * p_buffer, uint16_t count); + +bool fifo_peek_at (fifo_t* f, uint16_t position, void * p_buffer); + +static inline bool fifo_peek(fifo_t* f, void * p_buffer) +{ + return fifo_peek_at(f, 0, p_buffer); +} + static inline bool fifo_is_empty(fifo_t* f) { return (f->count == 0); } -static inline bool fifo_is_full(fifo_t* f) ATTR_PURE ATTR_ALWAYS_INLINE; static inline bool fifo_is_full(fifo_t* f) { return (f->count == f->depth); } -static inline uint16_t fifo_get_length(fifo_t* f) ATTR_PURE ATTR_ALWAYS_INLINE; static inline uint16_t fifo_get_length(fifo_t* f) { return f->count; } +static inline uint16_t fifo_remaining(fifo_t* f) +{ + return f->depth - f->count; +} + +static inline uint16_t fifo_depth(fifo_t* f) +{ + return f->depth; +} + #ifdef __cplusplus } #endif