收藏官网首页

微信宠物屋v2.3源码分析+RingBuffer源代码分析

查看数: 24483 | 评论数: 17 | 收藏 9
关灯 | 提示:支持键盘翻页<-左 右->
    组图打开中,请稍候......
发布时间: 2016-4-13 02:40

正文摘要:

这是我在ickey论坛发布的帖子。板子在ickey申请到的。。。 就不再重新整理编辑了,直接给大家带注释的源码和文档。 有兴趣的可以去icKey找132654这个用户的帖子 要是有人说,不是这个问题,只能说明你还没碰到 ...

回复

WM_CH 发表于 2016-7-25 15:41:10
【机智云Gokit开发套件试用体验】+ RingBuffer源代码分析

大家都知道,环形缓冲区是比较常用的数据结构,正好机智云“微信宠物屋源代码v2.3”中也用到了。
下面给大家分析一下。

首先是数据结构:
“RingBuffer.h”
注意是head指向了读区域,tail指向了写区域!
注意是head指向了读区域,tail指向了写区域!
注意是head指向了读区域,tail指向了写区域!
  1. typedef struct {
  2. size_t rb_capacity; //缓冲区容量
  3. char *rb_head; //用于读出的指针
  4. char *rb_tail; //用于写入的指针
  5. char rb_buff[256]; //缓冲区实体
  6. }RingBuffer;
复制代码

下面分析他的几个函数:
“RingBuffer.c”

  1. //用来比较最小值的宏
  2. #define min(a, b) (a)<(b)?(a)b)

  3. //新建RingBuffer,给成员赋值
  4. //MAX_RINGBUFFER_LEN 这个宏,被定义为"P0数据最大长度"的2倍
  5. //head/tail 两个指针,都指向缓冲区实体(数组rb_buff)的首地址
  6. void rb_new(RingBuffer* rb)
  7. {
  8. rb->rb_capacity = MAX_RINGBUFFER_LEN; //capacity;
  9. rb->rb_head = rb->rb_buff;
  10. rb->rb_tail = rb->rb_buff;
  11. };
复制代码

获得缓冲区总容量Capacity:
  1. size_t rb_capacity(RingBuffer *rb)
  2. {
  3. return rb->rb_capacity;
  4. }
复制代码

获得缓冲区可读区域,返回可读区域大小:
三种情况:
1、head与tail都指向同一个地方时,可读区域大小为0【这种情况只会在缓冲区还未使用时出现,
开始使用之后,不会出现head/tail重合的现象,即tail永远不会等于head,否则head指向的数据还未读走就被覆盖了!】
2、head < tail  ,说明tail没有写到缓冲区末尾,从缓冲区开头重新开始。可读的区域自然为(tail - head)
3、head > tail  ,说明tail已经从缓冲区末尾写完,并从开头处重新准备写了。
插入图片给大家看看:
rb_buff是数组名,因此可以作为缓冲实体首地址的指针。

size_t     rb_can_read(RingBuffer *rb){    if (rb->rb_head == rb->rb_tail) return 0;    if (rb->rb_head < rb->rb_tail) return rb->rb_tail - rb->rb_head;    return rb_capacity(rb) - (rb->rb_head - rb->rb_tail);}

获得可写区域大小,就可以用总容量 减去 可读区域大小来计算了:

size_t     rb_can_write(RingBuffer *rb){    return rb_capacity(rb) - rb_can_read(rb);}

读数据,从head指向的地址开始,读到data指向的地址处,读count个数据。返回读的个数
三种情况:
1、head < tail  ,此时要从count 和"可读区域大小"中选一个较小的值,作为读操作的次数。避免了count 大于“可读区域”的错误。
2、head > tail  且 count 的个数 小于“从head到缓冲区末尾的数据个数”图中蓝色。直接复制内存,再修改head 指针即可。
3、head > tail  且 count 的个数 大于“从head到缓冲区末尾的数据个数”。
此时,先把从head到缓冲区末尾的值蓝色复制到data处,再把剩余的绿色复制过去。注意两个值:copy_sz 和*(data + copy_sz)如图
这种情况下,问题来了,要是绿色的区域超过了tail 怎么办?:)
所以,应该加了一个判断,这个在写操作中做了,但这里没做。即要读的个数count 要小于可读区域的大小。
不然会出现head > tail 但head 指向的数据以及head 后边的数据又不是有效数据,这个问题。
代码:

  1. size_t rb_can_read(RingBuffer *rb)
  2. {
  3. if (rb->rb_head == rb->rb_tail) return 0;
  4. if (rb->rb_head < rb->rb_tail) return rb->rb_tail - rb->rb_head;
  5. return rb_capacity(rb) - (rb->rb_head - rb->rb_tail);
  6. }


  7. 获得可写区域大小,就可以用总容量 减去 可读区域大小来计算了:

  8. size_t rb_can_write(RingBuffer *rb)
  9. {
  10. return rb_capacity(rb) - rb_can_read(rb);
  11. }
复制代码



写数据,把数据从data指向的地址,写到tail 指向的地址,写count个。返回写的个数。
这里进来直接判断,要写入的内容大小 要小于可写区域大小,防止造成数据覆盖。写入合法。
下面写入分了三种情况:
1、2 需要计算tail_avail_sz,这个值为tail 到缓冲区末尾的数据区域大小。
1、head < tail  ,count < tail_avail_sz  。直接复制内容。假如tail 到了缓冲区末尾,让tail 回到缓冲区首地址。
2、head < tail  ,count > tail_avail_sz  。先写入 tail_avail_sz 个数据,tail 回到缓冲区首地址,再写入剩余的部分。
3、head > tail  ,这种情况最简单,由于已经做了写入合法判断,所以直接复制内容,修改tail 即可。
代码:

  1. size_t rb_read(RingBuffer *rb, void *data, size_t count)
  2. {
  3. if (rb->rb_head < rb->rb_tail)
  4. {
  5. int copy_sz = min(count, rb_can_read(rb));
  6. memcpy(data, rb->rb_head, copy_sz);
  7. rb->rb_head += copy_sz;
  8. return copy_sz;
  9. }
  10. else
  11. {
  12. if (count < rb_capacity(rb)-(rb->rb_head - rb->rb_buff))
  13. {
  14. int copy_sz = count;
  15. memcpy(data, rb->rb_head, copy_sz);
  16. rb->rb_head += copy_sz;
  17. return copy_sz;
  18. }
  19. else
  20. {
  21. int copy_sz = rb_capacity(rb) - (rb->rb_head - rb->rb_buff);
  22. memcpy(data, rb->rb_head, copy_sz);
  23. rb->rb_head = rb->rb_buff;
  24. copy_sz += rb_read(rb, (char*)data+copy_sz, count-copy_sz);
  25. return copy_sz;
  26. }
  27. }
  28. }
复制代码


对于源程序中的,指针不为NULL判断,其实是必须要加上的,不知道为什么,我下载的代码,这些部分都被注释掉了。



另附我在编辑中遇到的“不合理”的问题:(吐槽)
1、不知道什么情况下,编辑的时候,进入了“修改”模式,就是不能在随意的插入内容,这个怎么切换回Insert模式?
2、修改字号、字体大小时,编辑框乱跳。
Ctrl + V 粘贴时,编辑框乱跳。
拖拉编辑框改变编辑框大小时,编辑框乱跳。
这些乱跳现象虽然不影响编辑,但是着实让人难受。
3、代码区域编辑时不可见,不知道我是在代码框编辑,还是在文本框中编辑。看我帖子后边的几个空的代码框,就是当时插入了代码,后敲了回车想输入文本时出现的。想删也找不到地方。
搞的只能编辑的时候,先写几个字,站住位置,告诉自己这一行是文本。。。再放心的插入代码。。。
4、图片大小不能调整,这个貌似有点苛刻了。但是论坛的水印太大,容易影响阅读。我插入图片时,都是留出来余量编辑的图片。
5、代码框,虽然可以选择不同的语种,比如C、Java,然而没有区别。。。我还以为会有语法高亮呢、
6、英文、数字字符与汉字之间间隔太小,我有敲一个或两个空格。看着舒服些。。。


jipin 发表于 2016-7-25 22:40:04
让管理员送一板,必须的。
初进茅庐 发表于 2017-4-26 09:54:18
楼主,这个版本的协议是不是不适合乐鑫的板子?
maomaodemao 发表于 2016-12-9 00:26:03
向您学习
淡忘瞬间 发表于 2016-10-2 13:41:44
WM_CH 发表于 2016-7-25 15:41
【机智云Gokit开发套件试用体验】+ RingBuffer源代码分析

大家都知道,环形缓冲区是比较常用的数据结构, ...

厉害 佩服
林光光1号 发表于 2016-8-7 01:17:20
很详细,赞一个
admin 发表于 2016-8-4 21:57:06
赞赞赞  楼主 参加开源大赛吗》???
WM_CH 发表于 2016-8-4 20:43:51
聪聪聪 发表于 2016-7-28 13:45
楼主是不是要用机智云的软件,那个mcu程序是不是得植入机智云的通讯协议

不晓得你说的是啥啊
聪聪聪 发表于 2016-7-28 13:45:39
楼主是不是要用机智云的软件,那个mcu程序是不是得植入机智云的通讯协议
jipin 发表于 2016-7-20 23:31:18
3.0的源码发布了,楼主加注释啊。给大家科普一下。
月下 发表于 2016-7-18 17:18:59
支持~~~~~~~
molo 发表于 2016-7-5 08:53:56
学习一下,多谢分享。
k7arm 发表于 2016-7-2 17:26:51
多谢楼主分享啊
钱昊 发表于 2016-6-26 10:30:46
论坛越来越火啦
crossok 发表于 2016-6-12 09:07:56
mark下,感谢楼主分享
飞翔中的语言 发表于 2016-5-19 19:12:33
请问你可以实现两个led灯的控制吗?第二个估计不简单
zhangke0504 发表于 2016-5-11 13:47:44
看看支持就
加入Q群 返回顶部

版权与免责声明 © 2006-2024 Gizwits IoT Technology Co., Ltd. ( 粤ICP备11090211号 )

快速回复 返回顶部 返回列表