万能的FIFO篇

简介: 万能的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;
  }
}
相关文章
|
7月前
|
设计模式 安全 Java
【Linux 系统】多线程(生产者消费者模型、线程池、STL+智能指针与线程安全、读者写者问题)-- 详解
【Linux 系统】多线程(生产者消费者模型、线程池、STL+智能指针与线程安全、读者写者问题)-- 详解
|
7月前
|
算法 编译器 C语言
【C/C++ 编程题 02】用两个栈实现一个队列的功能
【C/C++ 编程题 02】用两个栈实现一个队列的功能
53 0
|
7月前
|
算法 数据安全/隐私保护 C++
【C/C++ 编程题 03】用两个栈实现一个队列的功能
【C/C++ 编程题 03】用两个栈实现一个队列的功能
33 0
|
前端开发 芯片
【芯片前端】保持代码手感——握手型同步FIFO设计
【芯片前端】保持代码手感——握手型同步FIFO设计
|
存储 缓存 C语言
FIFO基础知识
本文介绍了什么是FIFO,FIFO的用途、功能和重要参数。最后,利用C语言数组实现了FIFO,给出了详细的程序设计。
136 0
|
前端开发 芯片
【芯片前端】保持代码手感——同步FIFO
【芯片前端】保持代码手感——同步FIFO
|
存储 前端开发 芯片
【芯片前端】保持代码手感——异步FIFO全解析
【芯片前端】保持代码手感——异步FIFO全解析
102 0
|
前端开发 调度 芯片
【芯片前端】根据数据有效选择输出的握手型FIFO结构探究
【芯片前端】根据数据有效选择输出的握手型FIFO结构探究
|
缓存 算法 数据库
【算法】FIFO先来先淘汰算法分析和编码实战
【算法】FIFO先来先淘汰算法分析和编码实战
【算法】FIFO先来先淘汰算法分析和编码实战
【异步FIFO的一些小事·0】异步FIFO同步化设计
【异步FIFO的一些小事·0】异步FIFO同步化设计
159 0
【异步FIFO的一些小事·0】异步FIFO同步化设计