HarmonyOS小熊派 | HarmonyOS WiFi编程开发--Wifi连接热点

举报
Yuchuan 发表于 2021/08/08 18:06:39 2021/08/08
【摘要】 编写一个Wifi连接热点业务程序

BearPi-HM_Nano开发板WiFi编程开发——Wifi连接热点

本示例将演示如何在BearPi-HM_Nano开发板上编写一个Wifi连接热点业务程序

BearPi-HM_Nano

Wifi API分析

本案例主要使用了以下几个API完成Wifi联网

依赖文件:

//foundation/communication/wifi_lite/interfaces/wifiservice/wifi_device.h

//device/bearpi/bearpi_hm_nano/sdk_liteos/third_party/lwip_sack/include/lwip/netifapi.h

1、RegisterWifiEvent()

/**
 * @brief Registers a callback for a specified Wi-Fi event.
 *
 * The registered callback will be invoked when the Wi-Fi event defined in {@link WifiEvent} occurs. \n
 *
 * @param event Indicates the event for which the callback is to be registered.
 * @return Returns {@link WIFI_SUCCESS} if the callback is registered successfully; returns an error code defined
 * in {@link WifiErrorCode} otherwise.
 * @since 1.0
 * @version 1.0
 */
WifiErrorCode RegisterWifiEvent(WifiEvent* event);

描述: 为指定的Wi-Fi事件注册回调函数。当WifiEvent中定义的Wi-Fi事件发生时,将调用已注册的回调函数

参数:

名字 描述
event 表示要注册回调的事件.

2、EnableWifi()

/**
 * @brief Enables the station mode.
 *
 * @return Returns {@link WIFI_SUCCESS} if the station mode is enabled; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 1.0
 * @version 1.0
 */
WifiErrorCode EnableWifi(void);

描述:

启用STA模式

3、AddDeviceConfig()

/**
 * @brief Adds a specified hotspot configuration for connecting to a hotspot.
 *
 * This function generates a <b>networkId</b>. \n
 *
 * @param config Indicates the hotspot configuration to add.
 * @param result Indicates the generated <b>networkId</b>. Each <b>networkId</b> matches a hotspot configuration.
 * @return Returns {@link WIFI_SUCCESS} if the specified hotspot configuration is added; returns an error code defined
 * in {@link WifiErrorCode} otherwise.
 * @since 1.0
 * @version 1.0
 */
WifiErrorCode AddDeviceConfig(const WifiDeviceConfig* config, int* result);

描述:

添加用于配置连接到热点信息,此函数生成一个networkId

参数:

名字 描述
config 表示要连接的热点信息.
result 表示生成的networkId。每个networkId匹配一个热点配置

4、ConnectTo()

/**
 * @brief Connects to a hotspot matching a specified <b>networkId</b>.
 *
 * Before calling this function, call {@link AddDeviceConfig} to add a hotspot configuration. \n
 *
 * @param networkId Indicates the <b>networkId</b> matching the target hotspot.
 * @return Returns {@link WIFI_SUCCESS} if the hotspot is connected; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 1.0
 * @version 1.0
 */
WifiErrorCode ConnectTo(int networkId);

描述:

连接到指定networkId的热点

参数:

名字 描述
networkId 表示与目标热点匹配的网络id.

5、netifapi_netif_find()

/**
* @ingroup Threadsafe_Network_Interfaces
* @brief
*  This thread-safe interface is called when to find interface
*/
struct netif *netifapi_netif_find(const char *name);

描述:

获取netif用于IP操作

6、dhcp_start()

err_t dhcp_start(n)

描述:

启动DHCP, 获取IP

软件设计

主要代码分析

完成Wifi热点的连接需要以下几步

  1. 通过 RegisterWifiEvent 接口向系统注册扫描状态监听函数,用于接收扫描状态通知,如扫描动作是否完成等
  • OnWifiConnectionChangedCallBack 用于绑定连接状态监听函数,该回调函数有两个参数 state  info 

    • state表示扫描状态,取值为0和1,1表示热点连接成功;

    • info表示Wi-Fi连接信息,包含以下参数;

      名字 描述
      ssid [WIFI_MAX_SSID_LEN] 连接的热点名称.
      bssid [WIFI_MAC_LEN] MAC地址.
      rssi 接收信号强度(RSSI).
      connState Wifi连接状态.
      disconnectedReason Wi-Fi断开的原因.
  1. 调用 EnableWifi 接口,使能 Wifi。
  2. 调用 AddDeviceConfig 接口,配置连接的热点信息。
  3. 调用 ConnectTo 接口,连接到指定networkId的热点。
  4. 调用 WaitConnectResultData 接口等待,该函数中会有15s的时间去轮询连接成功标志位 staConnectSuccess,当 staConnectSuccess 为 1 时退出等待。
  5. 调用 netifapi_netif_find 接口,获取 netif 用于 IP 操作
  6. 调用 dhcp_start 接口,启动 DHCP, 获取 IP

yuchuan_wifi_sta_connect.c

#include <stdio.h>
#include <unistd.h>
#include <string.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_device.h"
#include "wifi_error_code.h"

#include "lwip/netif.h"
#include "lwip/netifapi.h"
#include "lwip/api_shell.h"

#define WIFI_STA_CONNECT_TASK_CB_SIZE 0U
#define WIFI_STA_CONNECT_TASK_STACK_SIZE 1024 * 4
#define WIFI_STA_CONNECT_TASK_PRIORITY 25
#define DEF_TIMEOUT 15
#define ONE_SECOND 1
#define SELECT_WLAN_PORT "wlan0"
#define SELECT_WIFI_SSID "520aini"
#define SELECT_WIFI_PASSWORD "abcd12345"
#define SELECT_WIFI_SECURITYTYPE WIFI_SEC_TYPE_PSK

static void WifiInit(void);
static void WaitScanResultData(void);
static int WaitConnectResultData(void);
static void OnWifiScanStateChangedCallBack(int state, int size);
static void OnWifiConnectionChangedCallBack(int state, WifiLinkedInfo *info);
static void OnHotspotStaJoinCallBack(StationInfo *info);
static void OnHotspotStaLeaveCallBack(StationInfo *info);
static void OnHotspotStateChangedCallBack(int state);

static int staConnectSuccess = 0;
static int staScanSuccess = 0;
static int ssidCount = 0;
WifiEvent wifiEventHandler = {0};
WifiErrorCode errorCode;

/* 扫描WiFi站点改变的回调函数 */
static void OnWifiScanStateChangedCallBack(int state, int size)
{
    (void)state;
    if (size > 0)
    {
        ssidCount = size;
        staScanSuccess = 1;
    }
    return;
}

/* 连接WiFi站点改变的回调函数 */
static void OnWifiConnectionChangedCallBack(int state, WifiLinkedInfo *info)
{
    (void)info;
    if (state > 0)
    {
        staConnectSuccess = 1;
        printf("WiFi Connect Success pls Happy play game!!!\r\n");
    }
    else
    {
        printf("WiFi Connect Falied pls check acount or passwd!!!\r\n");
    }
    return;
}

/* 热点加入站点的回调函数 */
static void OnHotspotStaJoinCallBack(StationInfo *info)
{
    (void)info;
    printf("Sta Join AP!!!\r\n");
    return;
}

/* 热点离开站点的回调函数 */
static void OnHotspotStaLeaveCallBack(StationInfo *info)
{
    (void)info;
    printf("OnHotspotStaLeaveCallBack: info is null!!!\r\n");
    return;
}

/* 热点状态改变的回调函数 */
static void OnHotspotStateChangedCallBack(int state)
{
    printf("OnHotspotStateChangedCallBack: state is %d.\r\n", state);
    return;
}

/* 初始化WIFI */
static void WifiInit(void)
{
    printf("Wifi Init Start ...\r\n");

    // void (*OnWifiScanStateChanged)(int state, int size);
    wifiEventHandler.OnWifiScanStateChanged = OnWifiScanStateChangedCallBack;
    // void (*OnWifiConnectionChanged)(int state, WifiLinkedInfo* info);
    wifiEventHandler.OnWifiConnectionChanged = OnWifiConnectionChangedCallBack;
    // void (*OnHotspotStaJoin)(StationInfo* info);
    wifiEventHandler.OnHotspotStaJoin = OnHotspotStaJoinCallBack;
    // void (*OnHotspotStaLeave)(StationInfo* info);
    wifiEventHandler.OnHotspotStaLeave = OnHotspotStaLeaveCallBack;
    // void (*OnHotspotStateChanged)(int state);
    wifiEventHandler.OnHotspotStateChanged = OnHotspotStateChangedCallBack;

    /* 注册WiFi事件 */
    // WifiErrorCode RegisterWifiEvent(WifiEvent* event);
    errorCode = RegisterWifiEvent(&wifiEventHandler);
    if (errorCode != WIFI_SUCCESS)
    {
        printf("YuchuanWiFiStaConnTask Register WiFi Event Falied!!!\r\n");
    }
    else
    {
        printf("YuchuanWiFiStaConnTask Register WiFi Event Successed!!!\r\n");
    }
}

/* 等待扫描数据结果 */
static void WaitScanResultData(void)
{
    int scanTimeOut = DEF_TIMEOUT;
    while (scanTimeOut > 0)
    {
        sleep(ONE_SECOND);
        scanTimeOut--;
        if (staScanSuccess == 1)
        {
            printf("WaitScanResultData: wait success[%d]s.\r\n", (DEF_TIMEOUT - scanTimeOut));
            break;
        }
    }
    if (scanTimeOut <= 0)
    {
        printf("WaitScanResultData: wait timeout!!!\r\n");
    }
}

/* 等待WiFi连接结果数据函数 */
static int WaitConnectResultData(void)
{
    int connectTimeout = DEF_TIMEOUT;
    while (connectTimeout > 0)
    {
        sleep(1);
        connectTimeout--;
        if (staConnectSuccess == 1)
        {
            printf("WaitConnectResultData:Wifi Connect Result Data Success[%d].\r\n", (DEF_TIMEOUT - connectTimeout));
            break;
        }
    }
    if (connectTimeout <= 0)
    {
        printf("WaitConnectResultData: WiFi Connect TimeOut!!!\r\n");
        return 0;
    }
    return 1;
}

/* connect wifi task function */
static BOOL yuchuanWifiStaConnTask(void)
{
    WifiScanInfo *info = NULL;
    unsigned int size = WIFI_SCAN_HOTSPOT_LIMIT;
    static struct netif *g_lwip_netif = NULL;
    WifiDeviceConfig select_ap_config = {0};

    // 延时2s
    osDelay(200);
    printf("system init ...\r\n");

    // 1、初始化WIFI
    WifiInit();

    // 2、使能WiFi
    // WifiErrorCode EnableWifi(void);
    errorCode = EnableWifi();
    if (errorCode != WIFI_SUCCESS)
    {
        printf("Enable WiFi Falied Error Code is %d.\r\n", errorCode);
        return -1;
    }

    // 3、判断WiFi是否激活
    // int IsWifiActive(void);
    if (IsWifiActive() == 0)
    {
        printf("WiFi is not Active!!!\r\n");
        return -1;
    }

    // 4、分配内存空间,保存获取到的WiFi信息
    info = malloc(sizeof(WifiScanInfo) * WIFI_SCAN_HOTSPOT_LIMIT);
    if (info == NULL)
    {
        return -1;
    }

    // 5、轮巡查询WiFi列表
    do
    {
        // 重置标志
        ssidCount = 0;
        staScanSuccess = 0;

        // 1、开始扫描
        errorCode = Scan();
        if (errorCode != WIFI_SUCCESS)
        {
            printf("WiFi Scan Falied Error Code is %d.\r\n", errorCode);
        }

        // 2、等待扫描结果
        WaitScanResultData();

        // 3、获取扫描列表
        // WifiErrorCode GetScanInfoList(WifiScanInfo* result, unsigned int* size);
        errorCode = GetScanInfoList(info, &size);
        if (errorCode != WIFI_SUCCESS)
        {
            printf("Get Scan WiFi List Info Falied!!!\r\n");
        }

    } while (staScanSuccess != 1);

    // 6、打印WiFi列表信息
    printf("***************以下为获取到的WiFi列表信息,请注意查收,谢谢.********************\r\n");
    for (uint8_t i = 0; i < ssidCount; i++)
    {
        printf("no:%03d, ssid:%-30s, rssi:%5d.\r\n", i + 1, info[i].ssid, info[i].rssi / 100);
    }
    printf("***************WiFi列表信息打印End********************\r\n");

    // 7、连接指定的WiFi
    for (uint8_t i = 0; i < ssidCount; i++)
    {
        if (strcmp(SELECT_WIFI_SSID, info[i].ssid) == 0)
        {
            int result;

            printf("Select:%3d wireless, Waiting...\r\n", i + 1);

            // 拷贝要连接的热点信息
            strcpy(select_ap_config.ssid, info[i].ssid);
            strcpy(select_ap_config.preSharedKey, SELECT_WIFI_PASSWORD);
            select_ap_config.securityType = SELECT_WIFI_SECURITYTYPE;

            // WifiErrorCode AddDeviceConfig(const WifiDeviceConfig* config, int* result);
            errorCode = AddDeviceConfig(&select_ap_config, &result);
            if (errorCode == WIFI_SUCCESS)
            {
                // WifiErrorCode ConnectTo(int networkId);
                errorCode = ConnectTo(result);
                if (errorCode == WIFI_SUCCESS && WaitConnectResultData() == 1)
                {
                    printf("WiFi Connect Successed Pls go ahead!!!\r\n");
                    // struct netif *netifapi_netif_find_by_name(const char *name);
                    g_lwip_netif = netifapi_netif_find(SELECT_WLAN_PORT);
                    break;
                }
            }
        }
        if (i == (ssidCount - 1))
        {
            printf("ERROR: No wifi as expected\r\n");
            while (1)
            {
                osDelay(100);
            }
        }
    }

    // 8、启动DHCP
    if (g_lwip_netif)
    {
        dhcp_start(g_lwip_netif);
        printf("Begain DHCP Start Work!!!\r\n");
    }

    // 9、等待DHCP
    for (;;)
    {
        if (dhcp_is_bound(g_lwip_netif) == ERR_OK)
        {
            printf("<-- DHCP state:OK -->\r\n");

            // 打印获取到的IP地址
            netifapi_netif_common(g_lwip_netif, dhcp_clients_info_show, NULL);
            break;
        }
        printf("<-- DHCP state:Inprogress -->\r\n");
        osDelay(100);
    }

    // 10、执行其他操作
    for (;;)
    {
        osDelay(100);
    }
}

/* wifi sta connect enter function */
static void YuchuanWifiStaConnect(void)
{
    osThreadAttr_t threadAttr;
    threadAttr.attr_bits = 0U;
    threadAttr.cb_mem = NULL;
    threadAttr.cb_size = WIFI_STA_CONNECT_TASK_CB_SIZE;
    threadAttr.stack_mem = NULL;
    threadAttr.stack_size = WIFI_STA_CONNECT_TASK_STACK_SIZE;
    threadAttr.priority = WIFI_STA_CONNECT_TASK_PRIORITY;

    threadAttr.name = "YuchuanWifiStaConnTask";

    if (osThreadNew((osThreadFunc_t)yuchuanWifiStaConnTask, NULL, &threadAttr) == NULL)
    {
        printf("Falied To Create YuchuanWifiStaConnTask!!!\r\n");
    }
}

APP_FEATURE_INIT(YuchuanWifiStaConnect);

编译调试

修改对接热点的账号密码

修改 yuchuan_wifi_sta_connect.c 热点账号密码

#define SELECT_WIFI_SSID "520aini"
#define SELECT_WIFI_PASSWORD "abcd12345"

修改 BUILD.gn 文件

//applications/sample/BearPi/BearPi-HM_Nano/sample/D2_YuchuanWifiStaConnect/BUILD.gn

static_library("yuchuanWiFiStaConnect"){
    sources = [
        "yuchuan_wifi_sta_connect.c",
    ]
    
    include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/kal/cmsis",
        "//foundation/communication/wifi_lite/interfaces/wifiservice",
    ]
}

修改 applications\BearPi\BearPi-HM_Nano\sample 路径下 BUILD.gn 文件,指定 yuchuanWiFiStaConnect 参与编译。

# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import("//build/lite/config/component/lite_component.gni")

lite_component("sample") {
    features = [
        #"A1_kernal_thread:thread_example",
        #"A2_kernel_timer:timer_example",
        #"A3_kernel_event:event_example",
        #"A4_kernel_mutex:mutex_example",
        #"A5_kernel_semaphore:semaphore_example",
        #"A6_kernel_message:message_example",

        #"B1_basic_led_blink:led_example",
        #"B2_basic_button:button_example",
        #"B3_basic_pwm_led:pwm_example",
        #"B4_basic_adc:adc_example", 
        #"B5_basic_i2c_nfc:i2c_example",
        #"B6_basic_uart:uart_example",
        
        #"C1_e53_sf1_mq2:e53_sf1_example",
        #"C2_e53_ia1_temp_humi_pls:e53_ia1_example",
        #"C3_e53_sc1_pls:e53_sc1_example",
        #"C4_e53_sc2_axis:e53_sc2_example",
        #"C5_e53_is1_infrared:e53_is1_example",

        #"D1_iot_wifi_ap:wifi_ap",
        #"D2_iot_wifi_sta_connect:wifi_sta_connect",        
        #"D3_iot_udp_client:udp_client",
        #"D4_iot_tcp_server:tcp_server",
        #"D5_iot_mqtt:iot_mqtt",        
        #"D6_iot_cloud_oc:oc_mqtt",
        #"D7_iot_cloud_onenet:onenet_mqtt",
        #"D8_iot_cloud_oc_smoke:cloud_oc_smoke",
        #"D9_iot_cloud_oc_light:cloud_oc_light",
        #"D10_iot_cloud_oc_manhole_cover:cloud_oc_manhole_cover",
        #"D11_iot_cloud_oc_infrared:cloud_oc_infrared",
        #"D12_iot_cloud_oc_agriculture:cloud_oc_agriculture",
        #"D13_iot_cloud_oc_gps:cloud_oc_gps",
        #"B1_YuchuanBasicLEDBlink:yuchuanLED",
        #"B2_YuchuanBasicButton:yuchuanButton",
        #"C1_YuchuanE53_SF1_MQ2:YuchuanE53SF1Mq2",
        #"C2_YuchuanE53IA1:yuchuanE53IA1",
        #"C3_YuchuanE53SC1:yuchuanE53SC1",
        #"LinuxCExample:linuxC",
        #"C4_YuchuanE53SC2:YuchuanE53SC2",
        #"C5_YuchuanE53IS1:YuchuanE53IS1",
        "D2_YuchuanWifiStaConnect:yuchuanWiFiStaConnect",
    ]
}

运行结果

示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,会打印连接到的Wifi热点信息。

ready to OS start
sdk ver:Hi3861V100R001C00SPC025 2020-09-03 18:10:00
formatting spiffs...
FileSystem mount ok.
wifi init success!

hiview init success.00 00:00:00 0 132 D 0/HIVIEW: log limit init success.
00 00:00:00 0 132 I 1/SAMGR: Bootstrap core services(count:3).
00 00:00:00 0 132 I 1/SAMGR: Init service:0x4b10c8 TaskPool:0xe503c
00 00:00:00 0 132 I 1/SAMGR: Init service:0x4b10d4 TaskPool:0xe505c
00 00:00:00 0 132 I 1/SAMGR: Init service:0x4b15a0 TaskPool:0xe507c
00 00:00:00 0 164 I 1/SAMGR: Init service 0x4b10d4 <time: 0ms> success!
00 00:00:00 0 64 I 1/SAMGR: Init service 0x4b10c8 <time: 0ms> success!
00 00:00:00 0 8 I 1/SAMGR: Init service 0x4b15a0 <time: 0ms> success!
00 00:00:00 0 8 I 1/SAMGR: Initialized all core system services!
00 00:00:00 0 64 I 1/SAMGR: Bootstrap system and application services(count:0).
00 00:00:00 0 64 I 1/SAMGR: Initialized all system and application services!
00 00:00:00 0 64 I 1/SAMGR: Bootstrap dynamic registered services(count:0).
system init ...
Wifi Init Start ...
YuchuanWiFiStaConnTask Register WiFi Event Successed!!!
+NOTICE:SCANFINISH
WaitScanResultData: wait success[1]s.
***************以下为获取到的WiFi列表信息,请注意查收,谢谢.********************
no:001, ssid:YuchuanHuaying                , rssi:  -44.
no:002, ssid:TP-LINK_5E52                  , rssi:  -69.
no:003, ssid:A-Lin                         , rssi:  -75.
no:004, ssid:@PHICOMM_4A                   , rssi:  -76.
no:005, ssid:KWONG_2.4G.ASUS               , rssi:  -82.
no:006, ssid:Liao                          , rssi:  -84.
no:007, ssid:xu                            , rssi:  -90.
no:008, ssid:Mobile WiFi                   , rssi:  -90.
***************WiFi列表信息打印End********************
Select:  1 wireless, Waiting...
+NOTICE:CONNECTED
WiFi Connect Success pls Happy play game!!!
WaitConnectResultData:Wifi Connect Result Data Success[1].
WiFi Connect Successed Pls go ahead!!!
Begain DHCP Start Work!!!
<-- DHCP state:Inprogress -->
<-- DHCP state:Inprogress -->
<-- DHCP state:Inprogress -->
<-- DHCP state:Inprogress -->
<-- DHCP state:OK -->
server :
        server_id : 192.168.43.1
        mask : 255.255.255.0, 1
        gw : 192.168.43.1
        T0 : 3600
        T1 : 1800
        T2 : 3150
clients <1> :
        mac_idx mac             addr            state   lease   tries   rto
        0       9411316bfc76    192.168.43.130  10      0       1       3

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。