C语言队列-FIFO

app_FIFO.h

#include "main.h"
#include "app_FIFO.h"

#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) < (b) ? (b) : (a))

#ifndef TRUE
#define TRUE  1
#endif
#ifndef FALSE
#define FALSE 0
#endif

#define SUCCESS				1
#define ERROR_NO_MEM		    0
#define ERROR_INVALID_LENGTH    		0


#define FIFO_LENGTH()           (p_fifo->Count)
#define IS_POWER_OF_TWO(SIZE)   is_power_of_2(SIZE)

/* 
判断数字是否是2的次幂
 */
#ifdef FIFI_2_POWER
static __INLINE uint8_t is_power_of_2(uint16_t n)
{
	return (n != 0 && ((n & (n - 1)) == 0));
}
#endif

/* 
计算队列的长度
 */
static __INLINE uint16_t fifo_length(FIFO_T * p_fifo)
{
    // uint16_t tmp = p_fifo->read_pos;
    // return p_fifo->write_pos - tmp;

    return p_fifo->Count;
}
/* 队列未使用的空间 */
static __INLINE uint16_t fifo_unused(FIFO_T *fifo)
{
#ifdef FIFI_2_POWER
	return (fifo->buf_size_mask + 1) - (fifo->write_pos - fifo->read_pos);
#else
    return fifo->write_pos - fifo->read_pos;
#endif
    
}


/**
 * @brief	写新数据到缓冲区
 * @param	p_fifo	: 指向队列的的实例
 * @param	m_pBuf: 队列指向的缓冲区
 * @param   buf_size: 队列的大小
 * @return	>0:成功 ; 0:失败
 */
int  FIFO_Init( FIFO_T* p_fifo ,uint8_t* m_pBuf ,uint16_t buf_size)
{
	if(!m_pBuf )return ERROR_NO_MEM;
	if(!buf_size)return ERROR_NO_MEM;

#ifdef FIFI_2_POWER
    // Check that the buffer size is a power of two.
    if (!IS_POWER_OF_TWO(buf_size))
    {
        return ERROR_INVALID_LENGTH;
    }

    /* 到这一步,buf_size_mask应该是除了最高bit位是0,其它全是1 */
    p_fifo->buf_size_mask = buf_size - 1;
#endif

	p_fifo->p_buf = m_pBuf;					/*缓冲区指针 */
	p_fifo->buf_size = buf_size;	

	p_fifo->read_pos = 0;
	p_fifo->write_pos = 0;			
	p_fifo->Count = 0;

    return SUCCESS;
}


//----------------static-------------------------------------------------------------
/**
 * @brief	查看指定位置的数据
 * @param	p_fifo	: 指向队列的的实例
 * @param	index: 队列的索引(下标)
 * @param   p_byte: 接收查看的数据指针
 */
static __INLINE void fifo_peek(FIFO_T * p_fifo, uint16_t index, uint8_t * p_byte)
{
#ifdef FIFI_2_POWER
    *p_byte = p_fifo->p_buf[(p_fifo->read_pos + index) & p_fifo->buf_size_mask];
#else
    
    *p_byte = p_fifo->p_buf[ index ];

#endif

}

/**
* @brief	从队列里取出一个数据,新读数据指针
* @param	p_fifo	: 指向队列的的实例
* @param   p_byte: 存放取出的数据
*/
static __INLINE void fifo_get(FIFO_T * p_fifo, uint8_t * p_byte)
{
//    fifo_peek(p_fifo, 0, p_byte);
	*p_byte = p_fifo->p_buf[ p_fifo->read_pos ];
	
    // p_fifo->read_pos++;
	p_fifo->read_pos = (++p_fifo->read_pos)%p_fifo->buf_size;
	p_fifo->Count -=1;

}


/**
* @brief	向队列里写入一个数据,新写数据指针
* @param	p_fifo	: 指向队列的的实例
* @param   byte: 要写入的数据
*/
static __INLINE void fifo_Input(FIFO_T * p_fifo, uint8_t byte)
{
#ifdef FIFI_2_POWER
    p_fifo->p_buf[p_fifo->write_pos & p_fifo->buf_size_mask] = byte;
#else
    p_fifo->p_buf[p_fifo->write_pos ] = byte;
#endif
    // p_fifo->write_pos++;
    p_fifo->write_pos = (++p_fifo->write_pos)%p_fifo->buf_size;
	// if(++p_fifo->write_pos >=p_fifo->buf_size)
	// {
	// 	p_fifo->write_pos =p_fifo->buf_size;
	// }
	p_fifo->Count+=1;
}

//====================================================================
/**
* @brief	如果队列还没满,就写入一个数据
* @param	p_fifo	: 指向队列的的实例
* @param   byte: 要写入的数据
* @return	>0:成功 ; =0:失败
* @remark  会更新写数据指针
*/
int app_fifo_Input(FIFO_T * p_fifo, uint8_t byte)
{
#ifdef FIFI_2_POWER
    if (FIFO_LENGTH() <= p_fifo->buf_size_mask)
#else
    if (FIFO_LENGTH() <= p_fifo->buf_size)
#endif
    {
        fifo_Input(p_fifo, byte);
        return SUCCESS;
    }

    return ERROR_NO_MEM;
}


/**
 * @brief	如果队列长度不为0,就取出一个数据
 * @param	p_fifo	: 指向队列的的实例
 * @param   p_byte: 接收查看的数据指针
 * @return	>0:成功 ; =0:失败
 * @remark  会更新读数据指针
 */
int app_fifo_get(FIFO_T * p_fifo, uint8_t * p_byte)
{
    if (FIFO_LENGTH() != 0)
    {
        fifo_get(p_fifo, p_byte);
        return SUCCESS;
    }

    return ERROR_NO_MEM;

}


/**
 * @brief	查看指定位置的数据
 * @param	p_fifo	: 指向队列的的实例
 * @param	index: 队列的索引(下标)
 * @param   p_byte: 接收查看的数据指针
 * @return	>0:成功 ; =0:失败
 * @remark  不会更新数据指针
 */
int app_fifo_peek(FIFO_T * p_fifo, uint16_t index, uint8_t * p_byte)
{
    if (FIFO_LENGTH() > index)
    {
        fifo_peek(p_fifo, index, p_byte);
        return SUCCESS;
    }

    return ERROR_NO_MEM;
}

//=============================================================

/**
 * @brief	写新数据到缓冲区
 * @param	p_fifo	: 指向队列的的实例
 * @param	m_pBuf: 队列指向的缓冲区
 * @param   p_size: 传入要读取的长度,返回读成功的长度,必须是变量(非常量)
 * @return	>0:成功 ; 0:失败
 */
int app_fifo_read(FIFO_T * p_fifo, uint8_t * p_byte_array, uint16_t * p_size)
{

    if(!p_fifo )return ERROR_NO_MEM;
    if(!p_size)return ERROR_NO_MEM;

    const uint16_t byte_count    = FIFO_LENGTH();//队列的长度
    const uint16_t requested_len = (*p_size);//取出的长度
    uint16_t       index         = 0;
    uint16_t       read_size     = MIN(requested_len, byte_count);//能取出的长度

    (*p_size) = byte_count;

    // Check if the FIFO is empty.
    // if (byte_count == 0)
    if (p_fifo->Count==0)
    {
        return ERROR_NO_MEM;
    }

    // Check if application has requested only the size.
    if (p_byte_array == NULL)
    {
        return ERROR_NO_MEM;
    }

    // Fetch bytes from the FIFO.
    while (index < read_size)
    {
        fifo_get(p_fifo, &p_byte_array[index++]);
    }

    (*p_size) = read_size;

    return SUCCESS;
}


/**
 * @brief	写新数据到缓冲区
 * @param	p_fifo	: 指向环形缓冲区的实例
 * @param	p_byte_array: 指向要写入环形缓冲区的数据地址
 * @param   p_size: 要写入前传入的数量,成功后写入的数量,必须是变量的地址
 * @return	1:成功写入; 0:写入失败 ;
 * @remark  此功能会更新队列,p_size返回成功写入的数量
 */
int app_fifo_write(FIFO_T * p_fifo, uint8_t const * p_byte_array, uint16_t * p_size)
{
    if(!p_fifo)return ERROR_NO_MEM;
    if(!p_size)return ERROR_NO_MEM;
#ifdef FIFI_2_POWER
    const uint16_t available_count = p_fifo->buf_size_mask - fifo_length(p_fifo) + 1;
#else
    const uint16_t available_count = p_fifo->buf_size - FIFO_LENGTH() ;
#endif
    const uint16_t requested_len   = (*p_size);
    uint16_t       index           = 0;
    uint16_t       write_size      = MIN(requested_len, available_count);

    (*p_size) = available_count;

    // Check if the FIFO is FULL.
    // if (available_count == 0)
    if (p_fifo->Count==p_fifo->buf_size)
    {
        return ERROR_NO_MEM;
    }

    // Check if application has requested only the size.
    if (p_byte_array == NULL)
    {
        return ERROR_NO_MEM;
    }

    //Fetch bytes from the FIFO.
    while (index < write_size)
    {
        fifo_Input(p_fifo, p_byte_array[index++]);
    }

    (*p_size) = write_size;

    return SUCCESS;
}

app_FIFO.c


#include "main.h"
#include "app_FIFO.h"

#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) < (b) ? (b) : (a))

#ifndef TRUE
#define TRUE  1
#endif
#ifndef FALSE
#define FALSE 0
#endif

#define SUCCESS				1
#define ERROR_NO_MEM		    0
#define ERROR_INVALID_LENGTH    		0


#define FIFO_LENGTH()           (p_fifo->Count)
#define IS_POWER_OF_TWO(SIZE)   is_power_of_2(SIZE)

/* 
判断数字是否是2的次幂
 */
#ifdef FIFI_2_POWER
static __INLINE uint8_t is_power_of_2(uint16_t n)
{
	return (n != 0 && ((n & (n - 1)) == 0));
}
#endif

/* 
计算队列的长度
 */
static __INLINE uint16_t fifo_length(FIFO_T * p_fifo)
{
    // uint16_t tmp = p_fifo->read_pos;
    // return p_fifo->write_pos - tmp;

    return p_fifo->Count;
}
/* 队列未使用的空间 */
static __INLINE uint16_t fifo_unused(FIFO_T *fifo)
{
#ifdef FIFI_2_POWER
	return (fifo->buf_size_mask + 1) - (fifo->write_pos - fifo->read_pos);
#else
    return fifo->write_pos - fifo->read_pos;
#endif
    
}


/**
 * @brief	写新数据到缓冲区
 * @param	p_fifo	: 指向队列的的实例
 * @param	m_pBuf: 队列指向的缓冲区
 * @param   buf_size: 队列的大小
 * @return	>0:成功 ; 0:失败
 */
int  FIFO_Init( FIFO_T* p_fifo ,uint8_t* m_pBuf ,uint16_t buf_size)
{
	if(!m_pBuf )return ERROR_NO_MEM;
	if(!buf_size)return ERROR_NO_MEM;

#ifdef FIFI_2_POWER
    // Check that the buffer size is a power of two.
    if (!IS_POWER_OF_TWO(buf_size))
    {
        return ERROR_INVALID_LENGTH;
    }

    /* 到这一步,buf_size_mask应该是除了最高bit位是0,其它全是1 */
    p_fifo->buf_size_mask = buf_size - 1;
#endif

	p_fifo->p_buf = m_pBuf;					/*缓冲区指针 */
	p_fifo->buf_size = buf_size;	

	p_fifo->read_pos = 0;
	p_fifo->write_pos = 0;			
	p_fifo->Count = 0;

    return SUCCESS;
}


//----------------static-------------------------------------------------------------
/**
 * @brief	查看指定位置的数据
 * @param	p_fifo	: 指向队列的的实例
 * @param	index: 队列的索引(下标)
 * @param   p_byte: 接收查看的数据指针
 */
static __INLINE void fifo_peek(FIFO_T * p_fifo, uint16_t index, uint8_t * p_byte)
{
#ifdef FIFI_2_POWER
    *p_byte = p_fifo->p_buf[(p_fifo->read_pos + index) & p_fifo->buf_size_mask];
#else
    
    *p_byte = p_fifo->p_buf[ index ];

#endif

}

/**
* @brief	从队列里取出一个数据,新读数据指针
* @param	p_fifo	: 指向队列的的实例
* @param   p_byte: 存放取出的数据
*/
static __INLINE void fifo_get(FIFO_T * p_fifo, uint8_t * p_byte)
{
//    fifo_peek(p_fifo, 0, p_byte);
	*p_byte = p_fifo->p_buf[ p_fifo->read_pos ];
	
    // p_fifo->read_pos++;
	p_fifo->read_pos = (++p_fifo->read_pos)%p_fifo->buf_size;
	p_fifo->Count -=1;

}


/**
* @brief	向队列里写入一个数据,新写数据指针
* @param	p_fifo	: 指向队列的的实例
* @param   byte: 要写入的数据
*/
static __INLINE void fifo_Input(FIFO_T * p_fifo, uint8_t byte)
{
#ifdef FIFI_2_POWER
    p_fifo->p_buf[p_fifo->write_pos & p_fifo->buf_size_mask] = byte;
#else
    p_fifo->p_buf[p_fifo->write_pos ] = byte;
#endif
    // p_fifo->write_pos++;
    p_fifo->write_pos = (++p_fifo->write_pos)%p_fifo->buf_size;
	// if(++p_fifo->write_pos >=p_fifo->buf_size)
	// {
	// 	p_fifo->write_pos =p_fifo->buf_size;
	// }
	p_fifo->Count+=1;
}

//====================================================================
/**
* @brief	如果队列还没满,就写入一个数据
* @param	p_fifo	: 指向队列的的实例
* @param   byte: 要写入的数据
* @return	>0:成功 ; =0:失败
* @remark  会更新写数据指针
*/
int app_fifo_Input(FIFO_T * p_fifo, uint8_t byte)
{
#ifdef FIFI_2_POWER
    if (FIFO_LENGTH() <= p_fifo->buf_size_mask)
#else
    if (FIFO_LENGTH() <= p_fifo->buf_size)
#endif
    {
        fifo_Input(p_fifo, byte);
        return SUCCESS;
    }

    return ERROR_NO_MEM;
}


/**
 * @brief	如果队列长度不为0,就取出一个数据
 * @param	p_fifo	: 指向队列的的实例
 * @param   p_byte: 接收查看的数据指针
 * @return	>0:成功 ; =0:失败
 * @remark  会更新读数据指针
 */
int app_fifo_get(FIFO_T * p_fifo, uint8_t * p_byte)
{
    if (FIFO_LENGTH() != 0)
    {
        fifo_get(p_fifo, p_byte);
        return SUCCESS;
    }

    return ERROR_NO_MEM;

}


/**
 * @brief	查看指定位置的数据
 * @param	p_fifo	: 指向队列的的实例
 * @param	index: 队列的索引(下标)
 * @param   p_byte: 接收查看的数据指针
 * @return	>0:成功 ; =0:失败
 * @remark  不会更新数据指针
 */
int app_fifo_peek(FIFO_T * p_fifo, uint16_t index, uint8_t * p_byte)
{
    if (FIFO_LENGTH() > index)
    {
        fifo_peek(p_fifo, index, p_byte);
        return SUCCESS;
    }

    return ERROR_NO_MEM;
}

//=============================================================

/**
 * @brief	写新数据到缓冲区
 * @param	p_fifo	: 指向队列的的实例
 * @param	m_pBuf: 队列指向的缓冲区
 * @param   p_size: 传入要读取的长度,返回读成功的长度,必须是变量(非常量)
 * @return	>0:成功 ; 0:失败
 */
int app_fifo_read(FIFO_T * p_fifo, uint8_t * p_byte_array, uint16_t * p_size)
{

    if(!p_fifo )return ERROR_NO_MEM;
    if(!p_size)return ERROR_NO_MEM;

    const uint16_t byte_count    = FIFO_LENGTH();//队列的长度
    const uint16_t requested_len = (*p_size);//取出的长度
    uint16_t       index         = 0;
    uint16_t       read_size     = MIN(requested_len, byte_count);//能取出的长度

    (*p_size) = byte_count;

    // Check if the FIFO is empty.
    // if (byte_count == 0)
    if (p_fifo->Count==0)
    {
        return ERROR_NO_MEM;
    }

    // Check if application has requested only the size.
    if (p_byte_array == NULL)
    {
        return ERROR_NO_MEM;
    }

    // Fetch bytes from the FIFO.
    while (index < read_size)
    {
        fifo_get(p_fifo, &p_byte_array[index++]);
    }

    (*p_size) = read_size;

    return SUCCESS;
}


/**
 * @brief	写新数据到缓冲区
 * @param	p_fifo	: 指向环形缓冲区的实例
 * @param	p_byte_array: 指向要写入环形缓冲区的数据地址
 * @param   p_size: 要写入前传入的数量,成功后写入的数量,必须是变量的地址
 * @return	1:成功写入; 0:写入失败 ;
 * @remark  此功能会更新队列,p_size返回成功写入的数量
 */
int app_fifo_write(FIFO_T * p_fifo, uint8_t const * p_byte_array, uint16_t * p_size)
{
    if(!p_fifo)return ERROR_NO_MEM;
    if(!p_size)return ERROR_NO_MEM;
#ifdef FIFI_2_POWER
    const uint16_t available_count = p_fifo->buf_size_mask - fifo_length(p_fifo) + 1;
#else
    const uint16_t available_count = p_fifo->buf_size - FIFO_LENGTH() ;
#endif
    const uint16_t requested_len   = (*p_size);
    uint16_t       index           = 0;
    uint16_t       write_size      = MIN(requested_len, available_count);

    (*p_size) = available_count;

    // Check if the FIFO is FULL.
    // if (available_count == 0)
    if (p_fifo->Count==p_fifo->buf_size)
    {
        return ERROR_NO_MEM;
    }

    // Check if application has requested only the size.
    if (p_byte_array == NULL)
    {
        return ERROR_NO_MEM;
    }

    //Fetch bytes from the FIFO.
    while (index < write_size)
    {
        fifo_Input(p_fifo, p_byte_array[index++]);
    }

    (*p_size) = write_size;

    return SUCCESS;
}

测试程序
app_FIFO_test.h

#include "main.h"
#include "app_FIFO.h"
#include "stdio.h"

#define BUFSIZE			20
#define FIFO_BUFSIZE	10

uint8_t wBuf[BUFSIZE];
uint8_t rBuf[BUFSIZE];
uint8_t testdat[30];
uint8_t* pBuf;



FIFO_T txfifo;
uint16_t num=0;

void FIFO_tsetMain()
{
	pBuf=rBuf;
	for (size_t i = 0; i < BUFSIZE*2; i++)
		testdat[i]=i+1;

	FIFO_Init(&txfifo,wBuf,FIFO_BUFSIZE);

	uint8_t a=99;
	/*向 wBuf 写入99
	 write_pos 是1*/
	app_fifo_Input(&txfifo,a);
	/*向指向的队列写入3个数据,向 wBuf 写入1,2,3
	 write_pos 是4
	*/
	num=3;
	app_fifo_write(&txfifo,testdat,&num);

	/*向队列写入10个数据,已经超过队列的大小
	已经写入了3个这里其实只能写入6个,num将返回6,
	write_pos 是0
	*/
	num=10;
	if(app_fifo_write(&txfifo,testdat,&num) )
	 printf("成功写入 %d 个\r\n",num);

	/* 再向队列写入3个,
	队列已满,写入失败
	 */
	num=3;
	if(!app_fifo_write(&txfifo,testdat,&num) )
		printf("写入失败\r\n");

	/*读取一个数
	读数据指针是 1,
	写数据指针是 0 
	*/
	if(app_fifo_get(&txfifo,pBuf) )
	{
		printf("取出一个数 %d\r\n",*pBuf);
		pBuf+=1;
	}
	
	/* 
	查看位置是3的数据
	 */
	uint8_t pos =3,r=0;
	if(app_fifo_peek(&txfifo,pos,&r) )
		printf("位置%d的数是 %d\r\n",pos,r);

	/*
	取出3个数据,放在 rBuf[]中,
	读数据指针是 4,
	写数据指针是 0
	  */
	uint16_t n=3;
	if(app_fifo_read(&txfifo,pBuf,&n) )
	{
		printf("成功取出 %d 个\r\n",n);
		printf("读数据指针 %d 个\r\n",txfifo.read_pos);
		printf("写数据指针 %d 个\r\n",txfifo.write_pos);
		pBuf+=n;
	}

	/*
	取出10个数据,放在 rBuf[]中,
	实际可读取空间只有6个,
	读数据指针是 6+4,
	写数据指针是 0
	  */
	n=10;
	if(app_fifo_read(&txfifo,pBuf,&n) )
	{
		printf("成功取出 %d 个\r\n",n);
		printf("读数据指针 %d 个\r\n",txfifo.read_pos);
		printf("写数据指针 %d 个\r\n",txfifo.write_pos);
		pBuf+=n;
	}
//---------------------------------------------------------------

	num=7;
	if(app_fifo_write(&txfifo,testdat,&num))
	{
		printf("成功写入%d个",num);
		printf("读数据指针 %d 个\r\n",txfifo.read_pos);
		printf("写数据指针 %d 个\r\n",txfifo.write_pos);

	}

	num=3;
	pBuf=rBuf;
	if(app_fifo_read(&txfifo,pBuf,&num) )
	{
		printf("成功取出 %d 个\r\n",num);
		printf("读数据指针 %d 个\r\n",txfifo.read_pos);
		printf("写数据指针 %d 个\r\n",txfifo.write_pos);
		pBuf+=num;
	}

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值