本文基于esp32c3说明如何配置使用wifi. 可以使用zephyr自带的esp32c3_devkitm进行验证.
esp32c3自带wifi和蓝牙,zephyr中wifi的数据通路通过ethernet的L2接入TCP/IP, wifi的控制通路通过wifi L2接入net_mgmt. 本文主要说明如何通过配置启用esp32c3,并演示如果使用net_mgmt进行wifi扫描,连接等操作。
配置
增加配置1
2
3
4
5
6
7
8
9
10
11
12
13
14# 启用WIFI
CONFIG_WIFI=y
CONFIG_WIFI_ESP32=y
# 启用网络
CONFIG_NETWORKING=y
CONFIG_NET_IPV4=y
# esp32c3的wifi数据通路是走ethernet,因此需要打开ethernet L2支持
CONFIG_NET_L2_ETHERNET=y
# esp32c3的wifi控制通路由net_mgmt管理,需要打开
CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y
在设备树中启用wifi1
2
3&wifi {
status = "okay";
};
Zephyr-3.2.0下 esp32c3使用的wifi节点没有实际的物理参数可配置,仅仅是用来标识启用该设备,如果不添加构建时会被Kconfig检查到报错1
warning: WIFI_ESP32 (defined at drivers/wifi/esp32/Kconfig.esp32:3) has direct dependencies DT_HAS_ESPRESSIF_ESP32_WIFI_ENABLED && !SMP && WIFI with value n, but is currently being y-selected by the following symbols:
代码
Zephyr对wifi的控制操作封装得非常简练,通过net_mgmt
进行控制请求, 结果直接返回或者是通过net_mgmt_init_event_callback/net_mgmt_add_event_callback
注册callback,在callback中处理控制请求的结果。
wifi控制请求
wifi控制的请求全部定义在include/zephyr/net/wifi_mgmt.h
中,有下面6种
NET_REQUEST_WIFI_SCAN
扫描AP节点NET_REQUEST_WIFI_CONNECT
连接AP节点NET_REQUEST_WIFI_DISCONNECT
断开连接NET_REQUEST_WIFI_AP_ENABLE
启用APNET_REQUEST_WIFI_AP_DISABLE
禁用APNET_REQUEST_WIFI_IFACE_STATUS
获取wifi接口状态,例如收发数据量的大小。注意这里获取不到信号强度的。
响应事件
对于请求,会有一些响应事件定义在include/zephyr/net/wifi_mgmt.h
中,有下面5种
NET_EVENT_WIFI_SCAN_RESULT
通知wifi扫描的结果NET_EVENT_WIFI_SCAN_DONE
通知wifi扫描已完成NET_EVENT_WIFI_CONNECT_RESULT
通知连接的结果NET_EVENT_WIFI_DISCONNECT_RESULT
通知断开连接的结果NET_EVENT_WIFI_IFACE_STATUS
通知wifi接口的状态
使用方法
扫描AP节点
1 | struct net_if *iface = net_if_get_default(); |
net_mgmt
执行NET_REQUEST_WIFI_SCAN
用于发动扫描AP,返回为0表示成功启动扫描,返回标准的errno表示失败。每扫到一个AP节点就有一次NET_EVENT_WIFI_SCAN_RESULT
,此时可以从callback获取到AP的信息, 本次扫描结束后产生NET_EVENT_WIFI_SCAN_DONE
.
连接和断开AP节点
1 | struct net_if *iface = net_if_get_default(); |
net_mgmt
执行NET_REQUEST_WIFI_CONNECT
用于执行连接动作,无论连接成功还是失败都会收到NET_EVENT_WIFI_CONNECT_RESULT
, 在callback中可以判断连接的结果。
1 | struct net_if *iface = net_if_get_default(); |
net_mgmt
执行NET_REQUEST_WIFI_DISCONNECT
用于执行断开连接动作,如果返回的状态为-EALREADY
表示已经断开。断开连接时会收到NET_EVENT_WIFI_DISCONNECT_RESULT
, 注意:即便没有执行NET_REQUEST_WIFI_DISCONNECT
而是因为AP主动断开,也会有NET_EVENT_WIFI_DISCONNECT_RESULT
产生
启用和禁用AP模式
通过设置可以让esp32c3处于AP模式1
2
3
4
5
6static struct wifi_connect_req_params ap_params;
// 设置ap_params和连接的参数方式一样,这里不再列出
int ret net_mgmt(NET_REQUEST_WIFI_AP_ENABLE, iface,
&ap_params, sizeof(struct wifi_connect_req_params))
net_mgmt
执行NET_REQUEST_WIFI_AP_ENABLE
用于启用AP模式,不会有事件产生
1 | int ret net_mgmt(NET_REQUEST_WIFI_AP_DISABLE, iface, |
net_mgmt
执行NET_REQUEST_WIFI_AP_DISABLE
用于启用AP模式,不会有事件产生
获取WIFI的接口状态
只有在配置了CONFIG_NET_STATISTICS_WIFI=y
和CONFIG_NET_STATISTICS_USER_API=y
的情况下才能获取状态1
2
3
4
5
6struct net_if *iface = net_if_get_default();
struct net_stats_wifi stats = { 0 };
int ret;
ret = net_mgmt(NET_REQUEST_STATS_GET_WIFI, iface,
&stats, sizeof(stats));
抓取的状态是接口收到的包统计而不是信号强度1
2
3
4
5
6
7
8struct net_stats_wifi {
struct net_stats_sta_mgmt sta_mgmt;
struct net_stats_bytes bytes;
struct net_stats_pkts pkts;
struct net_stats_pkts broadcast;
struct net_stats_pkts multicast;
struct net_stats_pkts errors;
};
由于状态可以及时返回,我们不需要再去处理NET_EVENT_WIFI_IFACE_STATUS
注册事件处理回调
事件处理回调用于处理响应事件, 首先注册回调1
2
3
4
5
6
7
8
9
10
11static struct net_mgmt_event_callback wifi_mgmt_cb;
//初始化,可以指定要响应那些事件
net_mgmt_init_event_callback(&wifi_mgmt_cb,
wifi_mgmt_event_handler,
(NET_EVENT_WIFI_SCAN_RESULT | \
NET_EVENT_WIFI_SCAN_DONE | \
NET_EVENT_WIFI_CONNECT_RESULT | \
NET_EVENT_WIFI_DISCONNECT_RESULT));
net_mgmt_add_event_callback(&wifi_mgmt_cb);
回调内依照event的不同分别处理1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb,
uint32_t mgmt_event, struct net_if *iface)
{
switch (mgmt_event) {
case NET_EVENT_WIFI_SCAN_RESULT:
{
//CB中的信息就是scan的结果
const struct wifi_scan_result *entry = (const struct wifi_scan_result *)cb->info;
}
break;
case NET_EVENT_WIFI_SCAN_DONE:
{
//CB中的信息是wifi状态
const struct wifi_status *status = (const struct wifi_status *)cb->info;
}
break;
case NET_EVENT_WIFI_CONNECT_RESULT:
{
//CB中的信息是wifi状态
const struct wifi_status *status = (const struct wifi_status *)cb->info;
}
break;
case NET_EVENT_WIFI_DISCONNECT_RESULT:
{
//CB中的信息是wifi状态
const struct wifi_status *status = (const struct wifi_status *)cb->info;
}
break;
default:
break;
}
}
不同的事件按照不同的结构来解析cb->info
, NET_EVENT_WIFI_SCAN_RESULT
按照struct wifi_scan_result
进行解析1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24struct wifi_scan_result {
//SSID
uint8_t ssid[WIFI_SSID_MAX_LEN];
uint8_t ssid_length;
// AP带宽
uint8_t band;
// AP的工作channel
uint8_t channel;
//密码验证方式
enum wifi_security_type security;
// 管理帧保护
enum wifi_mfp_options mfp;
//信号强度
int8_t rssi;
//BSSID
uint8_t mac[WIFI_MAC_ADDR_LEN];
uint8_t mac_length;
};
wifi的状态按照如下结构解析1
2
3struct wifi_status {
int status;
};
不同的事件status
含义不一样:
NET_EVENT_WIFI_SCAN_DONE
0表示扫描正常结束,其它为不正常结束NET_EVENT_WIFI_CONNECT_RESULT
0表示连接成功,其它为连接失败NET_EVENT_WIFI_DISCONNECT_RESULT
0表示断开连接成功,其它为断开连接失败
代码分析指南
目前zephyr中wifi的控制都是通过驱动注册的struct net_wifi_mgmt_offload
的API来进行,因此wifi的管理实现并不复杂,主要实现在subsys/net/l2/wifi/wifi_mgmt.c
中,例如:
由mgmt的宏包装实现函数1
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_CONNECT, wifi_connect);
再由实现函数调用offload API1
2
3
4
5
6
7
8
9
10
11
12static int wifi_connect(uint32_t mgmt_request, struct net_if *iface,
void *data, size_t len)
{
//找到驱动的device
const struct device *dev = net_if_get_device(iface);
//加载驱动的offload API
struct net_wifi_mgmt_offload *off_api =
(struct net_wifi_mgmt_offload *) dev->api
//调用驱动的offload API
return off_api->connect(dev, params);
}
offload api再向下就对接到驱动中,esp32c3对接到的是drivers/wifi/esp32/src/esp_wifi_drv.c
的esp32_wifi_scan
1
2
3
4
5
6
7
8
9
10static const struct net_wifi_mgmt_offload esp32_api = {
.wifi_iface.iface_api.init = esp32_wifi_init,
.wifi_iface.send = esp32_wifi_send,
.wifi_iface.get_stats = esp32_wifi_stats,
.scan = esp32_wifi_scan,
.connect = esp32_wifi_connect,
.disconnect = esp32_wifi_disconnect,
.ap_enable = esp32_wifi_ap_enable,
.ap_disable = esp32_wifi_ap_disable,
};
对上net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &cnx_params, sizeof(struct wifi_connect_req_params))
如何调用到wifi_connect
可以参考Zephyr网络管理模块分析-注册请求机制一文.