引言
在本文中,带大家编写一个程序,测试Hi3861的WiFi-AP模式,进一步熟悉相关API的使用。
请先按照本专栏第一讲中的第四部分准备好实验环境。
一、编写程序
首先,打开 DevEco Device Tool
,在鸿蒙项目 hispark_pegasus_312
的文件夹applications/sample/wifi-iot/app/experiment
下创建一个新文件夹C01_wifi_ap
。
然后,在文件夹C01_wifi_ap
新建一个文件:wifi_ap_test.c
。下面,我们就在这个文件中编写程序。
1.1 头文件
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_hotspot.h"
#include "netifapi.h"
1.2 宏定义
#define AP_SSID "Hi3861-AP" //Hi3861 WiFi热点的名称
#define AP_PSK "12345678" //Hi3861 WiFi热点的密码
1.3 全局变量
//WiFi事件回调函数结构体
WifiEvent g_wifiEventHandler = {0};
//网络接口结构体指针
static struct netif *g_lwip_netif = NULL;
//Hi3861的WiFi-AP模式的状态, 1: 打开, 0: 关闭
static volatile int g_hotspotStarted = 0;
//接入Hi3861的WiFi热点的站点数
static volatile int g_joinedStations = 0;
1.4 函数
1.4.1 子函数
函数原型 | 功能描述 |
---|---|
int WiFiEventHandlerRegister(void) | 对WiFi事件的回调函数进行注册。 |
void PrintStationInfo(StationInfo* info) | 打印接入/离开WiFi热点的WiFi设备的信息。 |
int ChangeHotspotIpAddr(void) | 更改Hi3861-WiFi-AP的地址信息。 |
int StartHotspot(const HotspotConfig* config) | 开启Hi3861的WiFi热点。 |
int StopHotspot(void) | 关闭Hi3861的WiFi热点。 |
这些子函数主要就是通过调用之前介绍的API来实现的,它们又在任务函数或WiFi事件的回调函数中被调用。
1、函数:PrintStationInfo
//打印站点的信息
static void PrintStationInfo(StationInfo* info)
{
static char macAddress[32] = {0};
unsigned char* mac = info->macAddress;
if (!info) return;
snprintf(macAddress, sizeof(macAddress),
"%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
printf("PrintStationInfo: mac=%s, reason=%d \r\n", macAddress, info->disconnectedReason);
}
在这个函数中调用了函数snprintf
,这个函数的作用是:按照第3个参数所规定的格式,把最后6个参数(MAC地址的6个字节)变成字符串,并把这个字符赋值给第一个参数。
2、函数:ChangeHotspotIpAddr
//更改Hi3861-WiFi-AP的地址信息
static int ChangeHotspotIpAddr(void)
{
int errCode = 0;
ip4_addr_t ipaddr; //IP地址
ip4_addr_t gateway; //网关
ip4_addr_t netmask; //子网掩码
g_lwip_netif = netifapi_netif_find("ap0");
if(g_lwip_netif)
{
//停止WiFi热点的DHCP服务器
printf("\r\n");
printf("Stopping DHCP server ...... \r\n");
errCode = netifapi_dhcps_stop(g_lwip_netif);
if(errCode != ERR_OK)
{
printf("Error!!! errCode = %d \r\n", errCode);
return -1;
}
printf("Succeed! \r\n");
//设置WiFi热点的地址信息
printf("Changing IP address ...... \r\n");
IP4_ADDR(&ipaddr, 192, 168, 3, 1);
IP4_ADDR(&gateway, 192, 168, 3, 1);
IP4_ADDR(&netmask, 255, 255, 255, 0);
errCode = netifapi_netif_set_addr(g_lwip_netif, &ipaddr, &netmask, &gateway);
if(errCode != ERR_OK)
{
printf("Error!!! errCode = %d \r\n", errCode);
return -1;
}
printf("Succeed! IP: 192.168.3.1 \r\n");
//启动WiFi热点的DHCP服务器
printf("Starting DHCP server ...... \r\n");
errCode = netifapi_dhcps_start(g_lwip_netif, 0, 0);
if(errCode != ERR_OK)
{
printf("Error!!! errCode = %d \r\n", errCode);
return -1;
}
printf("Succeed! \r\n");
}
else
{
printf("Error!!! g_lwip_netif is NULL!!! \r\n");
return -1;
}
return 0;
}
函数中的IP4_ADDR
是在头文件ip4_addr.h
中定义的一个带参数的宏,其作用是:是把分成4个数的地址合成为一个按大端模式存放的32bit无符号整数。
1.4.2 WiFi事件回调函数
在AP模式下,有三种WiFi事件。所以,我们要相应编写三个回调函数,分别对这三种WiFi事件进行处理。
函数原型 | 功能描述 |
---|---|
void OnHotspotStateChangedHandler(int state) | 回调函数,WiFi事件:Hi3861-AP模式的状态发生改变(打开/关闭) |
void OnHotspotStaJoinHandler(StationInfo* info) | 回调函数,WiFi事件:有站点接入Hi3861的WiFi热点 |
void OnHotspotStaLeaveHandler(StationInfo* info) | 回调函数,WiFi事件:有站点离开Hi3861的WiFi热点 |
1.4.3 任务函数和任务入口函数
可以把任务函数理解成这个程序中的主函数;任务入口函数就是把任务函数创建成一个任务,并使之进入就绪状态,接受操作系统的调度。
函数原型 | 功能描述 |
---|---|
void WifiHotspotTaskFun(void) | 任务函数 |
void WifiHotspotTaskEntry(void) | 任务入口函数 |
任务函数的基本流程如下图所示:
步骤Step3-3并不是必须的,如果不更改WiFi的地址信息,WiFi热点的默认IP地址是:192.168.5.1。
任务函数的代码如下:
//任务函数
static void WifiHotspotTaskFun(void)
{
int errCode = 0;
int timeout;
HotspotConfig config = {0}; //WiFi热点的配置参数结构体
//Step1: 准备WiFi热点的配置参数
strcpy(config.ssid, AP_SSID); //Hi3861 WiFi热点的名称
strcpy(config.preSharedKey, AP_PSK); //Hi3861 WiFi热点的密码
config.securityType = WIFI_SEC_TYPE_PSK; //Hi3861 WiFi热点的加密类型
config.band = HOTSPOT_BAND_TYPE_2G; //Hi3861 WiFi热点的频段
config.channelNum = 7; //Hi3861 WiFi热点的信道
while(1)
{
//Step2: 注册WiFi事件的回调函数
printf("\r\n");
WiFiEventHandlerRegister();
//Step3: 开启Hi3861的WiFi热点
printf("\r\n");
printf("starting AP ...\r\n");
StartHotspot(&config);
//Step4: 延时
printf("\r\n");
printf("Please connect this hotspot with your mobile phone ...\r\n");
printf("\r\n");
for(timeout=120; timeout>0; timeout--)
{
osDelay(100);
if(timeout == 10)
{
printf("\r\n");
printf("Hotspot will be closed after %d s ...... \r\n", timeout);
}
}
//Step5: 关闭WiFi热点
StopHotspot();
//Step6: 注销WiFi事件的回调函数
printf("\r\n");
printf("UnRegister WifiEvent ...... \r\n");
errCode = UnRegisterWifiEvent(&g_wifiEventHandler);
if(errCode != WIFI_SUCCESS)
{
printf("Error!!! errCode = %d \r\n", errCode);
}
printf("Succeed! \r\n");
//Step7: 延时
for(timeout=30; timeout>0; timeout--)
{
osDelay(100);
if(timeout < 10)
{
printf("Hotspot will be opened after %d s ...... \r\n", timeout);
}
}
}
}
二、编写/修改编译脚本
1、在文件夹C01_wifi_ap
新建一个文件:BUILD.gn
。这个编译脚本的内容如下:
static_library("C01_wifi_ap") {
sources = [
"wifi_ap_test.c",
]
include_dirs = [
"//utils/native/lite/include",
"//device/hisilicon/hispark_pegasus/hi3861_adapter/kal/cmsis",
"//foundation/communication/wifi_lite/interfaces/wifiservice",
"//device/soc/hisilicon/hi3861v100/sdk_liteos/third_party/lwip_sack/include/lwip",
]
}
2、修改文件夹applications/sample/wifi-iot/app
下的文件BUILD.gn
:
import("//build/lite/config/component/lite_component.gni")
lite_component("app") {
features = [
"startup",
"experiment/C01_wifi_ap",
]
}
三、编译、烧写
略。参考:《鸿蒙设备开发之Hello World》第三、四部分。
四、测试
1、烧写完毕后,参考《鸿蒙设备开发之Hello World》第五部分,启动测试程序。测试程序将按照任务函数的流程在终端窗口中打印输出一些信息,如下图所示:
2、当看到上图最后一条提示信息后,你就可以在手机的WiFi设置里看到Hi3861的WiFi热点。用手机连接这个WiFi热点,终端输出如下图所示:
mac
是手机的MAC地址,active stations
是当前接入WiFi热点的设备的数量。
当手机从Hi3861的WiFi热点断开时,终端输出如下图所示:
3、当即将关闭WiFi热点时,终端输出下图所示第一条提示信息,然后在10s后关闭DHCP服务、关闭AP模式、注销WiFi事件回调函数。