网络管理器(netmgr)
概述
网络管理器负责所有网络的联网管理功能,具体如下:
- 链路层的开启/初始化/配置/复位等
- 链路层设备信息的获取
- 链路层事件的处理和转发(linkup,linkdown)
- 网络IP的配置(DHCP或者静态IP)
Netmgr根据联网管理的需要,调用到对应设备的网络层和链路层接口函数。YoC将不同类型的网络连接外设都看作是具有网络层功能和链路层功能的外设,这样就可以统一所有的网络设备。网络管理器设计如下图所示:
Netmgr各层次功能如下:
- HAL层:是驱动适配层的函数指针封装。
- 驱动适配层:实现网络层接口(如mac、dns、ip地址等获取和配置)和链路层接口(如对于wifi设备来说,需要对接wifi_impl.h定义的接口)
- 设备实现层:实现了网络连接设备相关的一些操作
其中对于wifi设备来说,驱动移植请参考此说明。
网络管理器接口
初始化
网络设备初始化
netmgr_hdl_t netmgr_dev_eth_init(); ///< 有线网络设备初始化
netmgr_hdl_t netmgr_dev_gprs_init(); ///< GPRS设备初始化
netmgr_hdl_t netmgr_dev_wifi_init(); ///< 无线设备初始化
netmgr_hdl_t netmgr_dev_nbiot_init(); ///< NB-IOT设备初始化
网络设备初始化。以netmgr_dev_wifi_init为例,该函数会注册netmgr_dev_t结构中的provision配网等回调函数。同时打开已注册的wifi设备节点,调用该设备实现的hal层初始化接口。同时将该设备加入到网络设备列表中统一管理。
netmgr_hdl_t类型为一个声明为void*的指针,实际指向netmgr_dev_t结构体,详细定义如下:
#define NETMGR_NAME_LEN (16)
typedef struct netmgr_dev_s {
slist_t next; ///< 指向下一个网络设备(向后扩展,如果存在多个)
char name[NETMGR_NAME_LEN]; ///< 当前网络设备的名称
union {
wifi_setting_t wifi_config;
eth_setting_t eth_config;
gprs_setting_t gprs_config;
} config; ///< 存储相关配置。对于wifi来说,存储ssid名称、密码等信息
uint8_t dhcp_en; ///< 是否使能dhcp功能
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gw;
int (*provision)(struct netmgr_dev_s *node); ///< 开启链路层服务,使能配网
int (*unprovision)(struct netmgr_dev_s *node); ///< 关闭链路层服务
int (*info)(struct netmgr_dev_s *node); ///< 获取网络连接信息,如ip/dns/netmask、网卡连接状态等
int (*reset)(struct netmgr_dev_s *node); ///< 重置链路层服务
aos_dev_t *dev; ///< 指向打开的网络设备节点
int is_gotip;
int is_linkup; ///< 网络设备链路层是否up起来
} netmgr_dev_t;
返回值:
调用失败时返回NULL
注意事项:
- 当前YoC平台最多同时仅支持一个网络设备。暂时不支持多个网络设备共存
- 调用某网络设备初始化前,需要先注册对应的设备驱动。如对于rtl8723ds无线网络芯片来说需要注册wifi_rtl8723ds_register驱动
服务初始化
void netmgr_service_init(utask_t *task)
初始化网络管理微服务。若外部微任务task为空,则内部创建微任务。同时将微服务加入到微任务中。
网络设备配置
当配置好网络设备必要的参数后,即可通过调用netmgr_start开始网络连接。
无线配置
int netmgr_config_wifi(netmgr_hdl_t hdl, char *ssid, uint8_t ssid_length, char *psk, uint8_t psk_length);
配置无线设备的ssid名称和对应的秘钥psk。
若定义了CONFIG_KV_SMART配置,如在某solution下的package.yaml中配置了CONFIG_KV_SMART: 1
,则ssid和psk同时会被存储到kv文件系统中。对应的key定义如下:
#define KV_WIFI_SSID "wifi_ssid"
#define KV_WIFI_PSK "wifi_psk"
返回值:
调用成功时返回0,否则返回-1。
有线配置
int netmgr_config_eth(netmgr_hdl_t hdl, eth_mac_duplex_e duplex, eth_mac_speed_e speed);
配置有线网卡的双工模式duplex和工作速率speed。
与无线配置一样,若使能CONFIG_KV_SMART配置,duplex和speed同时会被存储到kv文件系统中。对应的key定义如下:
#define KV_ETH_DUPLEX "eth_dup"
#define KV_ETH_SPEED "eth_speed"
返回值:
调用成功时返回0,否则返回-1。
GPRS配置
int netmgr_config_gprs(netmgr_hdl_t hdl, int mode);
配置GPRS的工作模式mode。当前尚未实现,预留。
返回值:
调用成功时返回0,否则返回-1。
网络管理操作
使能网络设备连接
int netmgr_start(netmgr_hdl_t hdl);
当网络参数配置后,就可以调用该接口使能指定网络设备开始正常工作。该函数最终会调用到对应网络设备初始化配置的provision配网回调。
该接口是非阻塞的,网络连接成功后,网络管理器会上报EVENT_NETMGR_GOT_IP事件,否则上报EVENT_NETMGR_NET_DISCON事件。应用开发者可通过event_subscribe接口订阅这两个消息来判断网络是否连接成功。用户也可通过调用netmgr_is_gotip判断是否正常获取到ip。
返回值:
调用成功时返回0,否则返回-1。
重置网络连接
int netmgr_reset(netmgr_hdl_t hdl, uint32_t sec);
复位网络设备连接,并在指定sec秒后自动重连。当sec为0时,复位后立即重连。该函数最终会调用到对应网络设备初始化配置的reset配网回调。该接口是非阻塞的。
返回值:
调用成功时返回0,否则返回-1。
停止网络连接
int netmgr_stop(netmgr_hdl_t hdl);
停止指定网络设备运行。该函数最终会调用到对应网络设备初始化配置的unprovision配网回调。该接口是阻塞的。
返回值:
调用成功时返回0,否则返回-1。
网络设备信息/状态获取
获取设备句柄
netmgr_hdl_t netmgr_get_handle(const char *name);
根据网络设备名称获取网络管理器句柄,上层无需保存。该接口根据网络设备名从内部维护的网络设备列表中查找对应的句柄。网络设备对应的名称如下表所示:
网络设备 | 设备名 |
---|---|
无线网卡 | wifi |
有线网卡 | eth |
GPRS | gprs |
NB-IoT | nbiot |
返回值:
调用失败时返回NULL
网络设备是否获取到ip
int netmgr_is_gotip(netmgr_hdl_t hdl);
指定hdl的网络设备是否获取到ip。
返回值:
当前网络设备已经成功获取到ip时返回1,否则返回0
网络管理器的适配
底层网络芯片适配到网络管理器时需要实现网络层net_ops_t定义的接口(如mac、dns、ip地址等获取和配置)和链路层定义的接口(如对于wifi设备来说,需要实现wifi_driver_t定义的接口)。这两层封装的接口通过提供的HAL接口由上层网络管理器调用。
rtl8723ds无线网卡适配
// 网络层接口
static net_ops_t rtl8723ds_net_driver = {
.set_mac_addr = rtl8723ds_set_mac_addr,
.get_mac_addr = rtl8723ds_get_mac_addr,
.set_dns_server = rtl8723ds_set_dns_server,
.get_dns_server = rtl8723ds_get_dns_server,
.set_hostname = rtl8723ds_set_hostname,
.get_hostname = rtl8723ds_get_hostname,
.start_dhcp = rtl8723ds_start_dhcp,
.stop_dhcp = rtl8723ds_stop_dhcp,
.set_ipaddr = rtl8723ds_set_ipaddr,
.get_ipaddr = rtl8723ds_get_ipaddr,
.subscribe = rtl8723ds_subscribe,
.ping = rtl8723ds_ping_remote,
};
// wifi 定义的链路层接口
static wifi_driver_t rtl8723ds_wifi_driver = {
.init = rtl8723ds_init,
.deinit = rtl8723ds_deinit,
.reset = rtl8723ds_reset,
.set_mode = rtl8723ds_set_mode,
.get_mode = rtl8723ds_get_mode,
.install_event_cb = rtl8723ds_install_event_cb,
.set_protocol = rtl8723ds_set_protocol,
.get_protocol = rtl8723ds_get_protocol,
.set_country = rtl8723ds_set_country,
.get_country = rtl8723ds_get_country,
.set_mac_addr = rtl8723ds_set_mac_addr,
.get_mac_addr = rtl8723ds_get_mac_addr,
.set_auto_reconnect = rtl8723ds_set_auto_reconnect,
.get_auto_reconnect = rtl8723ds_get_auto_reconnect,
.set_lpm = rtl8723ds_set_lpm,
.get_lpm = rtl8723ds_get_lpm,
.power_on = rtl8723ds_power_on,
.power_off = rtl8723ds_power_off,
.start_scan = rtl8723ds_start_scan,
.start = rtl8723ds_start,
.stop = rtl8723ds_stop,
.sta_get_link_status = rtl8723ds_sta_get_link_status,
.ap_get_sta_list = rtl8723ds_ap_get_sta_list,
/** promiscuous APIs */
.start_monitor = rtl8723ds_start_monitor,
.stop_monitor = rtl8723ds_stop_monitor,
.send_80211_raw_frame = rtl8723ds_send_80211_raw_frame,
.set_channel = rtl8723ds_set_channel,
.get_channel = rtl8723ds_get_channel,
.set_smartcfg = NULL,
};
static netdev_driver_t rtl8723ds_driver = {
.drv =
{
.name = "wifi",
.init = rtl8723ds_dev_init,
.uninit = rtl8723ds_dev_uninit,
.open = rtl8723ds_dev_open,
.close = rtl8723ds_dev_close,
},
.link_type = NETDEV_TYPE_WIFI,
.net_ops = &rtl8723ds_net_driver,
.link_ops = &rtl8723ds_wifi_driver,
};
void wifi_rtl8723ds_register(rtl8723ds_gpio_pin *config)
{
if (config) {
memcpy(&g_gpio_config, config, sizeof(rtl8723ds_gpio_pin));
} else {
LOGE(TAG, "Err:Please input gpio config\n");
return;
}
gpio_pin_handle_t wl_en_pin;
/* 网络主芯片上电管脚配置 */
if (config->power != 0xFFFFFFFF) {
LOGD(TAG, "pull up WLAN power\n");
drv_pinmux_config(g_gpio_config.power, PIN_FUNC_GPIO);
power_pin = csi_gpio_pin_initialize(g_gpio_config.power, NULL);
csi_gpio_pin_config_mode(power_pin, GPIO_MODE_PUSH_PULL);
csi_gpio_pin_config_direction(power_pin, GPIO_DIRECTION_OUTPUT);
csi_gpio_pin_write(power_pin, 1);
}
/* WLAN使能管脚配置 */
if (config->wl_en != 0xFFFFFFFF) {
LOGD(TAG, "Init WLAN enable\n");
drv_pinmux_config(g_gpio_config.wl_en, PIN_FUNC_GPIO);
wl_en_pin = csi_gpio_pin_initialize(g_gpio_config.wl_en, NULL);
csi_gpio_pin_config_mode(wl_en_pin, GPIO_MODE_PUSH_PULL);
csi_gpio_pin_config_direction(wl_en_pin, GPIO_DIRECTION_OUTPUT);
csi_gpio_pin_write(wl_en_pin, 1);
}
extern SDIO_BUS_OPS rtw_sdio_bus_ops;
rtw_sdio_bus_ops.bus_probe();
// 初始化lwip网络协议栈
LwIP_Init();
wifi_manager_init();
// 注册rtl8723ds驱动,调用注册的rtl8723ds_dev_init函数
driver_register(&rtl8723ds_driver.drv, NULL, 0);
}
实现netdev_driver_t结构中的网络层接口net_ops和链路层接口link_ops。网络管理器在配网时需要使用这两层的相关接口。
网络管理器的使用示例
rtl8723ds无线网卡连接
示例代码如下:
#define PIN_WI_EN PA16
#define PIN_POWER_EN 0xFFFFFFFF
/* network event callback */
void user_local_event_cb(uint32_t event_id, const void *param, void *context)
{
char url[128];
if (event_id == EVENT_NETMGR_GOT_IP) { // 网络连接成功
LOGD(TAG, "Net up");
} else if (event_id == EVENT_NETMGR_NET_DISCON) {
if ((int)param == NET_DISCON_REASON_DHCP_ERROR) {
LOGD(TAG, "Net down");
netmgr_reset(netmgr_get_handle("wifi"), 30); // 本次网络连接失败,30s后自动重连
}
}
}
static netmgr_hdl_t network_init()
{
/* kv config check */
aos_kv_setstring("wifi_ssid", "your ssid"); // 配置无线网络的名称和密码,并使能wifi
aos_kv_setstring"wifi_psk", "your psk");
aos_kv_setint("wifi_en", 1);
netmgr_hdl_t netmgr_hdl = netmgr_dev_wifi_init(); // 初始化wifi网卡
netmgr_service_init(NULL); // 初始化网络管理服务
if (netmgr_hdl)
netmgr_start(netmgr_hdl); // 启动wifi管理器
return netmgr_hdl;
}
void main()
{
board_yoc_init();
/* init wifi driver and network */
rtl8723ds_gpio_pin pin = {
.wl_en = PIN_WI_EN,
.power = PIN_POWER_EN,
};
wifi_rtl8723ds_register(&pin);// 根据rtl8723ds网卡相应的管脚注册无线网卡驱动
network_init();
/* 系统事件订阅 */
event_subscribe(EVENT_NETMGR_GOT_IP, user_local_event_cb, NULL); // 订阅网络连接成功事件
event_subscribe(EVENT_NETMGR_NET_DISCON, user_local_event_cb, NULL); // 订阅网络连接失败事件
}