rt-thread icon indicating copy to clipboard operation
rt-thread copied to clipboard

关于AT组件中读取一行数据的效率问题

Open wangzhouwang opened this issue 3 years ago • 3 comments

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;

}

wangzhouwang avatar Jun 02 '22 06:06 wangzhouwang

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个字节

wangzhouwang avatar Jun 02 '22 06:06 wangzhouwang

get_urc_obj 的设计目的就是及时感知底层的数据,如果有 URC 数据就及时跳转到对应的函数中去,以实现对 URC 数据的处理。

实际每次读取到一个字节即返回的事情,应该是不常有的。


至于 urc_recv_func ,作为 URC 的处理函数,得到接收多少数据的大小,就开辟相应空间来接收,应该是没有问题的。 你这里提到的,分配 1 个字节,却占用 16 个字节的情况,能不能给出对应的 LOG,与内存空间的数据?如果真的是这样,确实有危险。

xiangxistu avatar Jun 02 '22 12:06 xiangxistu

rt-thread 驱动篇(五)serialX 小试牛刀http://www.elecfans.com/d/1849301.html 之前的串口驱动框架,都做不到你要的,serialX 专为这种情况而生

thewon86 avatar Jul 04 '22 06:07 thewon86