目录
  • 一、准备工作
  • 二、软件设计
  • 三、编译调试

Wifi AP 热点

本示例将演示如何在BearPi-HM_Nano 2开发板上编写一个创建Wifi热点程序。

一、准备工作

参考BearPi-HM_Nano_2十分钟上手教程完成开发环境搭建、代码获取等工作,以及熟悉代码的编译和烧录流程。

二、软件设计

主要代码分析

打开device\bearpi\bearpi_hm_nano2\app\D1_iot_wifi_ap\wifi_ap.c

完成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地址;

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

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

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

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

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

static int StartUdpServer(void)
{
    /****************以下为UDP服务器代码,默认IP:192.168.5.1***************/
    // 在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(UDP_SERVERPORT);

    // 调用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_s(recvBuf, sizeof(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;
        }
    }

    return 0;
    /*********************END********************/
}

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

    // 注册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");
    // 检查热点模式是否使能
    if (IsHotspotActive() == WIFI_HOTSPOT_ACTIVE) {
        printf("Wifi station is  active.\r\n");
        return -1;
    }
    // 设置指定的热点配置
    HotspotConfig config = { 0 };

    strcpy_s(config.ssid, strlen(AP_SSID) + 1, AP_SSID);
    strcpy_s(config.preSharedKey, strlen(AP_PSK) + 1, AP_PSK);
    config.securityType = WIFI_SEC_TYPE_PSK;
    config.band = HOTSPOT_BAND_TYPE_2G;
    config.channelNum = CHANNEL_NUM;

    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");

    StartUdpServer();
    return 0;
}

Wifi API分析

本案例主要使用了以下几个API完成Wifi热点创建

依赖文件:

foundation\communication\wifi_lite\interfaces\wifiservice\wifi_device.h foundation\communication\wifi_lite\interfaces\wifiservic\wifi_hotspot.h

RegisterWifiEvent()

WifiErrorCode RegisterWifiEvent (WifiEvent * event)

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

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

EnableHotspot()

WifiErrorCode EnableHotspot (void )

描述:

启用Wifi热点模式

SetHotspotConfig()

WifiErrorCode SetHotspotConfig(const HotspotConfig* config)

描述:

设置指定的热点配置

IsHotspotActive()

int IsHotspotActive(void);

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

GetStationList()

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

描述:

获取连接到该热点的一系列STA

参数:

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

三、编译调试

修改 BUILD.gn 文件

修改 device\bearpi\bearpi_hm_nano2\app 路径下 BUILD.gn 文件,指定 wifi_ap 参与编译。

"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",        

运行结果

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

RegisterWifiEvent succeed!

SetHotspotConfig succeed!

HotspotStateChanged:state is 1.

EnableHotspot succeed!

Wifi station is actived!

+NOTICE:STA CONNECTED
New Sta Join
HotspotSta[0]: macAddress=EC:5C:68:5B:2D:3D.

netifapi_netif_set_addr succeed!

netifapi_dhcps_start succeed!

Waiting to receive data...