前言
在计算机中,先入先出队列是一种传统的按序执行方法,先进入的指令先完成并引退,跟着才执行第二条指令(指令就是计算机在响应用户操作的程序代码,对用户而言是透明的)。当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; } }