万能的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;
}
}