Author: RT-Thread Community Developer Yan Shisan
The BL808 WiFi is a wireless MCU with a single chip SOC that integrates WiFi functionality on the chip. When porting RT-Thread, the RT-Thread wlan framework is used to manage Wi-Fi driver devices.
The RT-Thread wlan framework is like a conductor that connects to specific Wi-Fi drivers, controls Wi-Fi connection, disconnection, scanning, and other operations, and provides a unified Wi-Fi control interface to the application.
The wlan framework has three main parts:
After using the wlan driver framework, the Wi-Fi driver only needs to focus on the actions of connecting, disconnecting, scanning, etc., and inform the wlan framework of the relevant actions through events. The wlan framework manages lwip according to the received events.
1. To enable the wlan driver:
Execute the following command under Linux to enable the wlan driver.
1$ scons --menuconfig
2RT-Thread Components --->
3 Device Drivers --->
4 [*] Using Wi-Fi framework --->
By default, the wlan driver will select lwip after being enabled.
For WiFi SOC chips, the original SDK already has the thread to manage WiFi data transmission and reception. You can disable the Rx thread and Tx thread in lwip to save system resources.
1Network --->
2 -*- LwIP: light weight TCP/IP stack --->
3 [*] Not use Rx thread
4 [*] Not use Tx thread
2. Adapt the wlan driver framework
Initialization
Use rt_wlan_dev_register()
to register STATION and AP devices, and register the wlan device interface function with the corresponding device.
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, 0, sizeof(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, 0, sizeof(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);
Starting the device
In main.c
, add rt_wlan_set_mode
to set the STATION and AP modes separately.
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}
Interfaces Implementation
In STATION mode, at least two functions need to be implemented: drv_wlan_join()
to connect to the router and drv_wlan_disconnect()
to disconnect from the router.
In AP mode, at least two functions need to be implemented: drv_wlan_softap()
to start the AP and drv_wlan_ap_stop()
to stop the AP.
These four functions can be implemented according to the corresponding interfaces on the chip SDK.
Event Management
When implementing the above interfaces, you need to notify the wlan driver framework through events when the corresponding Wi-Fi events are triggered.
In STATION mode, when the router is successfully connected, use the rt_wlan_dev_indicate_event_handle(wifi_sta.wlan, RT_WLAN_DEV_EVT_CONNECT, RT_NULL)
function to notify the wlan framework that the station has successfully connected to the router. When the router is disconnected, use the rt_wlan_dev_indicate_event_handle(wifi_sta.wlan, RT_WLAN_DEV_EVT_DISCONNECT, RT_NULL)
function to notify the wlan framework that the station has disconnected from the router.
The wlan framework will obtain the IP address through the DHCP service after receiving the RT_WLAN_DEV_EVT_CONNECT event.
In AP mode, after the soft AP is successfully started, use the rt_wlan_dev_indicate_event_handle(wifi_ap.wlan, RT_WLAN_DEV_EVT_AP_START, RT_NULL)
function to notify the wlan framework that the AP mode has been successfully started. After the soft AP is successfully stopped, use the rt_wlan_dev_indicate_event_handle(wifi_ap.wlan, RT_WLAN_DEV_EVT_AP_STOP, RT_NULL)
function to notify the wlan framework that the soft AP has been stopped.
The wlan framework will start the DHCP_SERVER service after receiving the RT_WLAN_DEV_EVT_AP_START event.
After adopting the RT-Thread wlan driver framework, the chip SDK only needs to manage the Wi-Fi-related connection services, without managing the lwip protocol stack.
Data Transmission and Reception
As mentioned earlier, the wlan framework is responsible for starting the corresponding service in lwip after receiving the corresponding event.
drv_wlan_send()
function to send the required network data packets. For WiFi, the corresponding data packets need to be sent to WiFi by judging whether the device is a station or an AP.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}
rt_wlan_dev_report_data()
function to pass the data to the wlan framework, which further processes it through 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}
Other Required Interfaces
The main implementation is to read and write MAC addresses.
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}
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] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
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 is a wireless MCU with a single chip SOC that integrates WiFi functionality on the chip. When porting RT-Thread, the RT-Thread wlan framework needs to be used to manage Wi-Fi driver devices.