资讯详情

华为云14天鸿蒙设备开发-Day7WIFI功能开发

目录

  • 前言
  • 一、WiFI编程简介
    • 主要API简介
  • 二、开发过程
    • 1.AP与STA模式区别
    • 2.AP热点开发流程
    • 3.STA网站开发流程
  • 三、实现官方案例
    • 1. AP
      • 代码编写
      • 编译调试
    • 2. STA
      • 代码编写
      • 编译调试


前言

HarmonyOS新手入门设备开发的芯路历程 在官方文帐中,鸿蒙小熊派开发板从模块到芯片再次介绍。开发板使用的芯片是Hi3861V100芯片。 Hi3861V100是高度集成的2.4GHz SoC WiFi芯片,集成IEEE 802.11b/g/n基带和RF电路,RF电路包括功率放大器PA、低 噪声放大器LNA、RF balun、支持20MHz标准带宽和5MHz/10MHz窄带宽,提供最大72.2Mbit/s 物理层速率。Hi3861V100 WiFi支持正交频分复使用的基础支持(OFDM)该技术与直接序列扩频兼容(DSSS)和补码键控(CCK)技术,支 持IEEE 802.11 b/g/n协议的各种数据速率。 Hi3861V100芯片集成高性能32bit外设界面包括微处理器、硬件安全引擎和丰富的外设界面SPI、UART、I2C、PWM、 GPIO和多路ADC,支持高速SDIO2.0 Slave接口最高时钟可达50MHz;芯片内置SRAM和Flash,可独立运行,并支持 在Flash操作程序。 Hi3861V100支持HUAWEI LiteOS与第三方组件一起,提供开放、易用的开发和调试运行环境。 Hi3861V100支持HUAWEI LiteOS与第三方组件一起,提供开放、易用的开发和调试运行环境。 Hi3861V100芯片适用于物联网智能终端领域,如智能家电。

可以去官方社区账号专栏看更多。本文主要总结鸿蒙wifi接口


一、WiFI编程简介

Hi3861V100、Hi3861LV100 通过API(Application Programming Interface)为开发者提供Wi-Fi芯片初始化、资源配置、Station创建和配置、扫描、关联、去关联、状态查询等一系列功能, 框架结构如图所示。 在这里插入图片描述

  • APP应用开发层:用户基于用户API接口二次开发。

  • Example示例:SDK提供的功能开发示例。

  • API接口:提供基础SDK通用接口。

  • LWIP协议栈:网络协议栈。

  • WPA SUPPLICANT(含HOSTAPD):Wi-Fi管理模块。

  • Wi-Fi驱动:802.协议实现模块。

  • Platform平台:提供SoC系统板级支持包(包括芯片及外围设备驱动、操作系统及系统管理)

鸿蒙系统代码API文件如下: foundation\communication\interfaces\kits\wifi_lite\wifiservice\wifi_device.h foundation\communication\interfaces\kits\wifi_lite\wifiservice\wifi_hotspot.h

主要API简介

WifiErrorCode RegisterWifiEvent (WifiEvent * event)

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

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

WifiErrorCode EnableHotspot (void )

描述: 启用Wifi热点模式

WifiErrorCode SetHotspotConfig(const HotspotConfig* config)

描述: 设置指定的热点配置

int IsHotspotActive(void);

描述: 检查AP是否启用热点模式

WifiErrorCode GetStationList(StationInfo* result, unsigned int* size)

描述: 一系列连接到热点的获取系列STA 参数:

名字 描述
result 表示连接到热点STA列表
size 表示连接到该热点的STA数量

WifiErrorCode EnableWifi (void )

描述: 启用STA模式

WifiErrorCode AddDeviceConfig (const WifiDeviceConfig * config, int * result )

描述: 添加用于配置连接的热点信息,生成此函数networkId 参数:

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

WifiErrorCode ConnectTo (int networkId)

描述: 连接到指定networkId的热点

struct netif *netifapi_netif_find(const char *name);

描述: 获取netif用于IP操作

err_t dhcp_start(n)

描述:启动DHCP, 获取IP

二、开发流程

1.AP与STA模式区别

:无线接入点,是一个无线网络的创建者,是网络的中心节点。一般家庭或办公室使用的无线路由器就是一个AP。

:就是每一个连接到无线网络中的终端(如笔记本电脑、PDA及其它可以联网的用户设备)都可称为一个站点。

: Access Point,提供无线接入服务,允许其它无线设备接入,提供数据访问,一般的无线路由/网桥工作在该模式下。AP和AP之间允许相互连接。 在此模式下,手机、PAD、电脑等设备可以直接连上模块,可以很方便对用户设备进行控制。

: Station, 类似于无线终端,sta本身并不接受无线的接入,它可以连接到AP,一般无线网卡即工作在该模式。 这是一种基本的组网方式,由一个AP和许多STA组成。其特点是AP处于中心地位,STA之间的相互通信都通过AP转发完成。该模式下,WIFI模块工作在STA(CLIENT)模式。通过适当的设置,COM的数据与WIFI的网路数据相互转换。

2.AP热点开发流程

鸿蒙设备完成Wifi热点的扫描需要以下几步

  1. 通过 RegisterWifiEvent 接口向系统注册热点状态改变事件、STA站点加入事件、STA站点退出事件
  • OnHotspotStateChangedHandler 用于绑定热点状态改变事件,该回调函数有一个参数 state ;其中state表示是否开启AP模式,取值为0和1,0表示已启用Wifi AP模式,1表示已禁用Wifi AP模式;

  • OnHotspotStaLeaveHandler 用于绑定STA站点退出事件,当有STA站点退出,该回调函数会打印出退出站点的MAC地址;

  • OnHotspotStaJoinHandler 用于绑定STA站点加入事件,当有新的STA站点加入时,该回调函数会创建 HotspotStaJoinTask,在该任务中会调用 GetStationList 函数获取当前接入到该AP的所有STA站点信息,并打印出每个STA站点的MAC地址;

  1. 调用 SetHotspotConfig 接口,设置指定的热点配置;

  2. 调用 EnableHotspot 接口,使能 Wifi AP 模式;

  3. 调用 IsHotspotActive 接口,检查AP热点模式是否启用;

  4. 调用 netifapi_netif_set_addr 函数设置网卡信息;

  5. 调用 netifapi_dhcps_start 函数启动dhcp服务;

3.STA站点开发流程

鸿蒙设备完成Wifi热点的连接需要以下几步

  1. 通过 RegisterWifiEvent 接口向系统注册扫描状态监听函数,用于接收扫描状态通知,如扫描动作是否完成等
  • OnWifiConnectionChangedHandler 用于绑定连接状态监听函数,该回调函数有两个参数 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. 调用 WaitConnectResult 接口等待,该函数中会有15s的时间去轮询连接成功标志位 g_ConnectSuccess,当g_ConnectSuccess 为 1 时退出等待。
  5. 调用 netifapi_netif_find 接口,获取 netif 用于 IP 操作
  6. 调用 dhcp_start 接口,启动 DHCP, 获取 IP

三、官方案例实现

1. AP

此模式下并不能联网,只是能够将终端连接到设备而已。如需联网应该采用AP+STA模式。

代码编写

#define AP_SSID "BearPi"
#define AP_PSK "0987654321"

#define ONE_SECOND 1
#define DEF_TIMEOUT 15

static void OnHotspotStaJoinHandler(StationInfo *info);
static void OnHotspotStateChangedHandler(int state);
static void OnHotspotStaLeaveHandler(StationInfo *info);

static struct netif *g_lwip_netif = NULL;
static int g_apEnableSuccess = 0;
WifiEvent g_wifiEventHandler = { 
         0};
WifiErrorCode error;

static BOOL WifiAPTask(void)
{ 
         
    //延时2S便于查看日志
    osDelay(200);

    //注册wifi事件的回调函数
    g_wifiEventHandler.OnHotspotStaJoin = OnHotspotStaJoinHandler;
    g_wifiEventHandler.OnHotspotStaLeave = OnHotspotStaLeaveHandler;
    g_wifiEventHandler.OnHotspotStateChanged = OnHotspotStateChangedHandler;
    error = RegisterWifiEvent(&g_wifiEventHandler);
    if (error != WIFI_SUCCESS)
    { 
         
        printf("RegisterWifiEvent failed, error = %d.\r\n",error);
        return -1;
    }
    printf("RegisterWifiEvent succeed!\r\n");
    //设置指定的热点配置
    HotspotConfig config = { 
         0};

    strcpy(config.ssid, AP_SSID);
    strcpy(config.preSharedKey, AP_PSK);
    config.securityType = WIFI_SEC_TYPE_PSK;
    config.band = HOTSPOT_BAND_TYPE_2G;
    config.channelNum = 7;

    error = SetHotspotConfig(&config);
    if (error != WIFI_SUCCESS)
    { 
         
        printf("SetHotspotConfig failed, error = %d.\r\n", error);
        return -1;
    }
    printf("SetHotspotConfig succeed!\r\n");

    //启动wifi热点模式
    error = EnableHotspot(); 
    if (error != WIFI_SUCCESS)
    { 
         
        printf("EnableHotspot failed, error = %d.\r\n", error);
        return -1;
    }
    printf("EnableHotspot succeed!\r\n");

    //检查热点模式是否使能
    if (IsHotspotActive() == WIFI_HOTSPOT_NOT_ACTIVE)
    { 
         
        printf("Wifi station is not actived.\r\n");
        return -1;
    }
    printf("Wifi station is actived!\r\n");

    //启动dhcp
    g_lwip_netif = netifapi_netif_find("ap0");
    if (g_lwip_netif) 
    { 
         
        ip4_addr_t bp_gw;
        ip4_addr_t bp_ipaddr;
        ip4_addr_t bp_netmask;

        IP4_ADDR(&bp_gw, 192, 168, 1, 1);           /* input your gateway for example: 192.168.1.1 */
        IP4_ADDR(&bp_ipaddr, 192, 168, 1, 1);       /* input your IP for example: 192.168.1.1 */
        IP4_ADDR(&bp_netmask, 255, 255, 255, 0);    /* input your netmask for example: 255.255.255.0 */

        err_t ret = netifapi_netif_set_addr(g_lwip_netif, &bp_ipaddr, &bp_netmask, &bp_gw);
        if(ret != ERR_OK)
        { 
         
            printf("netifapi_netif_set_addr failed, error = %d.\r\n", ret);
            return -1;
        }
        printf("netifapi_netif_set_addr succeed!\r\n");

        ret = netifapi_dhcps_start(g_lwip_netif, 0, 0);
        if(ret != ERR_OK)
        { 
          
            printf("netifapi_dhcp_start failed, error = %d.\r\n", ret);
            return -1;
        }
        printf("netifapi_dhcps_start succeed!\r\n");

    }

    /****************以下为UDP服务器代码***************/
	//在sock_fd 进行监听
    int sock_fd;
    //服务端地址信息
	struct sockaddr_in server_sock;

    //创建socket
	if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
	{ 
         
		perror("socket is error.\r\n");
		return -1;
	}

	bzero(&server_sock, sizeof(server_sock));
	server_sock.sin_family = AF_INET;
	server_sock.sin_addr.s_addr = htonl(INADDR_ANY);
	server_sock.sin_port = htons(8888);

	//调用bind函数绑定socket和地址
	if (bind(sock_fd, (struct sockaddr *)&server_sock, sizeof(struct sockaddr)) == -1)
	{ 
         
		perror("bind is error.\r\n");
		return -1;
	}

    int ret;
    char recvBuf[512] = { 
         0};
    //客户端地址信息
    struct sockaddr_in client_addr;
    int size_client_addr= sizeof(struct sockaddr_in);
    while (1)
    { 
         
        
        printf("Waiting to receive data...\r\n");
        memset(recvBuf, 0, sizeof(recvBuf));
        ret = recvfrom(sock_fd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr*)&client_addr,(socklen_t*)&size_client_addr);
        if(ret < 0)
        { 
         
            printf("UDP server receive failed!\r\n");
            return -1;
        }
        printf("receive %d bytes of data from ipaddr = %s, port = %d.\r\n", ret, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
        printf("data is %s\r\n",recvBuf);
        ret = sendto(sock_fd, recvBuf, strlen(recvBuf), 0, (struct sockaddr *)&client_addr, sizeof(client_addr));
        if (ret < 0)
        { 
         
            printf("UDP server send failed!\r\n");
            return -1;
        }
    }
    /*********************END********************/
}

课程上说是获取站点列表函数在回调函数中调用得不到结果,所以写了个任务函数在回调函数中调用。

static void HotspotStaJoinTask(void)
{ 
         
    static char macAddress[32] = { 
         0};
    StationInfo stainfo[WIFI_MAX_STA_NUM] = { 
         0};
    StationInfo *sta_list_node = NULL;
    unsigned int size = WIFI_MAX_STA_NUM;

    error = GetStationList(stainfo, &size);
    if (error != WIFI_SUCCESS) { 
         
        printf("HotspotStaJoin:get list fail, error is %d.\r\n", error);
        return;
    }
    sta_list_node = stainfo;
    for (uint32_t i = 0; i < size; i++, sta_list_node++) { 
         
    unsigned char* mac = sta_list_node->macAddress;
    snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    printf("HotspotSta[%d]: macAddress=%s.\r\n",i, macAddress);
    }
    g_apEnableSuccess++;
}
static void OnHotspotStaJoinHandler(StationInfo *info)
{ 
         
    if (info == NULL) { 
         
    printf("HotspotStaJoin:info is null.\r\n");
    } 
    else { 
         
        printf("New Sta Join\n");
        osThreadAttr_t attr;
        attr.name = "HotspotStaJoinTask";
        attr.attr_bits = 0U;
        attr.cb_mem = NULL;
        attr.cb_size = 0U;
        attr.stack_mem = NULL;
        attr.stack_size = 2048;
        attr.priority = 24;
        if (osThreadNew((osThreadFunc_t)HotspotStaJoinTask, NULL, &attr) == NULL) { 
         
            printf("HotspotStaJoin:create task fail!\r\n");
        }
    }
    return;
}

static void OnHotspotStaLeaveHandler(StationInfo *info)
{ 
         
    if (info == NULL) { 
         
        printf("HotspotStaLeave:info is null.\r\n");
    } 
    else { 
         
        static char macAddress[32] = { 
         0};
        unsigned char* mac = info->macAddress;
        snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
        printf("HotspotStaLeave: macAddress=%s, reason=%d.\r\n", macAddress, info->disconnectedReason);
        g_apEnableSuccess--;
    }
    return;
}

static void OnHotspotStateChangedHandler(int state)
{ 
         
    printf("HotspotStateChanged:state is %d.\r\n", state);
    if (state == WIFI_HOTSPOT_ACTIVE) { 
         
        printf("wifi hotspot active.\r\n");
    } else { 
         
        printf("wifi hotspot noactive.\r\n");
    }
}

编译调试

修改 applications\BearPi\BearPi-HM_Nano\sample 路径下 BUILD.gn 文件,指定 wifi_ap 参与编译。 Linux终端或者MobaXterm的会话连接内,进入代码目录执行 python build.py BearPi-HM_Nano进行编译。 使用HiBurn工具,波特率设置为2000000. 选择对应的com口和要烧录的文件,勾选auto burn。点击connect,再点开发板复位按键。进行烧录。 通过MobaXterm的串口工具查看。用手机连一下试试。

2. STA

此模式下设备能联网,但是不能够将终端连接到设备。如需联网应该采用AP+STA模式。

代码编写

相关声明

#define DEF_TIMEOUT 15
#define ONE_SECOND 1

static void WiFiInit(void);
static void WaitSacnResult(void);
static int WaitConnectResult(void);
static void OnWifiScanStateChangedHandler(int state, int size);
static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo *info);
static void OnHotspotStaJoinHandler(StationInfo *info);
static void OnHotspotStateChangedHandler(int state);
static void OnHotspotStaLeaveHandler(StationInfo *info);

static int g_staScanSuccess = 0;
static int g_ConnectSuccess = 0;
static int ssid_count = 0;
WifiEvent g_wifiEventHandler = { 
         0};
WifiErrorCode error;

#define SELECT_WLAN_PORT "wlan0"

#define SELECT_WIFI_SSID "your wifi ssid"//这里改成要连接的热点账号和对应密码
#define SELECT_WIFI_PASSWORD "your wifi password"
#define SELECT_WIFI_SECURITYTYPE WIFI_SEC_TYPE_PSK

static BOOL WifiSTATask(void)
{ 
         
    WifiScanInfo *info = NULL;
    unsigned int size = WIFI_SCAN_HOTSPOT_LIMIT;
    static struct netif *g_lwip_netif = NULL;
    WifiDeviceConfig select_ap_config = { 
         0};

    osDelay(200);
    printf("<--System Init-->\r\n");

    //初始化WIFI,将回调函数绑定写到这里了
    WiFiInit();

    //使能WIFI
    if (EnableWifi() != WIFI_SUCCESS)
    { 
         
        printf("EnableWifi failed, error = %d\n", error);
        return -1;
    }

    //判断WIFI是否激活
    if (IsWifiActive() == 0)
    { 
         
        printf("Wifi station is not actived.\n");
        return -1;
    }

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

    //轮询查找WiFi列表
    do
        标签: hm2518集成电路集成电路hi12g03d1c集成电路

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台