/* @file fifo.h
  * 
  * @brief Generic circular FIFO implementation, able to store elements of arbitrary nature
  * 
  * Elements are returned in the order in which they were stored. 
  * If the number of element to store is superior to the amount the FIFO can hold ( the FIFO is then full ),
  * the oldest element is trashed and the new one stored instead. 
  *
  */

/** @par LICENCE
 * 
 *  @verbatim
   Copyright (C) 2009  ADDI-DATA GmbH for the source code of this module.
        
        ADDI-DATA GmbH
        Airpark Business Center
        Airport Boulevard B210
        77836 Rheinmünster
        Germany
        Tel: +49(0)7229/1847-0
        Fax: +49(0)7229/1847-200
        http://www.addi-data-com
        info@addi-data.com
 
 This library is free software; you can redistribute it and/or modify it under 
 the terms of the GNU Lesser General Public License as published by the 
 Free Software Foundation; either version 2.1 of the License, 
 or (at your option) any later version.
 
 This library is distributed in the hope that it will be useful, 
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 or FITNESS FOR A PARTICULAR PURPOSE. 
 See the GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License 
 along with this library; if not, write to the Free Software Foundation, 
 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
 
 You also shoud find the complete LGPL in the LGPL.txt file accompanying 
 this source code.
 
 @endverbatim
**/

#ifndef FIFO_H_
#define FIFO_H_

/* The macro DECLARE_NEW_FIFO_TYPE takes the following parameters:
 *  - name of the type associated to the macro structure (__type_name)
 *  - maximum number of elements in the FIFO (__size)
 *  - data type of the element in the FIFO (__data_type)
 * 
 * Calling it declares the following:
 * - a new type of name __type_name, containing a memory of __size elements of type __data_type
 * - the functions initialise(), is_empty(), is_full(), count(), add(), retrieve(), max(). 
 * 
 * The name of the functions are prefixed with __type_name
 * 
 * initialise() takes a parameter of type (__type_name *) and has no return value
 *  
 * is_empty() takes a parameter of type (__type_name *) and returns 1 if the FIFO is empty
 * 
 * is_full() takes a parameter of type (__type_name *) and returns 1 if the FIFO is full, meaning containing that at least __size elements has been stored
 * 
 * count() takes a parameter of type (__type_name *) and returns the number of current elements in the FIFO
 * 
 * max() takes no parameter and returns the maximum number of elements the FIFO can hold before cycling
 * 
 * add() takes a parameter of type (__type_name *), a parameter of type (__data_type *) to store, 
 * which may be actually an array of elements, and the number of elements to store. It returns 0 
 * if the store operation didn't cycle, 1 if it did, meaning that more elements than what could 
 * be actually done were stored and oldest elements were lost
 * 
 * retrieve() takes a parameter of type (__type_name *), a parameter of type (__data_type *) to store retrieved elements, 
 * which may be actually an array of elements, and the number of elements to retrieve. It returns the actual number
 * of elements that were removed of the FIFO and may be 0 if the FIFO was empty
 *  
 */


#define DECLARE_NEW_FIFO_TYPE(__type_name,__size,__data_type) \
typedef \
struct \
{ \
	unsigned int begin,end, count; \
	__data_type tab[__size]; \
} __type_name; \
static inline void __type_name ## _initialise(__type_name * fifo) \
{ \
	memset(fifo,0,sizeof(__type_name)); \
	fifo->end = fifo->begin = fifo->count = 0; \
} \
static inline int __type_name ## _is_empty(__type_name * fifo) \
{ \
	return (fifo->count == 0) ; \
} \
static inline int __type_name ## _is_full(__type_name * fifo) \
{ \
	if( (fifo->end==fifo->begin-1) || (fifo->begin==0 && fifo->end==__size-1) ) \
	{ \
		return 1 ; \
	} \
	else \
	{ \
    	return 0 ; \
	}\
} \
static inline int __type_name ## _count(__type_name * fifo) \
{ \
	return fifo->count; \
} \
static inline int __type_name ## _add(__type_name * fifo,__data_type * data, int size) \
{ \
	int ret = 0; \
	int i; \
	\
	for(i=0; i<size; i++) \
	{ \
		 ret = __type_name ## _is_full(fifo);\
									\
		if( fifo->end == __size ) \
		{\
	    	fifo->end = 0;\
	    	if ( fifo->begin == fifo->end )\
				fifo->begin++;\
		}\
		\
		if( fifo->count && (fifo->end==fifo->begin) )\
		{ \
			fifo->begin++;\
			if ( fifo->begin == __size )\
				fifo->begin = 0;\
		}\
		\
		memcpy( &(fifo->tab[fifo->end]), &(data[i]), sizeof( __data_type ) ) ;\
		\
		fifo->end++;\
					\
		if (fifo->count != __size) fifo->count++;\
	}\
	return ret;\
} \
static inline int __type_name ## _retrieve(__type_name * fifo, __data_type * data, int size) \
{ \
	int i; \
	for(i=0; i<size;i++) \
	{ \
		if (__type_name ## _is_empty(fifo)) \
			return (i); \
		\
		if ( fifo->begin == __size ) \
			fifo->begin = 0; \
		\
		memcpy(&(data[i]), &( fifo->tab[fifo->begin]) ,sizeof( __data_type ) ); \
		\
		fifo->begin++; \
		\
		fifo->count--;\
	}\
	return size;\
} \
static inline unsigned int __type_name ## _max(void) \
{ \
	return __size; \
}


#endif /*FIFO_H_*/
