代码设计过程中遇到bug
多的不说,先贴代码,重点关注at_queue_flush函数
void at_queue_flush(at_queue_t at_q) {
uint8_t* p_temp = at_q->buf;
memset(at_q->buf, 0, at_q->size);
memset(at_q, 0, sizeof(*at_q));
at_q->buf = p_temp;
}
这是个环形缓冲区(下面简称rb),flush使其清空函数,目的是使得缓冲区内容全部清零,以及其他字段清零。代码是这么做的
- 先存rb 的缓冲区的地址,赋给p_temp
- 将缓冲区的内容通过memset清零。
- 将整一个rb通过memset清零,期望所有字段归零,此时buf为空指针。
- buf指向p_temp, 即指向之前保存的缓冲区地址
结果发现,调用了flush函数以后,再对其putchar是失败的!putchar返回0,由代码逻辑来看,这是缓冲区满造成的。但是紧随其后调用at_queue_debug,发现结果为
|======at_queue_info======|
buf=
size=0
read_mirror=0
read_idx=0
write_mirror=0
write_idx=0
*/
这明显是初始状态,缓冲区为空,为什么会putchar失败呢?
真相令人震惊
文章写到这里,我也发现我自己的问题了,flush没有恢复rb->size这个数据,于是乎,size为0,当然不能够再putchar啦。
上面说是初始状态,这是不对的,因为根据代码逻辑,size=1024才是初始状态
ok,本篇文章为无营养文章,到此结束
环形缓冲区完整代码如下(可直接运行)
由于环形缓冲区用于进行at模块响应数据的接收,所以命名为at_queue了,不要在意- -
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>
#define at_queue_space_len(at_q) ((at_q)->size - at_queue_data_len(at_q))
struct at_queue_s {
uint8_t* buf; /* the buffer holding the data */
uint16_t size;
uint16_t read_mirror : 1; /* 用于判断当read_idx==write_idx时,buf是空还是满 */
uint16_t read_idx : 15;
uint16_t write_mirror : 1;
uint16_t write_idx : 15;
};
struct at_queue_s at_queue;
typedef struct at_queue_s *at_queue_t;
uint8_t at_queue_buf[1024];
typedef enum at_queue_state{
AT_QUEUE_EMPTY,
AT_QUEUE_FULL,
AT_QUEUE_HALFFULL,
}AT_QUEUE_STATE;
static inline AT_QUEUE_STATE at_queue_get_state(at_queue_t at_q){
if(at_q->read_idx == at_q->write_idx) {
if(at_q->read_mirror == at_q->write_mirror)
return AT_QUEUE_EMPTY;
else
return AT_QUEUE_FULL;
}
return AT_QUEUE_HALFFULL;
}
// 获得缓冲区数据长度
uint16_t at_queue_data_len(at_queue_t at_q) {
switch(at_queue_get_state(at_q)) {
case AT_QUEUE_EMPTY:
return 0;
case AT_QUEUE_FULL:
return at_q->size;
case AT_QUEUE_HALFFULL:
if(at_q->write_idx > at_q->read_idx)
return at_q->write_idx - at_q->read_idx;
else
return at_q->size - (at_q->read_idx - at_q->write_idx);
};
return at_q->size;
}
void at_queue_init(at_queue_t at_q, uint8_t* pool, uint16_t size) {
assert(at_q != NULL);
assert(size > 0);
/* initialize read and write index */
at_q->read_mirror = at_q->read_idx = 0;
at_q->write_mirror = at_q->write_idx = 0;
at_q->buf = pool;
at_q->size = size;
}
/**
* put a character into ring buffer
*/
size_t at_queue_putchar(at_queue_t at_q, const uint8_t ch) {
assert(at_q != NULL);
/* whether has enough space */
if (!at_queue_space_len(at_q)){
printf("in at_queue_putchar: AT_QUEUE_FULL!\r\n");
return 0;
}
at_q->buf[at_q->write_idx] = ch;
/* flip mirror */
if(at_q->write_idx == at_q->size-1) {
at_q->write_mirror = ~at_q->write_mirror;
at_q->write_idx = 0;
} else {
at_q->write_idx++;
}
return 1;
}
void at_queue_flush(at_queue_t at_q) {
uint8_t* p_temp = at_q->buf;
uint16_t size = at_q->size;
memset(at_q->buf, 0, at_q->size);
memset(at_q, 0, sizeof(*at_q));
at_q->buf = p_temp;
at_q->size = size;
}
static inline void at_queue_debug(at_queue_t at_q){
printf("|======at_queue_info======|\r\n");
printf("buf=%s\r\n",
at_q->buf /* the buffer holding the data */
);
printf("size=%u\r\nread_mirror=%u\r\nread_idx=%u\r\nwrite_mirror=%u\r\nwrite_idx=%u\r\n",
at_q->size,
at_q->read_mirror, /* 用于判断当read_idx==write_idx时,buf是空还是满 */
at_q->read_idx,
at_q->write_mirror,
at_q->write_idx
);
}
int main()
{
at_queue_t at_q = &at_queue;
at_queue_init(at_q, at_queue_buf, sizeof(at_queue_buf));
at_queue_debug(at_q);
/*|======at_queue_info======|
buf=
size=1024
read_mirror=0
read_idx=0
write_mirror=0
write_idx=0
*/
printf("at_q->buf addr = %p\r\n", at_q->buf);
// at_q->buf addr = 0x404050
at_queue_putchar(at_q, '\r');
at_queue_putchar(at_q, '\n');
at_queue_putchar(at_q, 'H');
at_queue_putchar(at_q, 'E');
at_queue_putchar(at_q, 'L');
at_queue_putchar(at_q, 'L');
at_queue_putchar(at_q, 'O');
at_queue_putchar(at_q, '\r');
at_queue_putchar(at_q, '\n');
at_queue_debug(at_q);
/*|======at_queue_info======|
buf=
HELLO
size=1024
read_mirror=0
read_idx=0
write_mirror=0
write_idx=9
*/
printf("at_q->buf addr = %p\r\n", at_q->buf);
// at_q->buf addr = 0x404050
at_queue_flush(at_q);
at_queue_debug(at_q);
/*|======at_queue_info======|
buf=
size=0
read_mirror=0
read_idx=0
write_mirror=0
write_idx=0
*/
printf("at_q->buf addr = %p\r\n", at_q->buf);
// at_q->buf addr = 0x404050
printf("%zu", at_queue_putchar(at_q, '\r'));
// 输出0,说明putchar失败,putchar认为缓冲区已满
at_queue_putchar(at_q, '\n');
at_queue_putchar(at_q, 'H');
at_queue_putchar(at_q, 'E');
at_queue_putchar(at_q, 'L');
at_queue_putchar(at_q, 'L');
at_queue_putchar(at_q, 'O');
at_queue_putchar(at_q, '\r');
at_queue_putchar(at_q, '\n');
at_queue_debug(at_q);
/*显示居然是空!,期望的是和第二次debug结果一样
|======at_queue_info======|
buf=
size=0
read_mirror=0
read_idx=0
write_mirror=0
write_idx=0
*/
printf("at_q->buf addr = %p\r\n", at_q->buf);
// at_q->buf addr = 0x404050
return 0;
}