万能的FIFO篇

前言

   在计算机中,先入先出队列是一种传统的按序执行方法,先进入的指令先完成并引退,跟着才执行第二条指令(指令就是计算机在响应用户操作的程序代码,对用户而言是透明的)。当CPU在某一时段来不及响应所有的指令时,指令就会被安排在FIFO队列中,比如0号指令先进入队列,接着是1号指令、2号指令……当CPU完成当前指令以后就会从队列中取出0号指令先行执行,此时1号指令就会接替0号指令的位置,同样,2号指令、3号指令……都会向前挪一个位置。
   在数据处理上也是同理,所以引入了万能的FIFO篇,可移植性强,更便于我们工程中处理数据(感谢前辈,顺手牵羊~)

lib_fifo.h

/**
 * @ 摘要:
 * 
 * @file lib_fifo.h
 * @author xin.han
 * @ 完成日期: 2021-02-07
 */

#ifndef __LIB_FIFO_H__
#define __LIB_FIFO_H__

#ifdef __cplusplus
extern "C"{
    
    
#endif

#include "lib_cfg.h"

#define pri_min(x,y) ((x) < (y) ? (x) : (y)) /*x和y取小值*/
#define pri_max(x,y) ((x) > (y) ? (x) : (y)) /*x和y取大值*/

/*
 * 1. size/in/out type must be unsinged
 * 2. in/out type must be same
 * 3. size must be pow o two
 * */

/*fifo数据结构 缓冲区指针,换成去长度,写入缓冲区指针,读取缓冲区指针*/
typedef struct 
{
    
    
	INT8U *buffer;
	INT16U size;
	volatile INT16U in;
	volatile INT16U out;
}/*__attribute__((packed))*/ FIFO, *pFIFO;
/***********************************************************
 * fifo缓冲区初始化
 * @param fifo缓冲区指针
 * @param 分配空间数组指针
 * @param 分配空间长度
 * @return 初始化是否正确 1正确 0错误
 */
BOOLEAN FifoInit( pFIFO ,INT8U * ,INT16U );
/*************************************************************
 * 释放fifo缓冲区 fifo指针为空
 * @param fifo缓冲区指针
 */
void FifoCancel( pFIFO );
/*************************************************************
 * 清空fifo缓冲区 将fifo缓冲区数据清空
 * @param
 */
void FifoClear( pFIFO );
/***************************************************************
 * 写入fifo缓冲区,将已知长度的数据写入fifo缓冲区
 * @param fifo缓冲区指针
 * @param 数据区指针
 * @param 数据长度
 * @return写入数据长度
 */
INT16U FifoWrite( pFIFO , INT8U *, INT16U );
/***************************************************************
 * 读取fifo缓冲区数据,从fifo缓冲区读取已知长度的数据放入数据区
 * @param fifo缓冲区指针
 * @param 数据区指针
 * @param 要读取数据长度
 * @return 读取数据的长度
 */
INT16U FifoRead( pFIFO , INT8U *, INT16U );
/****************************************************************
 * 获取fifo缓冲区剩余空间大小
 * @param fifo缓冲区指针
 * @return fifo缓冲区剩余空间大小
 */
INT16U FifoGetFreeSize( pFIFO );
/*****************************************************************
 * 获取fifo缓冲区存储数据长度
 * @param fifo缓冲区指针
 * @return fifo缓冲区存储数据长度
 */
INT16U FifoGetDataSize( pFIFO );
/******************************************************************
 * 向fifo写入一个字节数据
 * @param fifo缓冲区指针
 * @param 要写入的数据值
 * @return 返回0 写入失败,返回1 写入成功
 */
INT16U FifoWriteByte(  pFIFO , INT8U );
/******************************************************************
 * 从fifo读取一个字节数据
 * @param fifo缓冲区指针
 * @param 读取数据存放地址
 * @return 返回0 读取失败,返回1 读取成功
 */
INT16U FifoReadByte(  pFIFO , INT8U *);


#ifdef __cplusplus
}
#endif


#endif

lib_fifo.c

/**
 * @ 摘要:
 * 
 * @file lib_fifo.c
 * @author xin.han
 * @ 完成日期: 2021-02-07
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "lib_fifo.h"

/*******************************************************
 * 查找2的整次幂最大数
 * @param size
 * @return
 */
static INT16U roundup_pow_of_two(INT16U size)
{
    
    
	int l;
	int i;
	//如果数据个数为0则返回错误
	if(size == 0)
		return 0;
	//字节个数乘以8 = 32
	l = sizeof(size)*8;

	// if pow of two, bin format:inlcude one bit-1
	//如果size是2的整次幂,则返回size
	if (!(size & (size - 1)))
		return size;

	//4INT8Us max (pow of two) is 0x8000
	//如果size大于等于0x8000,返回0x8000
	if (size >= 0x8000)
		return 0x8000;

	//l - 2: exclude 0x8000
	//从size最高位查询,找出为1的最高位,则返回的size也是2的整次幂
	for (i = l-2; i >= 0; i--) {
    
    
		if ((size >> i) == 1) {
    
    
			size = (1 << (i+1));
			//logwarn("i is %d\n", i);
			break;
		}
	}

	return size;
}
/********************************************************************
 * Fifo初始化 给fifo分配空间 并将fifo参数初始化
 * @param pfifo Fifo指针
 * @param pbyData 数据包指针
 * @param size 数据个数
 * @return
 */
BOOLEAN FifoInit(pFIFO pfifo, INT8U *pbyData, INT16U size)
{
    
    
	INT8U *buffer = NULL;//定义空指针

	// if not pow of two
	//如果数据个数不是2的整次幂
	if (size & (size - 1)){
    
    
		//logwarn("size is not pow of two, size is 0x%x\n", size);
		//找出size最大2的整次幂数
		size = roundup_pow_of_two( size );
		//如果大于等于最大要求值则返回错误
		if (size >= 0x8000){
    
    
			return FALSE;
		}
	}

	//check pfifo->in/out
	//如果fifo缓冲区的插入值类型与取出值类型不一样则返回错误
	if (sizeof(pfifo->in) != sizeof(pfifo->out))
	{
    
    
		// printf("sizeof(pfifo->in) != sizeof(pfifo->out)\n");
		return FALSE;
	}
	//给Fifo定义空间
	buffer = pbyData;//(INT8U *)malloc( size ); //calloc
	//如果缓冲区空间为0则返回错误
	if (!buffer){
    
    
		//logerr("malloc(%d) failed!\n", size);
		return FALSE;
	}

	//log("malloc() is ok, size is %d(0x%x)\n", size, size);
	//给fifo缓冲区赋值
	pfifo->buffer = buffer;
	pfifo->size = size;
	pfifo->in = pfifo->out = 0;

//	printf("FifoInit pfifo_buffer is %p\n",buffer);
//	printf("FifoInit pfifo_size is %d(0x%x)\n",size, size);

	return TRUE;
}
/*****************************************************************
 * 释放fifo缓冲区
 * @param pfifo
 */
void FifoCancel(pFIFO pfifo)
{
    
    
	//如果fifo缓冲区指针为空,则已经释放
	if (pfifo == NULL)
		return;
	//如果fifo缓冲区指向的空间不为空则需要释放空间,将指针赋值为空
	if (pfifo->buffer != NULL)
		pfifo->buffer = NULL;//free (pfifo->buffer);

	pfifo->size = 0;//缓冲区长度赋值为0
	pfifo->in = pfifo->out = 0;//fifo缓冲区的提取和插入标志赋值为0
}
/*******************************************************************
 * 清空fifo缓冲区
 * @param pfifo
 */
void FifoClear(pFIFO pfifo)
{
    
    
	//如果fifo缓冲区指针为空,则返回
	if (pfifo == NULL)
		return;
	//初始化fifo缓冲区提取和插入值
	pfifo->in = pfifo->out = 0;
}

/***********************************************************************
 * 写fifo缓冲区,将buffer数据写入fifo缓冲区
 * @param pfifo fifo指针
 * @param buffer 数据区指针
 * @param len 数据长度
 * @return
 */
INT16U FifoWrite(pFIFO pfifo, INT8U *buffer, INT16U len)   
{
    
      
	INT16U l;  
	/*如果fifo缓冲区指针为空 数据区指针为空 数据长度为0 则返回错误*/
	if (pfifo == NULL || buffer == NULL || len == 0)
		return FALSE;
	/*如果fifo缓冲区中的数据区指针为空返回错误*/
	if (pfifo->buffer == NULL)
		return FALSE;

	 
	/*选择数据长度和fifo缓冲区剩余空间长度中较小的值*/

	len = pri_min(len, pfifo->size - pfifo->in + pfifo->out);   

	/* first put the data starting from pfifo->in to buffer end */   
	l = pri_min(len, pfifo->size - (pfifo->in & (pfifo->size - 1)));   
	// printf("len is %d, l os %d, 2 is %d\n", len, l, (pfifo->in & (pfifo->size - 1)));
	/*先将数据插入到上次插入结束后的位置,插入直到fifo缓冲区最大值*/
	memcpy(pfifo->buffer + (pfifo->in & (pfifo->size - 1)), buffer, l);

	/* then put the rest (if any) at the beginning of the buffer */   
	/*然后将剩余的数据从fifo缓冲区开始位置插入*/
	memcpy(pfifo->buffer, buffer + l, len - l);

	/* Ensure that we add the INT8Us to the fifo before we update the pfifo->in index. */  
	 

	pfifo->in += len;   

	return len;   
}  
/*********************************************************************
 * 从fifo缓冲区提取数据
 * @param pfifo
 * @param buffer
 * @param len
 * @return
 */
INT16U FifoRead(pFIFO pfifo, INT8U *buffer, INT16U len)   
{
    
    
	INT16U l;  
	/*如果fifo缓冲区指针为空 数据区指针为空 数据长度为0 则返回错误*/
	if (pfifo == NULL || buffer == NULL || len == 0)
		return FALSE;
	/*如果fifo缓冲区中的数据区指针为空返回错误*/
	if (pfifo->buffer == NULL)
		return FALSE;

	 

	//选择fifo缓冲区有效数据长度和要读取的数据长度较小的值
	len = pri_min(len, pfifo->in - pfifo->out);   

//	printf("pri_min len is %d\n",len);

	/* Ensure that we sample the pfifo->in index -before- we start removing INT8Us from the fifo. */   
	 

	/* first get the data from pfifo->out until the end of the buffer */   
	/*读取数据是否跨过fifo缓冲区最大值*/
	l = pri_min(len, pfifo->size - (pfifo->out & (pfifo->size - 1)));

//	printf("pri_min l is %d\n",l);

	memcpy(buffer, pfifo->buffer + (pfifo->out & (pfifo->size - 1)), l);   

	/* then get the rest (if any) from the beginning of the buffer */   
	memcpy(buffer + l, pfifo->buffer, len - l);   

	/* Ensure that we remove the INT8Us from the fifo -before- we update the pfifo->out index. */   
	 

	pfifo->out += len;   

//	printf("return len is %d\n",len);

	return len;   
}  
/***************************************************************************
 * 获取fifo缓冲区剩余空间字节数
 * @param pfifo
 * @return
 */
INT16U FifoGetFreeSize(pFIFO pfifo)
{
    
    
	/*如果fifo缓冲区指针为空则返回0*/
	if (pfifo == NULL)
		return 0;
	/*否则返回fifo剩余空间字节数*/
	return (pfifo->size - pfifo->in + pfifo->out);
}
/****************************************************************************
 * 获取fifo存储数据字节数
 * @param pfifo
 * @return
 */
INT16U FifoGetDataSize(pFIFO pfifo)
{
    
    
	/*fifo缓冲区指针为空则返回0*/
	if (pfifo == NULL)
		return 0;
	/*否则返回fifo存储数据字节数*/
	return (pfifo->in - pfifo->out);
}
/*****************************************************************************
 *fifo写入单字节
 * @param pfifo
 * @param value
 * @return
 */
INT16U FifoWriteByte( pFIFO pfifo, INT8U value)
{
    
    	
	INT16U index;
	/*fifo缓冲区指针为空则返回0*/
	if (pfifo == NULL)
		return 0;
	/*如果fifo缓冲区中的数据区指针为空返回错误*/
	if (pfifo->buffer == NULL)
		return 0;
	/*如果fifo已没有剩余空间则返回0*/
	if (pfifo->size - pfifo->in + pfifo->out == 0 )
        	return 0;

		 
  /*找出要插入的位置*/
  index = pfifo->in & (pfifo->size - 1);
  /*将该字节数据写入缓冲区*/
  pfifo->buffer[ index ] = value;


  /*插入指针加1*/
  pfifo->in++;

  return 1;
}
/**********************************************************
 * fifo读取单字节数据
 * @param pfifo
 * @param buffer
 * @return
 */
INT16U FifoReadByte( pFIFO pfifo, INT8U *buffer)
{
    
    	
	INT16U index;
	/*fifo缓冲区指针为空则返回0*/
	if (pfifo == NULL || buffer == NULL)
		return 0;
	/*如果fifo缓冲区中的数据区指针为空返回错误*/
	if (pfifo->buffer == NULL)
		return 0;
	/*如果fifo已没有存储数据则返回0*/
  if ( pfifo->in - pfifo->out == 0 )
    return 0;
  /*找出要读取字节的位置*/
  index = pfifo->out & (pfifo->size - 1);

  *buffer = pfifo->buffer[ index ];

  pfifo->out++;

  return 1;
}



lib_ring.h

#ifndef __LIB_RING_H_
#define __LIB_RING_H_

#ifdef __cplusplus
extern "C"
{
    
    
#endif
  
#include "lib_cfg.h"

typedef struct 
{
    
    
  INT32U ticks;
  INT8U item_len;
  INT8U data[24];
} RING_ITEM;

typedef struct
{
    
    
  INT8U capacity;
  INT8U pToBuf;   /* offset from start of buffer where to write next */
  INT8U pFromBuf; /* offset from start of buffer where to read next */
  INT8U bufSize;  /* size of ring in bytes */
  RING_ITEM *buf;    /* pointer to start of buffer */
} RING_BUFFER, *pRING_BUFFER;

INT8U clearRingBuffer( RING_BUFFER *buffer );

INT8U IsEmpty( RING_BUFFER *buffer );
INT8U initRingBuffer( RING_BUFFER *buffer, INT8U capacity, RING_ITEM *items );
INT8U putRing( RING_BUFFER *buffer, RING_ITEM *item );
INT8U getRing( RING_BUFFER *buffer, RING_ITEM *dest_item );

#ifdef __cplusplus
}
#endif

#endif /* __LIB_RING_H_ */

lib_ring.c

#include <stdio.h>
#include <stdlib.h>
#include "lib_ring.h"


INT8U IsEmpty( RING_BUFFER *buffer )
{
    
    
  return buffer->bufSize == 0;
}

static INT8U IsFull( RING_BUFFER *buffer )
{
    
    
    return buffer->bufSize == buffer->capacity;
}
        
INT8U clearRingBuffer(RING_BUFFER *buffer)
{
    
    
  if (buffer == NULL) {
    
    
    return 0;
  }

  buffer->bufSize = 0;
  buffer->pFromBuf = 0;
  buffer->pToBuf = 0;

  return 1;
}

INT8U initRingBuffer(RING_BUFFER *buffer, INT8U capacity, RING_ITEM *items)
{
    
    
  if (items != (void *)0)
  {
    
    
    buffer->buf = items;
    buffer->capacity = capacity;
    
    clearRingBuffer(buffer);
    
    return 0;
  }
  else
  {
    
    
    return 1;
  }
}

static INT8U Succ( RING_BUFFER *buffer, INT8U Value )
{
    
    
    if( ++Value == buffer->capacity )
        Value = 0;
    return Value;
}

INT8U putRing( RING_BUFFER *buffer, RING_ITEM *item )
{
    
    
    if ( buffer == NULL || item == NULL ) {
    
    
      return 0;
    }

    if( IsFull( buffer ) )
    {
    
    
      return 0;
    }
    else
    {
    
    
        buffer->buf[ buffer->pToBuf ] = *item;
        buffer->pToBuf = Succ( buffer, buffer->pToBuf );
          
        buffer->bufSize++;
        return 1;
    }
}

INT8U getRing(RING_BUFFER *buffer, RING_ITEM *dest_item)
{
    
    
  if ( buffer == NULL || dest_item == NULL )
  {
    
    
    return 0;
  }
  if( IsEmpty( buffer ) )
  {
    
    
    return 0;
  }
  else
  {
    
    
    *dest_item = buffer->buf[ buffer->pFromBuf ];
    buffer->pFromBuf = Succ( buffer, buffer->pFromBuf );
    buffer->bufSize--;
    return 1;
  }
}

猜你喜欢

转载自blog.csdn.net/qq_42330920/article/details/113767852
今日推荐