从零开始的激光通讯(第1章 协议栈)——2、环形数组

从零开始的激光通讯(第1章 协议栈)——2、环形数组

github

https://github.com/HaHaHaHaHaGe/mynetstack

简介

在说明环形数组之前,先来看一看通常大家使用内存的方式
在这里插入图片描述
这是一段内存空间,大小16字节,起始地址0x80000000,截止地址0x8000000F

在这段内存中若想为其内存空间进行赋值操作,C语言下应当:

*(unsigned char*)(0x80000000) = 0x66;

很明显这条指令将0x66 赋值到了 0x80000000这个内存空间中

同样你也可以:

unsigned char i = 16
while(i--)
	*(unsigned char*)(0x80000000 + i) = 0x66;

这样你将把整个内存空间从 0x80000000 ~ 0x8000000F 全部赋值为0x66,当然在现实应用中会赋值更有意义的数据,并非0x66

同样你也可以读取数组内的数据

unsigned char recv;
recv = *(unsigned char*)(0x80000000);

或者连续读取内存中的数据

unsigned char recv[16];
unsigned char i = 16
while(i--)
	recv = *(unsigned char*)(0x80000000 + i);

啊~一切是那么的美好,我可以随意的存储、写入我希望的数据

好,接下来咱们在做一些假设:首先写入的人不再是你,而是其他人(程序)
那么这样一来问题就变得有些复杂了,
你并不能知道,对方什么时间会向里面写入数据

所以我需要有一个标志来代表是否有人向内存中写入了数据

然后轮询的检测这个标志,若此标志被置位了,则代表里面有新的数据,需要读取数据了

好的,问题解决了

但是这只是理想情况下,但在现实应用中,很可能当标志被置位时,我没有能力一口气全部读取新数据,这时候又该怎么办呢?

我们可以在增加一个标志,这个标志表示我读到的位置,而之前的写标志也更改为写到的位置,这样一来,就会变成下面的样子:
在这里插入图片描述
当写入方写入数据时只需要挪动写标志,读取方只是要挪动读标志

而且,我也只需要检测读写标志的距离就可知道当前是否有新的数据了

一切看似近乎完美,但是却有一个致命的问题:
在这里插入图片描述
当写位置达到末尾时,这时候该怎么办呢?

如果置之不理,那么很明显下一次写入的位置将是未知区域!,这是很危险的,一个野指针的存在比空指针更加的危险。

这时候就到环形数组发挥功效的时候了
在这里插入图片描述
环形数组,顾名思义,就像他的名字一样,结构是个环形,当读\写指针超过0x8000000F时也不会造成严重事故,因为他被重定向到了0x80000000

这便是环形数组了,当然内存自己本身不可能从硬件修改成环形结构,环形的结构是在软件层面上定义的

函数说明

有关环形数组的文件在\mynetstack\Source\BasicDataStream\inc 与\mynetstack\Source\BasicDataStream\src 中
名称为 ringbuffer.c 与 ringbuffer.h

注:程序还在更新,以GITHUB为准

/*
写数据到缓冲区函数
入口参数:
ptr:操作对象
data:写入的数据指针
datalen:写入的数据长度
*/
void write_buffer_data(ringbuffer *ptr, u8* data, u32 datalen);


/*
释放缓冲区函数
注:如果在创建时指定了已经开辟好的内存,
那么该函数只会清理此模块内部的变量,
不会更改外部的数据
入口参数:
ptr:操作对象
*/
u8 deinitial_buffer(ringbuffer *ptr);




/*
创建缓冲区函数
注:可在创建时指定已经开辟好的内存,
入口参数:
ptr:操作对象
self_mem: 是否由本函数自行分配空间,如果不需要,
应输入NO并在操作对象的start ptr中分配好相应的空间
size: 需要开辟空间的大小
*/
u8 initial_buffer(ringbuffer *ptr, u8 self_mem, u32 size);


/*
外部写入数据后使用此函数更新内部参数
入口参数:
ptr:操作对象
datalen:外部写入的数据长度
*/
void write_buffer_len(ringbuffer *ptr, u32 datalen);


/*
获取全部未读数据
入口参数:
ptr:操作对象
len: 读出数据的长度(字节)
preview:若为YES则此次读取不会修改ringbuff内指针状态
*/
u8* get_unread_data(ringbuffer *ptr, u32 *len,u8 preview);





/*
获取全部未读数据的指针(分两部分)
入口参数:
ptr:操作对象
ptr_1: 保存第一个指针
ptr_2: 保存第二个指针
len_1: 第一个指针内容的大小(字节)
len_2: 第二个指针内容的大小(字节)
preview:若为YES则此次读取不会修改ringbuff内指针状态
*/
void get_unread_ptr(ringbuffer *ptr, u8** ptr_1, u8** ptr_2, u32* len_1, u32* len_2, u8 preview);








/*
手动更新read指针
注:一般在get_unread_ptr后根据自身情况使用
入口参数:
ptr:操作对象
*/
void update_readlocation(ringbuffer *ptr);

猜你喜欢

转载自blog.csdn.net/weixin_41738734/article/details/84860982