• 《HarmonyOS开发 – OpenHarmony开发笔记(基于小型系统)》第5章 WiFi联网(STA模式)


    开发环境:
    开发系统:Ubuntu 20.04
    开发板:Pegasus物联网开发板
    MCU:Hi3861
    OpenHarmony版本:3.0.1-LTS

    HI3861默认已经初始化了WiFi,因此这里讲解如何使用WiFi联网。

    5.1使用AT联网

    串口终端上执行相应的AT命令,即可使Hi3861 WLAN模组联网,依次执行如下AT命令,启动STA模式,连接指定路由器,并开启DHCP功能配置IP地址。

    AT+STARTSTA                             # 启动STA模式
    AT+SCAN                                 # 扫描周边AP
    AT+SCANRESULT                           # 显示扫描结果
    AT+CONN="SSID",,2,"PASSWORD"            # 连接指定AP,其中SSID/PASSWORD为待连接的热点名称和密码
    AT+STASTAT                              # 查看连接结果
    AT+DHCP=wlan0,1                         # 通过DHCP向AP请求wlan0的IP地址
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    查看Hi3861 WLAN模组与网关联通是否正常,如下所示。

    AT+IFCFG                                # 查看模组接口IP
    AT+PING=X.X.X.X                         # 检查模组与网关的联通性,其中X.X.X.X需替换为实际的网关地址
    
    • 1
    • 2

    下面具体演示:

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    有上图可知Hi3861 WLAN模组联网成功。

    当然也可在同一个局域网中ping HI3861。

    在这里插入图片描述

    说明网络是连通的。

    关于Wifi联网的AT命令有很多,所有的AT指令都是通过函数hi_at_sys_cmd_register() 函数注册的,其中调用了hi_at_register_cmd()函数注册AT。

    重点介绍三个函数。

    1.启动WiFi STA模式, AT+STARTSTA

    hi_u32 cmd_sta_start_adv(hi_s32 argc, const hi_char *argv[])
    {
        hi_s32  ret;
        hi_wifi_bw bw = HI_WIFI_BW_LEGACY_20M;
    
        if (argc != 3) { /* "+STARTSTA" command fix 3 parameters */
            return HI_ERR_FAILURE;
        }
    
        ret = (hi_s32)sta_start_adv_param(argc, argv, &bw);
        if (ret != HI_ERR_SUCCESS) {
            return HI_ERR_FAILURE;
        }
    #ifndef CONFIG_FACTORY_TEST_MODE
        hi_char ifname[WIFI_IFNAME_MAX_SIZE + 1] = {0};
        hi_s32  len = sizeof(ifname);
        ret = hi_wifi_sta_start(ifname, &len);
        if (ret != HISI_OK) {
            return HI_ERR_FAILURE;
        }
    #endif
        ret = hi_wifi_set_bandwidth(DEFAULT_IFNAME_STA, strlen(DEFAULT_IFNAME_STA) + 1, bw);
        if (ret != HI_ERR_SUCCESS) {
    #ifndef CONFIG_FACTORY_TEST_MODE
            hi_wifi_sta_stop();
    #endif
            return HI_ERR_FAILURE;
        }
    
        hi_at_printf("OK\r\n");
        return HI_ERR_SUCCESS;
    }
    
    • 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
    • 32

    该函数的核心就是hi_wifi_sta_start()函数。

    2.连接WiFi ,AT+CONN

    /*****************************************************************************
    * Func description: station connect network
    * example: AT+CONN="hisilicon",,3,"123456789"
    *****************************************************************************/
    hi_u32 cmd_sta_connect(hi_s32 argc, const hi_char *argv[])
    {
        hi_wifi_assoc_request assoc_req = {0};
    
        if ((argc < 3) || (argc > 4)) {     /* argc 3/4 */
            return HI_ERR_FAILURE;
        }
    
        /* get ssid */
        if ((argv[0] != HI_NULL) && (cmd_sta_connect_get_ssid(argv, &assoc_req, HI_NULL, 0) != HI_ERR_SUCCESS)) {
            return HI_ERR_FAILURE;
        }
    
        /* get bssid */
        if (argv[1] == HI_NULL) {
            memset_s(assoc_req.bssid, sizeof(assoc_req.bssid), 0, sizeof(assoc_req.bssid));
        } else if (strlen(argv[1]) == HI_WIFI_TXT_ADDR_LEN) {
            if (cmd_strtoaddr(argv[1], assoc_req.bssid, HI_WIFI_MAC_LEN) != HISI_OK) {
                return HI_ERR_FAILURE;
            }
        } else {
            return HI_ERR_FAILURE;
        }
    
        /* get auth_type */
        if ((integer_check(argv[2]) != HI_ERR_SUCCESS) || (atoi(argv[2]) < HI_WIFI_SECURITY_OPEN) ||    /* argc 2 */
            (atoi(argv[2]) == HI_WIFI_SECURITY_WPA) || (atoi(argv[2]) == HI_WIFI_SECURITY_WPA2) || /* argc 2 */
            (atoi(argv[2]) == HI_WIFI_SECURITY_WPAPSK) || (atoi(argv[2]) >= HI_WIFI_SECURITY_UNKNOWN) || /* argc 2 */
            ((atoi(argv[2]) == HI_WIFI_SECURITY_OPEN) && (argc != 3)) || /* argc 2/3/4 */
            ((atoi(argv[2]) != HI_WIFI_SECURITY_OPEN) && (argc != 4))) { /* argc 2/3/4 */
            return HI_ERR_FAILURE;
        }
        assoc_req.auth = (hi_wifi_auth_mode)atoi(argv[2]); /* 2 */
    
        assoc_req.pairwise = HI_WIFI_PARIWISE_UNKNOWN;
    
        /* get key */
        if (argc == 4) {    /* argc 4 */
            const hi_char *buf = argv[3];   /* argc 3 */
            if (buf == HI_NULL) {
                return HI_ERR_FAILURE;
            }
            size_t len = strlen(argv[3]); /* 3:key */
            if ((atoi(argv[2]) == HI_WIFI_SECURITY_WEP) && (len != 9) && (len != 17) && /* argc 2, len 9/17 */
                (len != 12) && (len != 28))  { /* 12 28: password len */
                return HI_ERR_FAILURE;
            } else if ((atoi(argv[2]) != HI_WIFI_SECURITY_WEP) && ((len > HI_WIFI_AP_KEY_LEN_MAX + 2) ||    /* argc 2 */
                (len < HI_WIFI_AP_KEY_LEN_MIN + 2))) {  /* len plus 2 */
                return HI_ERR_FAILURE;
            }
            if ((*buf != '\"') || (*(buf + strlen(argv[3]) - 1) != '\"') || /* argc 3 */
                (memcpy_s(assoc_req.key, HI_WIFI_MAX_KEY_LEN + 1, buf + 1, strlen(argv[3]) - 2) != EOK)) { /* 3 2 */
                return HI_ERR_FAILURE;
            }
        }
    
        if (hi_wifi_sta_connect(&assoc_req) != HISI_OK) {
            return HI_ERR_FAILURE;
        }
    
        hi_at_printf("OK\r\n");
        return HI_ERR_SUCCESS;
    }
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    该函数主要用于解析AT+CONN指令,核心是hi_wifi_sta_connect()函数。

    3.获取IP地址, AT+DHCP

    hi_u32 at_setup_dhcp(hi_s32 argc, const hi_char **argv)
    {
        hi_s32 ret = 0;
    
        if (at_param_null_check(argc, argv) == HI_ERR_FAILURE) {
            return HI_ERR_FAILURE;
        }
    
        if (argc != 2) { /* at+dhcp cmd length equl 2 */
            return HI_ERR_FAILURE;
        }
    #ifndef CONFIG_FACTORY_TEST_MODE
        struct netif *netif_p = netifapi_netif_find(argv[0]);
        if (netif_p == NULL) {
            return HI_ERR_FAILURE;
        }
    
        if (strcmp(argv[1], "1") == 0) {
            ret = netifapi_dhcp_start(netif_p);
        } else if (strcmp(argv[1], "0") == 0) {
            ret = netifapi_dhcp_stop(netif_p);
        } else if (strcmp(argv[1], "2") == 0) {
            ret = netifapi_netif_common(netif_p, dhcp_clients_info_show, NULL);
        } else {
            return HI_ERR_FAILURE;
        }
    #endif
        if (ret == LOS_OK) {
            hi_at_printf("OK\r\n");
        }
    
        return ret;
    }
    
    • 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
    • 32
    • 33

    其中netifapi_netif_find()函数通过DHCP向AP请求wlan0的IP地址,然后就调用netifapi_dhcp_start()函数获取IP。

    以上函数在device/hisilicon/hispark_pegasus/sdk_liteos/components/at/src目录下。

    使用AT比较麻烦,接下来笔者将通过程序来联网。

    5.2 Hi3861自动联网

    编程自动联网,其本质和使用AT指令一样,最终都是调用了相同的API,只是通过加载应用的方式去实现了,联网流程和使用AP一样的,编写应用的方式参看上一章内容,本文将在wifi-iot目录下新建应用,这样可以简化步骤。

    5.2.1新建目录

    在./applications/sample/wifi-iot/app路径下新建一个目录,用于存放WiFi应用的源码文件。

    在app下新增业务wifi_connect,其中wifi_app.c为应用代码,BUILD.gn为编译脚本,目录结构如下:

    在这里插入图片描述

    5.2.2编写应用代码

    新建./applications/sample/wifi-iot/app/wifi_app下的wifi_app.c文件,在wifi_app.c中新建入口函数wifi_task,并实现业务逻辑。并在代码最下方,使用OpenHarmony启动模块接口SYS_RUN()启动业务。

    从上一节内容得到,连接WiFi核心就三个:启动STA模式,连接WiFi,设置IP。

    因此,最终的wifi_app.c的函数代码如下:

    /**
      ******************************************************************************
      * @file                wifi_app.c
      * @author              BruceOu
      * @version             V1.0
      * @date                2022-06-18
      * @blog                https://blog.bruceou.cn/
      * @Official Accounts   嵌入式实验楼
      * @brief                
      ******************************************************************************
      */
    #include <stdio.h>
    #include <unistd.h>
    #include "ohos_init.h"
    #include "cmsis_os2.h"
    #include <unistd.h>
    #include "hi_wifi_api.h"
    #include "lwip/ip_addr.h"
    #include "lwip/netifapi.h"
    
    #define SSID      "media"
    #define PASSWORD  "12345678"
    
    static struct netif *g_lwip_netif = NULL;
    
    /**
      * @brief  Set netif's ip, gateway and netmask
      * @param  pst_lwip_netif
      * @retval None
      */
    void hi_sta_set_addr(struct netif *pst_lwip_netif)
    {
        ip4_addr_t st_gw;
        ip4_addr_t st_ipaddr;
        ip4_addr_t st_netmask;
    
        if (pst_lwip_netif == NULL)
        {
            printf("hisi_reset_addr::Null param of netdev\r\n");
            return;
        }
    
        IP4_ADDR(&st_gw, 192, 168, 101, 1);
        IP4_ADDR(&st_ipaddr, 192, 168, 101, 100);
        IP4_ADDR(&st_netmask, 255, 255, 255, 0);
    
        netifapi_netif_set_addr(pst_lwip_netif, &st_ipaddr, &st_netmask, &st_gw);
    }
    
    /**
      * @brief  Wifi connect
      * @param  None
      * @retval None
      */
    int hi_wifi_start_connect(void)
    {
        int ret;
        errno_t rc;
        hi_wifi_assoc_request assoc_req = {0};
    
        // Copy SSID to assoc_req
        rc = memcpy_s(assoc_req.ssid, HI_WIFI_MAX_SSID_LEN + 1, SSID, strlen(PASSWORD));
        if (rc != EOK)
        {
            printf("[Wifi Connnect] hi_wifi_sta_connect fail");
            printf("%s %d \r\n", __FILE__, __LINE__);
            return -1;
        }
    
        //Set encryption method
        assoc_req.auth = HI_WIFI_SECURITY_WPA2PSK;
    
        // Wifi password
        memcpy(assoc_req.key, PASSWORD, strlen(PASSWORD));
    
        ret = hi_wifi_sta_connect(&assoc_req);
        if (ret != HISI_OK)
        {
    	printf("[Wifi Connnect] hi_wifi_sta_connect fail");
            printf("%s %d \r\n", __FILE__, __LINE__);
            return -1;
        }
    
    	return 0;
    }
    
    /**
      * @brief  wifi task
      * @param  None
      * @retval None
      */
    void wifi_task(void)
    {
        int ret;
        char ifname[WIFI_IFNAME_MAX_SIZE + 1] = {0};
        int len = sizeof(ifname);
        unsigned int  num = WIFI_SCAN_AP_LIMIT;
    
    	// Step 1: Start STA mode, AT+STARTSTA 
        ret = hi_wifi_sta_start(ifname, &len);
        if (ret != HISI_OK)
        {
            printf("[Wifi Connnect] hi_wifi_sta_start fail");
            printf("%s %d \r\n", __FILE__, __LINE__);
            return;
        }
    
        // Step 2: Connect to the specified AP:, AT+CONN="SSID", ,2,"PASSWORD"
        ret = hi_wifi_start_connect();
        if (ret != 0)
        {
            printf("[Wifi Connnect] hi_wifi_start_connect fail");
            printf("%s %d \r\n", __FILE__, __LINE__);
            return ;
        }
    
        // Step 3: DHCP requests the IP address of wlan0 from the AP, AT+DHCP=wlan0,1  
        g_lwip_netif = netifapi_netif_find(ifname);
        if(NULL == g_lwip_netif) 
        {
            printf("[Wifi Connnect] netifapi_netif_find fail");
            printf("%s %d \r\n", __FILE__, __LINE__);
            return;
        }	
    
        //DHCP automatically assigns IP
        if(ret != netifapi_dhcp_start(g_lwip_netif)) 
        {
            printf("[Wifi Connnect] netifapi_dhcp_start fail");
            return;
        }	
    
        printf("[Wifi Connnect] Connect to wifi successfully\n");
    
    }
    
    SYS_RUN(wifi_task);
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137

    5.2.3新建编译组织文件

    新建./applications/sample/wifi-iot/app/wifi_connect/BUILD.gn文件,内容如下所示:

    static_library(wifiapp") {
        sources = [
            "wifi_app.c"
        ]
        include_dirs = [
            "//utils/native/lite/include"
        ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • static_library中指定业务模块的编译结果,为静态库文件libwifiapp.a,开发者根据实际情况完成填写。

    • sources中指定静态库.a所依赖的.c文件及其路径,若路径中包含"//“则表示绝对路径(此处为代码根路径),若不包含”//"则表示相对路径。

    • include_dirs中指定source所需要依赖的.h文件路径。

    5.2.4新增组件

    将wifiapp添加到组件中。即修改applications/sample/wifi-iot/app/BUILD.gn文件,修改后如下所示。
    import(“//build/lite/config/component/lite_component.gni”)

    lite_component("app") {
        features = [
            "wifi_connect:wifiapp"
        ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • wifi_connect是相对路径,指向applications/sample/wifi-iot/app/wifi_connect。
    • wifiapp是目标,指向applications/sample/wifi-iot/app/wifi_connect/BUILD.gn中的static_library(“wifiapp”)。

    5.2.5编译下载测试

    最后,编译下载固件,我们就可以自动连接Wifi了。

    在这里插入图片描述

    接下来ping下网络:

    在这里插入图片描述

    说明自动连接网络成功。

    官网手册



    欢迎访问我的网站

    BruceOu的哔哩哔哩
    BruceOu的主页
    BruceOu的博客
    BruceOu的CSDN博客
    BruceOu的简书
    BruceOu的知乎


    欢迎订阅我的微信公众号

    关注公众号[嵌入式实验楼]获取更多资讯

  • 相关阅读:
    LintCode 3. 统计数字 Python
    华为机试真题 C++ 实现【字符串序列判定】
    前端字符统计
    【Python 千题 —— 基础篇】进制转换:十进制转二进制
    基于Matlab求解高教社杯全国大学生数学建模竞赛(CUMCM2004A题)-奥运会临时超市网点设计(附上源码+数据)
    K线形态识别_黑三兵
    JS代码案例
    <C++>深度学习多态
    微服务间通信重构与服务治理笔记
    CSS 笔记(十三):常用单位 & 适配方案(移动端)
  • 原文地址:https://blog.csdn.net/u013162035/article/details/125352541