AT组件的核心处理逻辑是将收到的 AT 模组的应答信息放到 recv_line_buf 缓冲区中,然后每次读一行数据("\r\n")进行处理,然后判断属于哪一类的消息,调用不同的函数。
本文以 EC200x 模组为例,详细分析了 AT 组件的实现过程和代码的调用逻辑,帮助在使用 AT 组件过程中遇到问题的开发者快速定位问题出现的位置。
可以通过修改 env 中的如下内容来控制是否启用 AT 组件的 debug log 功能,开启后可以看到日志级别为 debug 的相关日志。使能该选项后将在 `rtconfig.h` 中生成 `#define AT_DEBUG`,AT 组件日志级别的控制是在 `rt-thread/components/net/at/include/at_log.h` 文件中实现的。
RT-Thread Components
-> Network
-> AT commands
-> [*] Enable debug log output /* 选中表示修改日志级别为 debug */
特别注意:打开上述功能后,ec200x 线程(在 packages/at_device-2.0.4/class/ec200x/at_device_ec200x.c 文件中由 ec200x_netdev_check_link_status() 函数创建)会提示栈溢出,使用的栈空间约为 1598Bytes,建议将 ec200x_netdev_check_link_status() 函数中的 EC200X_LINK_THREAD_STACK_SIZE 宏更改为 1024 +1024 即 2048 个字节,以解决栈溢出的问题。
在调试时可以通过修改 env 中的如下内容来控制是否使能 AT 组件的收发 AT 指令的显示,开启后可以看到每次执行的 AT 指令以及返回的执行结果。
RT-Thread Components
-> Network
-> AT commands
-> [*] Enable print RAW format AT command communication data /* 选中表示打印执行的AT指令 */
上述选项选中后,在执行测试时,打印的 AT 指令示例如下
[D/AT] recvline: 0000-0020: 41 54 0D 0D 0A AT...
[D/AT] recvline: 0000-0020: 4F 4B 0D 0A OK..
[D/AT] sendline: 0000-0020: 41 54 45 30 ATE0
[D/AT] recvline: 0000-0020: 41 54 45 30 0D 0D 0A ATE0...
[D/AT] recvline: 0000-0020: 4F 4B 0D 0A OK..
[D/AT] sendline: 0000-0020: 41 54 2B 49 50 52 3F AT+IPR?
01-01 00:40:19 D/at.clnt: execute command (AT+IPR?) timeout (300 ticks)!
[D/AT] recvline: 0000-0020: 0D 0A ..
[D/AT] recvline: 0000-0020: 2B 49 50 52 3A 20 31 31 35 32 30 30 0D 0A +IPR: 115200..
[D/AT] recvline: 0000-0020: 0D 0A ..
[D/AT] recvline: 0000-0020: 4F 4B 0D 0A OK..
[D/AT] recvline: 0000-0020: 0D 0A ..
[D/AT] recvline: 0000-0020: 52 44 59 0D 0A RDY..
01-01 00:40:22 I/at.dev.ec200x: ec200x device initialize retry...
[D/AT] sendline: 0000-0020: 41 54 45 30 ATE0
01-01 00:40:24 D/at.clnt: execute command (ATE0) timeout (300 ticks)!
[D/AT] recvline: 0000-0020: 0D 0A ..
[D/AT] recvline: 0000-0020: 4F 4B 0D 0A OK..
[D/AT] recvline: 0000-0020: 0D 0A ..
[D/AT] recvline: 0000-0020: 4F 4B 0D 0A OK..
AT组件中会自动创建一个 GPRS 网络注册状态检查的线程,使用 "AT+CGREG?" 指令进行 GPRS 网络注册状态的检查,并根据指令返回的结果修改网卡设备的标志位,该指令返回结果中的 等于 1 或者 5,表示模块已在 UMTS/LTE 网络注册上 PS 业务。
GPRS 网络注册状态检查线程的名字是模拟网卡的名字,在本例中为 "ec200x",线程的入口函数是 ec200x_check_link_status_entry(packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c),该线程没间隔 60s 发送一条 AT 指令进行 GPRS 网络注册状态的检查,并根据返回的结果在函数 netdev_low_level_set_link_status` 中修改 `netdev->flags。各种情况的执行结果分析如下所示
上一次网络注册状态 | 这次网络注册状态 | 操作1 | 操作2 |
未注册 | 未注册 | 无 | 无 |
未注册 | 注册 | 标记 netdev->flags 的 NETDEV_FLAG_LINK_UP 标志 | 调用 sal_check_netdev_internet_up() 函数将任务放入 sys_work 队列,然后通过和 "link.rt-thread.org" 的 8101 端口交互来修改 netdev->flags 中的 NETDEV_FLAG_INTERNET_UP 标志 |
注册 | 未注册 | 清除 netdev->flags 的 NETDEV_FLAG_LINK_UP 和 NETDEV_FLAG_INTERNET_UP 标志 | 调用 netdev_auto_change_default() 函数切换到第一个连接的网络设备,本例中只用到了一个网络设 |
注册 | 注册 | 无 | 无 |
特别注意:GPRS 网络注册状态检查线程会检查模组的 power_status,power_status 在 ec200x_init() 函数中默认初始化为 RT_FALSE,然后在名为 "ec200x_net" 的线程的 ec200x_init_thread_entry() 线程入口函数中调用 ec200x_power_on() 函数来修改 power_status 的值。ec200x_power_on() 函数中 power_status 的值修改为 RT_TRUE 依赖于 power_pin 引脚的定义,因此在 env 中必须定义 power_pin 的编号,默认为 -1,定义规则在文件 drivers/drv_gpio.c 中。另外还需要注意的是在代码中 power_pin 为低电平表示模组处于上电状态,power_pin 为高电平表示模组处于断电状态。
power_pin 编号的定义在禁用网卡(netdev_set_down)与启用网卡(netdev_set_up)的实现中也至关重要,网卡的禁用与启用最终实际调用的函数为 ec200x_power_off() 和 ec200x_power_on(),因此必须定义power_pin 的编号,网卡禁用与启用的示例代码如下
/* "ec200x" 名字来源于设备注册时使用的名字,在文件 packages/at_device-v2.0.4/samples/at_sample_ec200x.c 中定义 */
struct at_device * dev = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, "ec200x");/* 根据名字查找 AT 设备 */
netdev_set_up(dev->netdev); /* 启用相应的网卡设备 */
netdev_set_down(dev->netdev); /* 禁用相应的网卡设备 */
rt-thread/components/net/sal_socket/src/sal_socket.c 中 check_netdev_internet_up_work() 函数会自动连接 "link.rt-thread.org"` 的 `8101 端口进行数据收发测试,从而判断是否可以连接外网。该文件中默认的打印级别为 DBG_INFO,为了方便看出是否可以连接外网,将 check_netdev_internet_up_work() 函数结尾的部分的测试结果打印由 LOG_D 修改为 LOG_I。
该函数的执行的过程大致为在 ec200x 初始化线程 ec200x_init_thread_entry() 中将将外网检查任务提交到 sys_work 工作队列中,系统工作队列处理线程 _workqueue_thread_entry() 会不断的检测是否有需要运行的任务,如果有则执行相应的任务,即执行外网连接检查任务。外网连接检查任务提交到工作队列的执行过程如下
ec200x_init_thread_entry /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x_power_on /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> at_obj_exec_cmd() /* 发送各种AT指令初始化EC200x rt-thread/components/net/at/src/at_client.c */
|-> ec200x_netdev_set_info /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> at_device_get_by_name /* packages/at_device-v2.0.4/src/at_device.c */
|-> netdev_low_level_set_status /* rt-thread/components/net/netdev/src/netdev.c */
|-> netdev->flags |= NETDEV_FLAG_LINK_UP; /* 网络设备的状态改为连接 */
|-> netdev_low_level_set_link_status /* rt-thread/components/net/netdev/src/netdev.c */
|-> netdev_low_level_set_dhcp_status /* rt-thread/components/net/netdev/src/netdev.c */
|-> netdev_low_level_set_ipaddr /* 设置本地的IP地址 rt-thread/components/net/netdev/src/netdev.c */
|-> sal_check_netdev_internet_up /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> rt_delayed_work_init(net_work, check_netdev_internet_up_work) /* 初始化外网连接检查任务 rt-thread/components/drivers/src/workqueue.c */
|-> (&work->work)->work_func = check_netdev_internet_up_work
|-> rt_work_submit(&(net_work->work), RT_TICK_PER_SECOND); /* rt-thread/components/drivers/src/workqueue.c */
|-> rt_workqueue_submit_work(sys_workq, work, time) /* 将任务提交到系统工作队列里面 rt-thread/components/drivers/src/workqueue.c */
|-> netdev_low_level_set_dns_server /* 设置DNS服务器 rt-thread/components/net/netdev/src/netdev.c */
|-> ec200x_netdev_check_link_status /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> rt_thread_create(ec200x_check_link_status_entry) /* 线程名字为"ec200x",创建 GPRS 网络注册状态检查线程 packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> rt_thread_startup(ec200x_check_link_status_entry) /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
/* GPRS 网络注册状态检查线程 */
ec200x_check_link_status_entry /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x_check_link_status /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> at_obj_exec_cmd("AT+CGREG?") /* 发送AT指令检查网络状态 */
|-> netdev_low_level_set_link_status /* rt-thread/components/net/netdev/src/netdev.c */
系统工作队列初始化和任务执行过程如下
rt_work_sys_workqueue_init /* rt-thread/components/drivers/src/workqueue.c */
|-> rt_workqueue_create("sys_work") /* 创建系统工作队列 rt-thread/components/drivers/src/workqueue.c */
|-> rt_thread_create(_workqueue_thread_entry) /* 线程名字为"sys_work",创建队列线程 rt-thread/components/drivers/src/workqueue.c */
_workqueue_thread_entry /* 系统工作队列处理线程 rt-thread/components/drivers/src/workqueue.c */
|-> if(rt_list_isempty)
|-> rt_thread_suspend(rt_thread_self()); /* 挂起自身 */
|-> rt_schedule(); /* 任务列表为空,挂起自身,切换线程 */
|-> rt_hw_interrupt_disable /* 任务列表不为空,依次往下执行,关闭中断 */
|-> rt_list_entry /* 找到要处理的任务节点 */
|-> rt_list_remove /* 将找到的任务节点从任务列表中移除 */
|-> rt_hw_interrupt_enable /* 使能中断 */
|-> work->work_func(work, work->work_data); /* 执行任务 */
外网连接检查任务的执行过程如下
check_netdev_internet_up_work /* 外网连接检查任务 rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> 与 "link.rt-thread.org" 的 8101 端口建立连接,进行收发数据测试
|-> 打印测试结果
|-> 收发测试成功 LOG_I("Set network interface device(%s) internet status up.", netdev->name);
|-> netdev->flags |= NETDEV_FLAG_INTERNET_UP;
|-> 收发测试失败 LOG_I("Set network interface device(%s) internet status down.", netdev->name);
|-> netdev->flags &= ~NETDEV_FLAG_INTERNET_UP;
at_device_register /* packages/at_device-v2.0.4/samples/at_sample_ec200x.c */
|-> class = at_device_class_get(class_id) /* packages/at_device-v2.0.4/src/at_device.c */
|-> class->device_ops->init(device) /* packages/at_device-v2.0.4/src/at_device.c */
|-> ec200x_init /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x->power_status = RT_FALSE; /* default power is off. packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x->sleep_status = RT_FALSE; /* default sleep is disabled. packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> at_client_init /* components/net/at/src/at_client.c */
|-> at_client_para_init /* components/net/at/src/at_client.c */
|-> rt_thread_create(client_parser) /* 线程名字为"at_clnt0",创建AT解析线程 components/net/at/src/at_client.c */
|-> client_parser /* AT解析线程的具体实现 components/net/at/src/at_client.c */
|-> rt_device_find /* 寻找串口设备 rt-thread/src/device.c */
|-> rt_device_open /* 打开串口设备 rt-thread/src/device.c */
|-> rt_thread_startup(client->parser) /* rt-thread/src/thread.c */
|-> ec200x_socket_init /* packages/at_device-v2.0.4/class/ec200x/at_socket_ec200x.c */
|-> ec200x_netdev_add("ec200x") /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> netdev_get_by_name("ec200x") /* rt-thread/components/net/netdev/src/netdev.c */
|-> netdev->ops = &ec200x_netdev_ops; /* 网络设备操作集 packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> sal_at_netdev_set_pf_info /* rt-thread/components/net/sal_socket/impl/af_inet_at.c */
|-> netdev_register /* rt-thread/components/net/netdev/src/netdev.c */
|-> netdev->status_callback = RT_NULL; /* rt-thread/components/net/netdev/src/netdev.c */
|-> netdev->addr_callback = RT_NULL; /* rt-thread/components/net/netdev/src/netdev.c */
|-> ec200x->power_pin /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x->power_status_pin /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x->wakeup_pin /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x_netdev_set_up /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> at_device_get_by_name /* packages/at_device-v2.0.4/src/at_device.c */
|-> ec200x_net_init /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> rt_thread_create(ec200x_init_thread_entry) /* 线程名字为"ec200x_net",执行各种AT指令初始化网络 packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> rt_thread_startup(ec200x_init_thread_entry) /* 启动网络初始化线程 packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> netdev_low_level_set_status /* rt-thread/components/net/netdev/src/netdev.c */
ec200x_device_class_register /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x_socket_class_register /* packages/at_device-v2.0.4/class/ec200x/at_socket_ec200x.c */
|-> class->socket_num = AT_DEVICE_EC200X_SOCKETS_NUM; /* packages/at_device-v2.0.4/class/ec200x/at_socket_ec200x.c */
|-> class->socket_ops = &ec200x_socket_ops; /* packages/at_device-v2.0.4/class/ec200x/at_socket_ec200x.c */
|-> class->device_ops = &ec200x_device_ops; /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> at_device_class_register /* packages/at_device-v2.0.4/src/at_device.c */
/* 启用网卡 */
netdev_set_up(netdev) /* components/net/netdev/src/netdev.c */
|-> netdev->ops->set_up(netdev) /* netdev->ops = &ec200x_netdev_ops; packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x_netdev_set_up ------------------------------| /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x_net_init | /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x_init_thread_entry | /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|
/* module init */ |
ec200x_init | /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> at_client_init | /* components/net/at/src/at_client.c */
|-> ec200x_socket_init | /* packages/at_device-v2.0.4/class/ec200x/at_socket_ec200x.c */
|-> ec200x_netdev_add | /* packages/at_device-v2.0.4/class/ec200x/at_socket_ec200x.c */
|-> netdev_register | /* rt-thread/components/net/netdev/src/netdev.c */
|-> ec200x_netdev_set_up ----------------------------------| /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x_net_init /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x_init_thread_entry /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
/* 禁用网卡 */
netdev_set_down(netdev) /* components/net/netdev/src/netdev.c */
|-> netdev->ops->set_down(netdev); /* components/net/netdev/src/netdev.c */
|-> ec200x_netdev_set_down ----------------------------| /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x_power_off | /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> netdev_low_level_set_status(netdev, RT_FALSE) | /* rt-thread/components/net/netdev/src/netdev.c */
|-> netdev->flags &= ~NETDEV_FLAG_UP | /* rt-thread/components/net/netdev/src/netdev.c */
|-> netdev_auto_change_default | /* rt-thread/components/net/netdev/src/netdev.c */
|
/* module deinit */ |
ec200x_deinit | /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x_netdev_set_down --------------------------------| /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
|-> ec200x_power_off /* packages/at_device-v2.0.4/class/ec200x/at_device_ec200x.c */
#define socket(domain, type, protocol) sal_socket(domain, type, protocol) /* rt-thread/components/net/sal_socket/include/socket/sys_socket/sys/socket.h */
|-> sal_socket /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> socket_new /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> socket_alloc /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> sock = st->sockets[idx]; /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> sock->socket = idx + SAL_SOCKET_OFFSET; /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> sock->magic = SAL_SOCKET_MAGIC; /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> sock->netdev = RT_NULL; /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> sock->user_data = RT_NULL; /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> sal_get_socket /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> socket_init /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> sock->netdev = netdev; /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> SAL_NETDEV_SOCKETOPS_VALID /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> pf->skt_ops->socket /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> at_socket /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> alloc_socket /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> sock->type = socket_type; /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> sock->state = AT_SOCKET_OPEN; /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> sock->ops->at_set_event_cb(AT_SOCKET_EVT_RECV, at_recv_notice_cb); /* 设置接收回调函数 rt-thread/components/net/at/at_socket/at_socket.c */
|-> ec200x_socket_set_event_cb /* packages/at_device-v2.0.4/class/ec200x/at_socket_ec200x.c */
|-> at_evt_cb_set[event] = cb; /* packages/at_device-v2.0.4/class/ec200x/at_socket_ec200x.c */
|-> sock->ops->at_set_event_cb(AT_SOCKET_EVT_CLOSED, at_closed_notice_cb); /* 设置关闭套接字回调函数 rt-thread/components/net/at/at_socket/at_socket.c */
|-> ec200x_socket_set_event_cb /* packages/at_device-v2.0.4/class/ec200x/at_socket_ec200x.c */
|-> at_evt_cb_set[event] = cb; /* packages/at_device-v2.0.4/class/ec200x/at_socket_ec200x.c */
#define connect(s, name, namelen) sal_connect(s, name, namelen) /* rt-thread/components/net/sal_socket/include/socket/sys_socket/sys/socket.h */
|-> sal_connect /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> SAL_SOCKET_OBJ_GET /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> SAL_NETDEV_IS_UP /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> SAL_NETDEV_SOCKETOPS_VALID /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> pf->skt_ops->connect /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> at_connect /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> at_get_socket /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> sock->ops->at_connect /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> ec200x_socket_connect /* packages/at_device-v2.0.4/class/ec200x/at_socket_ec200x.c *
#define send(s, dataptr, size, flags) sal_sendto(s, dataptr, size, flags, NULL, NULL) /* rt-thread/components/net/sal_socket/include/socket/sys_socket/sys/socket.h */
#define sendto(s, dataptr, size, flags, to, tolen) sal_sendto(s, dataptr, size, flags, to, tolen) /* rt-thread/components/net/sal_socket/include/socket/sys_socket/sys/socket.h */
|-> sal_sendto /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> SAL_SOCKET_OBJ_GET /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> SAL_NETDEV_IS_UP /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> SAL_NETDEV_SOCKETOPS_VALID /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> pf->skt_ops->sendto /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> at_sendto /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> at_get_socket /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> sock->ops->at_send /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> ec200x_socket_send /* packages/at_device-v2.0.4/class/ec200x/at_socket_ec200x.c */
recv() 函数执行时,EC200x 接收的 URC 函数将数据放到 `recvpkt_list` 中,然后 recv() 函数从 `recvpkt_list` 中取出数据。
#define recv(s, mem, len, flags) sal_recvfrom(s, mem, len, flags, NULL, NULL) /* rt-thread/components/net/sal_socket/include/socket/sys_socket/sys/socket.h */
#define recvfrom(s, mem, len, flags, from, fromlen) sal_recvfrom(s, mem, len, flags, from, fromlen) /* rt-thread/components/net/sal_socket/include/socket/sys_socket/sys/socket.h */
|-> sal_recvfrom /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> SAL_SOCKET_OBJ_GET /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> SAL_NETDEV_IS_UP /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> SAL_NETDEV_SOCKETOPS_VALID /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> pf->skt_ops->recvfrom /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> at_recvfrom /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> at_get_socket /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> at_recvpkt_get(&(sock->recvpkt_list)...) /* 从链表中获取数据 rt-thread/components/net/at/at_socket/at_socket.c */
/* EC200x 接收的 URC 函数 */
urc_recv_func /* packages/at_device-v2.0.4/class/ec200x/at_socket_ec200x.c */
|-> recv_buf = (char *) rt_calloc(1, bfsz); /* 申请空间,供 at_recv_pkt 使用,挂载在 rlist 列表中 */
|-> at_client_obj_recv /* rt-thread/components/net/at/src/at_client.c */
|-> at_client_getchar /* rt-thread/components/net/at/src/at_client.c */
|-> at_evt_cb_set[AT_SOCKET_EVT_RECV](socket, AT_SOCKET_EVT_RECV, recv_buf, bfsz); /* packages/at_device-v2.0.4/class/ec200x/at_socket_ec200x.c */
|-> at_recv_notice_cb /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> at_recvpkt_put(&(sock->recvpkt_list), buff, bfsz); /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> pkt->buff = (char *) ptr; /* 将buff指向之前申请到的空间 rt-thread/components/net/at/at_socket/at_socket.c */
|-> rt_slist_append /* 挂载到链表中 */
#define closesocket(s) sal_closesocket(s) /* rt-thread/components/net/sal_socket/include/socket/sys_socket/sys/socket.h */
|-> sal_closesocket /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> SAL_SOCKET_OBJ_GET /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> SAL_NETDEV_SOCKETOPS_VALID /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> pf->skt_ops->closesocket /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> at_closesocket /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> sock->ops->at_closesocket /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> ec200x_socket_close /* packages/at_device-v2.0.4/class/ec200x/at_socket_ec200x.c */
|-> free_socket /* rt-thread/components/net/at/at_socket/at_socket.c */
|-> socket_delete /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> sock = sal_get_socket(socket); /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> sock->magic = 0; /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> sock->netdev = RT_NULL; /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> socket_free /* rt-thread/components/net/sal_socket/src/sal_socket.c */
|-> rt_free(sock); /* rt-thread/src/memheap.c */
|-> rt_memheap_free /* rt-thread/src/memheap.c */
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !