RT-Thread操作系统 AT组件源码分析(以 EC20 为例)

  AT组件的核心处理逻辑是将收到的 AT 模组的应答信息放到 recv_line_buf 缓冲区中,然后每次读一行数据(“\r\n”)进行处理,然后判断属于哪一类的消息,调用不同的函数。
  本文以 EC200x 模组为例,详细分析了 AT 组件的实现过程和代码的调用逻辑,帮助在使用 AT 组件过程中遇到问题的开发者快速定位问题出现的位置。

1 AT 组件

1.1 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-v2.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 个字节,以解决栈溢出的问题。

1.2 AT 命令打印使能设置

  在调试时可以通过修改 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..

1.3 GPRS 网络注册状态检查

  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);                                                       /* 禁用相应的网卡设备 */

1.4 EC200x 是否能连接外网日志输出

  rt-thread/components/net/sal_socket/src/sal_socket.ccheck_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;

1.5 AT 设备注册过程

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 */

1.6 AT 设备类注册过程

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 */

1.7 网卡的启用与禁用

1.7.1 启用网卡的执行过程
/* 启用网卡 */
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 */
1.7.2 禁用网卡的执行过程
/* 禁用网卡 */
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 */

1.8 socket 编程源码分析

1.8.1 socket 执行过程
#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 */
1.8.2 connect 函数执行过程
#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 */
1.8.3 send 函数执行过程
#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 */
1.8.4 recv 函数执行过程

  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                                                     /* 挂载到链表中 */
1.8.5 closesocket 函数执行过程
#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 */
  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
RT-Thread诞生于2006年,是一款以开源、中立、社区化发展起来的物联网操作系统RT-Thread主要采用 C 语言编写,浅显易懂,且具有方便移植的特性(可快速移植到多种主流 MCU 及模组芯片上)。RT-Thread把面向对象的设计方法应用到实时系统设计中,使得代码风格优雅、架构清晰、系统模块化并且可裁剪性非常好。 RT-Thread有完整版和Nano版,对于资源受限的微控制器(MCU)系统,可通过简单易用的工具,裁剪出仅需要 3KB Flash、1.2KB RAM 内存资源的 NANO 内核版本;而相对资源丰富的物联网设备,可使用RT-Thread完整版,通过在线的软件包管理工具,配合系统配置工具实现直观快速的模块化裁剪,并且可以无缝地导入丰富的软件功能包,实现类似 Android 的图形界面及触摸滑动效果、智能语音交互效果等复杂功能。 RT-Thread架构 RT-Thread是一个集实时操作系统RTOS)内核、中间件组件的物联网操作系统,架构如下: 内核层:RT-Thread内核,是 RT-Thread的核心部分,包括了内核系统中对象的实现,例如多线程及其调度、信号量、邮箱、消息队列、内存管理、定时器等;libcpu/BSP(芯片移植相关文件 / 板级支持包)与硬件密切相关,由外设驱动和 CPU 移植构成。 组件与服务层:组件是基于 RT-Thread内核之上的上层软件,例如虚拟文件系统、FinSH命令行界面、网络框架、设备框架等。采用模块化设计,做到组件内部高内聚,组件之间低耦合。 RT-Thread软件包:运行于 RT-Thread物联网操作系统平台上,面向不同应用领域的通用软件组件,由描述信息、源代码或库文件组成。RT-Thread提供了开放的软件包平台,这里存放了官方提供或开发者提供的软件包,该平台为开发者提供了众多可重用软件包的选择,这也是 RT-Thread生态的重要组成部分。软件包生态对于一个操作系统的选择至关重要,因为这些软件包具有很强的可重用性,模块化程度很高,极大的方便应用开发者在最短时间内,打造出自己想要的系统。RT-Thread已经支持的软件包数量已经达到 180+。 RT-Thread的特点: 资源占用极低,超低功耗设计,最小内核(Nano版本)仅需1.2KB RAM,3KB Flash。 组件丰富,繁荣发展的软件包生态 。 简单易用 ,优雅的代码风格,易于阅读、掌握。 高度可伸缩,优质的可伸缩的软件架构,松耦合,模块化,易于裁剪和扩展。 强大,支持高性能应用。 跨平台、芯片支持广泛。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
RT-Thread操作系统资料包是为了方便开发者了解和使用RT-Thread操作系统而提供的一系列资料资源。 首先,RT-Thread操作系统资料包包含了操作系统的详细介绍和架构说明,让开发者能够了解RT-Thread的基本原理和设计思想。这对于初次接触RT-Thread的开发者来说是非常有价值的,可以帮助他们更好地理解操作系统的工作机制。 其次,RT-Thread操作系统资料包还提供了丰富的应用实例和案例分析,这些案例涵盖了不同领域的项目,如嵌入式系统、物联网设备等。这些实例可以帮助开发者更加直观地了解RT-Thread的功能和特性,以及如何在实际项目中使用RT-Thread进行开发。 此外,RT-Thread操作系统资料包还包含了详细的开发文档和API参考手册,这些文档可以为开发者提供操作系统的使用方法和开发技巧。开发者可以根据文档中的指导来进行基于RT-Thread的应用开发,从而提高开发效率和减少开发难度。 最后,RT-Thread操作系统资料包还提供了相关的开发工具和驱动程序,这些工具和驱动可以帮助开发者更好地进行开发和调试工作。开发者可以通过这些工具和驱动来实现硬件与操作系统的有效交互,加快项目的开发进度。 总的来说,RT-Thread操作系统资料包是一套全面而实用的开发资源,可以帮助开发者更好地理解和使用RT-Thread操作系统,提高开发效率和项目的成功率。无论是新手还是有经验的开发者,都能从中获得帮助和指导。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值