关于AT组件中读取一行数据的效率问题
static int at_recv_readline(at_client_t client) { rt_size_t read_len = 0; char ch = 0, last_ch = 0; rt_bool_t is_full = RT_FALSE;
rt_memset(client->recv_line_buf, 0x00, client->recv_bufsz);
client->recv_line_len = 0;
while (1)
{
at_client_getchar(client, &ch, RT_WAITING_FOREVER);
if (read_len < client->recv_bufsz)
{
client->recv_line_buf[read_len++] = ch;
client->recv_line_len = read_len;
}
else
{
is_full = RT_TRUE;
}
/* is newline or URC data */
if ((ch == '\n' && last_ch == '\r') || (client->end_sign != 0 && ch == client->end_sign)
|| **get_urc_obj(client)**)
{
if (is_full)
{
LOG_E("read line failed. The line data length is out of buffer size(%d)!", client->recv_bufsz);
rt_memset(client->recv_line_buf, 0x00, client->recv_bufsz);
client->recv_line_len = 0;
return -RT_EFULL;
}
break;
}
last_ch = ch;
}
#ifdef AT_PRINT_RAW_CMD at_print_raw_cmd("recvline", client->recv_line_buf, read_len); #endif
return read_len;
}
这个函数功能是从串口里面读取一行数据返回,但实际上是读取一个字节就返回,因为get_urc_obj(client) 这个条件每次判断都为真,这样会导致驱动中动态内存的浪费和通讯速度下降。建议改成
static int at_recv_readline(at_client_t client) { rt_size_t read_len = 0; char ch = 0, last_ch = 0; rt_bool_t is_full = RT_FALSE;
rt_memset(client->recv_line_buf, 0x00, client->recv_bufsz);
client->recv_line_len = 0;
while (1)
{
**rt_err_t result;**
result = at_client_getchar(client, &ch, 10);
**if(result != RT_EOK)
{
break;
}**
if (read_len < client->recv_bufsz)
{
client->recv_line_buf[read_len++] = ch;
client->recv_line_len = read_len;
}
else
{
is_full = RT_TRUE;
}
/* is newline or URC data */
if ((ch == '\n' && last_ch == '\r') || (client->end_sign != 0 && ch == client->end_sign)
/*|| get_urc_obj(client)*/)
{
if (is_full)
{
LOG_E("read line failed. The line data length is out of buffer size(%d)!", client->recv_bufsz);
rt_memset(client->recv_line_buf, 0x00, client->recv_bufsz);
client->recv_line_len = 0;
return -RT_EFULL;
}
break;
}
last_ch = ch;
}
#ifdef AT_PRINT_RAW_CMD at_print_raw_cmd("recvline", client->recv_line_buf, read_len); #endif
return read_len;
}
static void urc_recv_func(struct at_client *client, const char *data, rt_size_t size) { int device_socket = 0; rt_int32_t timeout = 0; rt_size_t bfsz = 0, temp_size = 0; char *recv_buf = RT_NULL, temp[8] = {0}; struct at_socket *socket = RT_NULL; struct at_device *device = RT_NULL; char *client_name = client->device->parent.name;
RT_ASSERT(data && size);
device = at_device_get_by_name(AT_DEVICE_NAMETYPE_CLIENT, client_name);
if (device == RT_NULL)
{
LOG_E("get device(%s) failed.", client_name);
return;
}
/* get the at deveice socket and receive buffer size by receive data */
sscanf(data, "+IPD,%d,%d:", &device_socket, (int *) &bfsz);
/* set receive timeout by receive buffer length, not less than 10ms */
timeout = bfsz > 10 ? bfsz : 10;
if (device_socket < 0 || bfsz == 0)
return;
recv_buf = (char *) rt_calloc(1, bfsz);
if (recv_buf == RT_NULL)
{
LOG_E("no memory receive buffer(%d).", bfsz);
/* read and clean the coming data */
while (temp_size < bfsz)
{
if (bfsz - temp_size > sizeof(temp))
{
at_client_obj_recv(client, temp, sizeof(temp), timeout);
}
else
{
at_client_obj_recv(client, temp, bfsz - temp_size, timeout);
}
temp_size += sizeof(temp);
}
return;
}
/* sync receive data */
if (at_client_obj_recv(client, recv_buf, bfsz, timeout) != bfsz)
{
LOG_E("%s device receive size(%d) data failed.", device->name, bfsz);
rt_free(recv_buf);
return;
}
/* get at socket object by device socket descriptor */
socket = &(device->sockets[device_socket]);
/* notice the receive buffer and buffer size */
if (at_evt_cb_set[AT_SOCKET_EVT_RECV])
{
at_evt_cb_set[AT_SOCKET_EVT_RECV](socket, AT_SOCKET_EVT_RECV, recv_buf, bfsz);
}
}
在网卡驱动中recv_buf = (char *) rt_calloc(1, bfsz); 会经常分配1个字节内存,实际上占用16个字节
get_urc_obj 的设计目的就是及时感知底层的数据,如果有 URC 数据就及时跳转到对应的函数中去,以实现对 URC 数据的处理。
实际每次读取到一个字节即返回的事情,应该是不常有的。
至于 urc_recv_func ,作为 URC 的处理函数,得到接收多少数据的大小,就开辟相应空间来接收,应该是没有问题的。 你这里提到的,分配 1 个字节,却占用 16 个字节的情况,能不能给出对应的 LOG,与内存空间的数据?如果真的是这样,确实有危险。
rt-thread 驱动篇(五)serialX 小试牛刀http://www.elecfans.com/d/1849301.html 之前的串口驱动框架,都做不到你要的,serialX 专为这种情况而生