BL808 RT-Thread Wi-Fi 驱动适配

2023/12/01 19:02
阅读数 25
BL808 WiFi 属于 SOC 单芯片型无线 MCU,片上集成 WiFi 功能,移植 RT-Thread 过程中,需要使用 RT-Thread wlan 框架。
RT-Thread wlan 框架是用于管理 Wi-Fi 驱动设备的框架,对下连接具体的 Wi-Fi 驱动,控制 Wi-Fi 的连接断开、扫描等操作,对上为应用提供统一的 Wi-Fi 控制接口。
wlan 框架主要有 3 部分组成:
  • dev 驱动接口层:为 wlan 框架提供统一的接口调用。
  • manage 管理层:为用户提供 Wi-Fi 扫描,链接,断线重连等功能。
  • protocol 协议:负责处理 Wi-Fi 产生的数据流,如 lwip。

使用了 wlan 驱动框架之后,Wi-Fi 驱动只需要关注 Wi-Fi 的连接、断开、扫描等动作,并通过 event 将相关动作告知 wlan 框架,由 wlan 框架根据收到的 event 管理 lwip。

1、使能 wlan 驱动

在 Linux 下 执行如下命令,并开启 wlan 驱动。

1$ scons --menuconfig
2RT-Thread Components  --->
3    Device Drivers  --->
4        [*] Using Wi-Fi framework  --->

开启 wlan 驱动后,默认会选中 lwip。

如 WiFi SOC 类芯片,原厂 SDK 中已经有线程管理 WiFi 数据收发,可关闭 lwip 中的 Rx thread 和 Tx thread,以节省系统资源。

1Network  --->
2    -*- LwIP: light weight TCP/IP stack  --->
3        [*]   Not use Rx thread
4        [*]   Not use Tx thread

2、wlan 驱动框架适配

初始化

通过 rt_wlan_dev_register() 注册 STATION 和 AP 设备,并将 wlan 设备接口函数注册进对应设备。

 1static const struct rt_wlan_dev_ops ops =
2{

3    .wlan_init = drv_wlan_init,
4    .wlan_mode = drv_wlan_mode,
5    .wlan_scan = drv_wlan_scan,
6    .wlan_join = drv_wlan_join,
7    .wlan_softap = drv_wlan_softap,
8    .wlan_disconnect = drv_wlan_disconnect,
9    .wlan_ap_stop = drv_wlan_ap_stop,
10    .wlan_ap_deauth = drv_wlan_ap_deauth,
11    .wlan_scan_stop = drv_wlan_scan_stop,
12    .wlan_get_rssi = drv_wlan_get_rssi,
13    .wlan_set_powersave = drv_wlan_set_powersave,
14    .wlan_get_powersave = drv_wlan_get_powersave,
15    .wlan_cfg_promisc = drv_wlan_cfg_promisc,
16    .wlan_cfg_filter = drv_wlan_cfg_filter,
17    .wlan_cfg_mgnt_filter = drv_wlan_cfg_mgnt_filter,
18    .wlan_set_channel = drv_wlan_set_channel,
19    .wlan_get_channel = drv_wlan_get_channel,
20    .wlan_set_country = drv_wlan_set_country,
21    .wlan_get_country = drv_wlan_get_country,
22    .wlan_set_mac = drv_wlan_set_mac,
23    .wlan_get_mac = drv_wlan_get_mac,
24    .wlan_recv = drv_wlan_recv,
25    .wlan_send = drv_wlan_send,
26};
27int rt_hw_wifi_init(void)
28
{
29    rt_err_t ret = RT_EOK;
30    static struct rt_wlan_device wlan0;
31    static struct rt_wlan_device wlan1;
32    memset(&wifi_sta, 0sizeof(wifi_sta));
33    ret = rt_wlan_dev_register(&wlan0, RT_WLAN_DEVICE_STA_NAME, &ops, 0, &wifi_sta);
34    wifi_sta.wlan = &wlan0;
35    memset(&wifi_ap, 0sizeof(wifi_ap));
36    ret |= rt_wlan_dev_register(&wlan1, RT_WLAN_DEVICE_AP_NAME, &ops, 0, &wifi_ap);
37    wifi_ap.wlan = &wlan1;
38    return ret;
39}
40INIT_DEVICE_EXPORT(rt_hw_wifi_init);

启动设备

在 main.c 中 加入 rt_wlan_set_mode 分别设置 STATION 和 AP 模式。

1int main(void)
2
{
3    rt_kprintf("Hello, RISC-V!\n");
4    /* set wifi work mode */
5    rt_wlan_set_mode(RT_WLAN_DEVICE_STA_NAME, RT_WLAN_STATION);
6    rt_wlan_set_mode(RT_WLAN_DEVICE_AP_NAME, RT_WLAN_AP);
7    return 0;
8}

接口实现

在 STATION 模式下,至少需要实现连接路由器 drv_wlan_join() 和断开路由器 drv_wlan_disconnect() 这 2 个函数。

在 AP 模式下,至少要实现 AP 开启 drv_wlan_softap 和 AP 关闭 drv_wlan_ap_stop() 这 2个函数。

这 4 个函数可以按照芯片 SDK 上的接口对应实现即可。

event 管理

在实现以上接口用,需要在 Wi-Fi 触发对应事件后,通过 event 通知 wlan 驱动框架。

在 STATION 模式下,当连接路由器成功后,通过 rt_wlan_dev_indicate_event_handle(wifi_sta.wlan, RT_WLAN_DEV_EVT_CONNECT, RT_NULL) 函数通知 wlan 框架 station 已经连接路由成功。当断开路由器后,通过 rt_wlan_dev_indicate_event_handle(wifi_sta.wlan, RT_WLAN_DEV_EVT_DISCONNECT, RT_NULL) 函数通过 wlan 框架 station 已经断开路由器。

wlan 框架在收到 RT_WLAN_DEV_EVT_CONNECT 时间后会通过 dhcp 服务获取 IP。

在 AP 模式下,开启软 AP 成功后,通过 rt_wlan_dev_indicate_event_handle(wifi_ap.wlan, RT_WLAN_DEV_EVT_AP_START, RT_NULL) 函数通知 wlan 框架 AP 模式开启成功。关闭软 AP 成功后,通过 rt_wlan_dev_indicate_event_handle(wifi_ap.wlan, RT_WLAN_DEV_EVT_AP_STOP, RT_NULL) 函数通知 wlan 框架软 AP 关闭。

wlan 框架在收到 RT_WLAN_DEV_EVT_AP_START 时间后会开启 DHCP_SERVER 服务。

采用了 RT-Thread wlan 驱动框架后,芯片 SDK 只需要负责管理 WiFi 相关的连接服务,而不需要管理 lwip 协议栈,

数据收发

上面说到 wlan 框架在收到对应的 evnet 后,负责启动 lwip 中的对应服务。

  • wlan 框架通过 drv_wlan_send() 函数将需要发送的网络数据包发输出去。针对WiFi 而言,需要通过判断设备是 station 还是 ap 后,将对应的数据包发送给 WiFi 。

1static int drv_wlan_send(struct rt_wlan_device *wlan, void *buff, int len)
2
{
3  if (wlan->user_data == &wifi_sta)
4      bl_wifi_tx(0, (struct pbuf *)buff);
5  else
6      bl_wifi_tx(1, (struct pbuf *)buff);
7  return RT_EOK;
8}
  • WiFi 设备接收到数据后,通过 rt_wlan_dev_report_data() 函数,将数据传递给 wlan 框架,wlan 框架会进一步通过 lwip 做进一步处理。

1int bl_wifi_rx(uint8_t idx, struct pbuf *p)
2
{
3  rt_err_t ret = RT_EOK;
4  if (idx == 0)
5      ret = rt_wlan_dev_report_data(wifi_sta.wlan, p, p->tot_len);
6  else
7      ret = rt_wlan_dev_report_data(wifi_ap.wlan, p, p->tot_len);
8  return ret;
9}

其他必须实现的接口

  • mac相关

主要实现 mac 地址读取和写入。

1static rt_err_t drv_wlan_set_mac(struct rt_wlan_device *wlan, rt_uint8_t mac[])
2
{
3  wifi_mgmr_sta_mac_set(mac);
4  return RT_EOK;
1static rt_err_t drv_wlan_get_mac(struct rt_wlan_device *wlan, rt_uint8_t mac[])
2
{
3  wifi_mgmr_sta_mac_get(mac);
4  return RT_EOK;
5}
  • Wi-Fi scan

 1static rt_err_t drv_wlan_scan(struct rt_wlan_device *wlan, struct rt_scan_info *scan_info)
2
{
3  int  channel_input_num = 0;
4  uint8_t channel_input[MAX_FIXED_CHANNELS_LIMIT] = {0};
5  const char *ssid = NULL;
6  uint8_t bssid[6] = {0xff0xff0xff0xff0xff0xff};
7  uint8_t scan_mode = SCAN_ACTIVE;
8  uint32_t duration_scan_us = 0;
9  if (scan_info != NULL && scan_info->ssid.len > 0)
10  {
11      ssid = scan_info->ssid.val;
12  }
13  if (wifi_mgmr_scan_adv(wlan, wifi_scan_complete_callback, channel_input, channel_input_num, bssid, ssid, scan_mode, duration_scan_us) != 0)
14      return -RT_ERROR;
15  return RT_EOK;
16}

BL808 WiFi 属于 SOC 单芯片型无线 MCU,片上集成 WiFi 功能,移植 RT-Thread 过程中,需要使用 RT-Thread wlan 框架。

版权声明:本文为RT-Thread论坛用户「燕十三」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://club.rt-thread.org/ask/article/c096fcdc37b26cef.html

———————End——————

新生态,创未来 | 2023RT-Thread 开发者大会开启报名


邀请你参加 2023 RT-Thread 开发者大会的大理由

1、刷新RT-Thread最新技术动态和产业服务能力

2、聆听行业大咖分享,洞察产业趋势

3、丰富的技术和产品展示,前沿技术发展和应用

4、绝佳的实践机会:AIOT、MPU、RISC-V...

5、精美伴手礼人手一份开发板盲盒和免费午餐

6、黑科技满点~滴水湖地铁口安排无人车接送至会场


立刻扫码报名吧


👇 点击报名开发者大会

本文分享自微信公众号 - RTThread物联网操作系统(RTThread)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部