解析机智云MCU源码

最近在搞了一块乐鑫的ESP826-12F模块,实现手机无线控制单片机,模块烧写的固件是机智云32M的,具体烧录过程就不说了,可参考这里http://club.gizwits.com/thread-3551-1-1.html,我这里解释一下源码吧。首先来介绍一下Utils/ ringbuffer,就是环形缓冲区,字面上理解,环形缓冲区,但实际并不是环形,只是模拟出来环形而已,因为内存地址是往一个方向增长的。
在这里插入图片描述
图1-内存增长图

先来看看ringbuffer.h
主要是用宏实现了一个求最小值的函数。
还有就是定义了一个环形缓冲区的结构体。

#define min(a, b) (a)<(b)?(a):(b)                   ///< Calculate the minimum value

typedef struct {
    
    
    size_t rbCapacity;
    uint8_t  *rbHead;
    uint8_t  *rbTail;
    uint8_t  *rbBuff;
}rb_t;

rb_t是环形缓冲区的结构体,rbCapacity为环形缓冲区的容量,指针rbHead指向头部,指针rbTail指向尾部,指针rbBuff指向缓冲区首地址,在创建缓冲区的时候,这些都会初始化。
缓冲区的创建

int8_t ICACHE_FLASH_ATTR rbCreate(rb_t* rb)
{
    
    
    if(NULL == rb)
    {
    
    
        return -1;
    }

    rb->rbHead = rb->rbBuff;
    rb->rbTail = rb->rbBuff;
    return 0;
}

这个是缓冲区的创建函数,这些开源的代码写的就是比较严谨,一进来首先判断指针是否为空,空的话直接返回(后面的函数也有,后面就不做解释了),这点值得我们学习,严谨,提高程序的健壮性,然后初始化头尾指针,均指向缓冲区首地址。初始化后的指向情况见下图
在这里插入图片描述
图二-初始化后指针指向

返回缓冲区的容量

int32_t ICACHE_FLASH_ATTR rbCapacity(rb_t *rb)
{
    
    
    if(NULL == rb)
    {
    
    
        return -1;
    }

    return rb->rbCapacity;
}

这个很容易理解,直接返回rbCapacity。

读取环形缓冲区可读数据大小

int32_t ICACHE_FLASH_ATTR rbCanRead(rb_t *rb)
{
    
    
    if(NULL == rb)
    {
    
    
        return -1;
    }

    if (rb->rbHead == rb->rbTail)
    {
    
    
        return 0;
    }

    if (rb->rbHead < rb->rbTail)
    {
    
    
        return rb->rbTail - rb->rbHead;
    }

    return rbCapacity(rb) - (rb->rbHead - rb->rbTail);
}

进来头尾指针是否相等,相等直接返回0,说明无数据可读,接着判断头指针是否小于尾指针,如果是,则直接返回rb->rbTail - rb->rbHead,头尾指针直接相减即为可读数据大小
在这里插入图片描述
图三-尾指针大于头指针结构图

如果都不满足,即返回rbCapacity(rb) - (rb->rbHead - rb->rbTail); 缓冲区的容量-(头指针-尾指针)下图实例:21-(7-2)=16
在这里插入图片描述
图四-头指针大于尾指针结构图

获取缓冲区可写数据区大小

int32_t ICACHE_FLASH_ATTR rbCanWrite(rb_t *rb)
{
    
    
    if(NULL == rb)
    {
    
    
        return -1;
    }

    return rbCapacity(rb) - rbCanRead(rb);  //总容量减去-可读数据区大小
}

读缓冲区数据
rb:准备读的缓冲区
data:读取数据的保存地址
count:要读取的个数

int32_t ICACHE_FLASH_ATTR rbRead(rb_t *rb, void *data, size_t count)
{
    
    
    int32_t copySz = 0;

    if(NULL == rb)
    {
    
    
        return -1;
    }

    if(NULL == data)
    {
    
    
        return -1;
    }

    if (rb->rbHead < rb->rbTail)			//结合图三
    {
    
    
        copySz = min(count, rbCanRead(rb)); //取出要读的数据长度,这里min避免过渡读取,
        memcpy(data, rb->rbHead, copySz); //读取数据到date
        rb->rbHead += copySz;			//移动头指针
        return copySz;					//返回读取的个数
    }
    else	  //结合图四
    {
    
    
        if (count < rbCapacity(rb)-(rb->rbHead - rb->rbBuff)) //判断count<21-(7-0)
        {
    
    
            copySz = count;
            memcpy(data, rb->rbHead, copySz);		//读取数据到date
            rb->rbHead += copySz;				//移动头指针
            return copySz;						//返回读取的个数
        }
        else       			// count>=20-(7-0)
        {
    
    
            copySz = rbCapacity(rb) - (rb->rbHead - rb->rbBuff); // copySz = 21-(7-0)
            memcpy(data, rb->rbHead, copySz); 			//读取数据到date
            rb->rbHead = rb->rbBuff; 		//移动头指针,指向缓冲区首地址,
            copySz += rbRead(rb, (char*)data+copySz, count-copySz); //递归调用rbRead
            return copySz;
        }
    }
}

这里我们假设缓冲区大小为21,方便讲解。
写缓冲区数据
rb:准备写的缓冲区
data:数据的保存地址
count:要写的个数
既然理解了读取数据,那么写数据写数据就是相反的过程,这里,交给你们自己解决,结合上面的图,一步一步啃,很简单的。

int32_t ICACHE_FLASH_ATTR rbWrite(rb_t *rb, const void *data, size_t count)
{
    
    
    int32_t tailAvailSz = 0;

    if((NULL == rb)||(NULL == data))
    {
    
    
        return -1;
    }

    if (count >= rbCanWrite(rb))
    {
    
    
        return -2;
    }

    if (rb->rbHead <= rb->rbTail)
    {
    
    
        tailAvailSz = rbCapacity(rb) - (rb->rbTail - rb->rbBuff);
        if (count <= tailAvailSz)
        {
    
    
            memcpy(rb->rbTail, data, count);
            rb->rbTail += count;
            if (rb->rbTail == rb->rbBuff+rbCapacity(rb))
            {
    
    
                rb->rbTail = rb->rbBuff;
            }
            return count;
        }
        else
        {
    
    
            memcpy(rb->rbTail, data, tailAvailSz);
            rb->rbTail = rb->rbBuff;

            return tailAvailSz + rbWrite(rb, (char*)data+tailAvailSz, count-tailAvailSz);
        }
    }
    else
    {
    
    
        memcpy(rb->rbTail, data, count);
        rb->rbTail += count;
        return count;
    }
}

今天就先介绍环形缓冲区,有什么问题可以留言,或者发邮件[email protected]

猜你喜欢

转载自blog.csdn.net/weixin_42163707/article/details/106414557