【鸿蒙开发】Hi3861学习笔记- WIFI应用AP建立网络

news2025/3/22 15:47:10

00. 目录

文章目录

    • 00. 目录
    • 01. LwIP简介
    • 02. AP模式简介
    • 03. API描述
      • 3.1 RegisterWifiEvent
      • 3.2 UnRegisterWifiEvent
      • 3.3 GetStationList
      • 3.4 GetSignalLevel
      • 3.5 EnableHotspot
      • 3.6 DisableHotspot
      • 3.7 SetHotspotConfig
      • 3.8 GetHotspotConfig
      • 3.9 IsHotspotActive
    • 04. 硬件设计
    • 05. 模块参考
    • 06. 软件设计
    • 07. 实验现象
    • 08. 附录

01. LwIP简介

LwIP 全名:Light weight IP,意思是轻量化的 TCP/IP 协议,是瑞典计算机科学院(SICS)的 Adam Dunkels 开发的一个小型开源的 TCP/IP

协议栈。LwIP的设计初衷是:用少量的资源消耗实现一个较为完整的 TCP/IP 协议栈,其中“完整”主要指的是 TCP 协议的完整性,实现的

重点是在保持 TCP 协议主要功能的基础上减少对 RAM 的占用。此外 LwIP 既可以移植到操作系统上运行,也可以在无操作系统的情况下

独立运行。

(1) LwIP具有主要特性

1.支持 ARP 协议(以太网地址解析协议)。

2.支持 ICMP 协议(控制报文协议),用于网络的调试与维护。

3.支持 IGMP 协议(互联网组管理协议),可以实现多播数据的接收。

4.支持 UDP 协议(用户数据报协议)。

5.支持 TCP 协议(传输控制协议),包括阻塞控制、RTT 估算、快速恢复和快速转发。

6.支持 PPP 协议(点对点通信协议),支持 PPPoE。

7.支持 DNS(域名解析)。

8.支持 DHCP 协议,动态分配 IP 地址。

9.支持 IP 协议,包括 IPv4、IPv6 协议,支持 IP 分片与重装功能,多网络接口下的数据包转发。

10.支持 SNMP 协议(简单网络管理协议)。

11.支持 AUTOIP,自动 IP 地址配置。

12.提供专门的内部回调接口(Raw API),用于提高应用程序性能。

13.提供可选择的 Socket API、NETCONN API (在多线程情况下使用) 。

(2) LwIP在嵌入式中使用有以下优点

1.资源开销低,即轻量化。LwIP 内核有自己的内存管理策略和数据包管理策略,使得内核处理数据包的效率很高。另外,LwIP 高度可剪

裁,一切不需要的功能都可以通过宏编译选项去掉。LwIP 的流畅运行需要 40KB 的代码 ROM 和几十 KB 的 RAM,这让它非常适合用在

内存资源受限的嵌入式设备中。

2.支持的协议较为完整。几乎支持 TCP/IP 中所有常见的协议,这在嵌入式设备中早已够用。

3.实现了一些常见的应用程序:DHCP 客户端、DNS 客户端、HTTP 服务器、MQTT 客户端、TFTP 服务器、SNTP 客户端等等。

4.同时提供了三种编程接口:RAW API、NETCONN API(注:NETCONN API 即为 Sequential API,为了统一,下文均采用 NETCONN

API)和 Socket API。这三种 API 的执行效率、易用性、可移植性以及时空间的开销各不相同,用户可以根据实际需要,平衡利弊,选择

合适的 API 进行网络应用程序的开发。

5.高度可移植。其源代码全部用 C 实现,用户可以很方便地实现跨处理器、跨编译器的移植。另外,它对内核中会使用到操作系统功能的

地方进行了抽象,使用了一套自定义的 API,用户可以通过自己实现这些 API,从而实现跨操作系统的移植工作。

6.开源、免费,用户可以不用承担任何商业风险地使用它。

7.相比于嵌入式领域其它的 TCP/IP 协议栈,比如 uC-TCP/IP、FreeRTOS-TCP 等,LwIP 的发展历史要更悠久一些,得到了更多的验证和测试。

LwIP 被广泛用在嵌入式网络设备中,国内一些物联网公司推出的物联网操作系统,其 TCP/IP 核心就是 LwIP;物联网知名的 WiFi 模块

ESP8266,其 TCP/IP固件,使用的就是 LwIP。

LwIP 尽管有如此多的优点,但它毕竟是为嵌入式而生,所以并没有很完整地实现 TCP/IP 协议栈。相比于 Linux 和 Windows 系统自带的

TCP/IP 协议栈,LwIP 的功能不算完整和强大。但对于大多数物联网领域的网络应用程序,LwIP已经足够了。

02. AP模式简介

Hi3861 是一款带 MCU 的 WiFi 芯片,支持 AP(Access Point)模式和 Station模式。在 AP 模式下,Hi3861 可以作为一个 WiFi 热点,

允许其他设备接入,形成一个 WiFi 局域网。

在这里插入图片描述

03. API描述

相关头文件

foundation\communication\interfaces\kits\wifi_lite\wifiservice\wifi_device.h

foundation\communication\interfaces\kits\wifi_lite\wifiservice\wifi_hotspot.h

3.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 7
 */
WifiErrorCode RegisterWifiEvent(WifiEvent *event)
功能:
	用于注册特定 WiFi 事件回调函数的 API。这个函数允许开发者为 WiFi 模块上发生的特定事件(如连接状态改变、扫描状态改变、热点状态改变等)注册回调函数。当这些事件发生时,系统会自动调用相应的回调函数,以便开发者能够处理这些事件。
        
参数:
	event:事件

返回值:
	0 成功,其他值错误信息

WifiEvent类型

/**
 * @brief Represents the pointer to a Wi-Fi event callback for station and hotspot connection, disconnection, or scan.
 *
 *
 * If you do not need a callback, set the value of its pointer to <b>NULL</b>. \n
 *
 * @since 7
 */
typedef struct {
    /** Connection state change */
    void (*OnWifiConnectionChanged)(int state, WifiLinkedInfo *info);
    /** Scan state change */
    void (*OnWifiScanStateChanged)(int state, int size);
    /** Hotspot state change */
    void (*OnHotspotStateChanged)(int state);
    /** Station connected */
    void (*OnHotspotStaJoin)(StationInfo *info);
    /** Station disconnected */
    void (*OnHotspotStaLeave)(StationInfo *info);
} WifiEvent;

3.2 UnRegisterWifiEvent

/**
 * @brief Unregisters a callback previously registered for a specified Wi-Fi event.
 *
 * @param event Indicates the event for which the callback is to be unregistered.
 * @return Returns {@link WIFI_SUCCESS} if the callback is unregistered successfully; returns an error code defined
 * in {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode UnRegisterWifiEvent(const WifiEvent *event);
功能:
	注销WiFI事件回调
参数:
	event:事件
返回值:
	0 成功,其他值错误信息    

3.3 GetStationList

/**
 * @brief Obtains an array of stations connected to this hotspot.
 *
 * The station information is defined in {@link StationInfo}. \n
 *
 * @param result Indicates the array of stations connected to this hotspot. The array is requested and released by the
 * caller. The value must be greater than or equal to {@link WIFI_MAX_STA_NUM}.
 * @param size Indicates the size of the array.
 * @return Returns {@link WIFI_SUCCESS} if the array of stations connected to this hotspot is obtained; returns an error
 *  code defined in {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode GetStationList(StationInfo *result, unsigned int *size)
功能:
	获取连接到该热点的一系列STA
参数:
	result:表示连接到该热点的STA列表
	size:表示连接到该热点的STA数量
返回值:
	0 成功,其他值错误信息

3.4 GetSignalLevel

/**
 * @brief Obtains the signal level indicated by a specified received signal strength indicator (RSSI) and frequency
 * band.
 *
 *
 * Based on the signal level, you can display the signal strength represented by the number of signal bars. \n
 *
 * @param rssi Indicates the RSSI.
 * @param band Indicates the frequency band, either {@link HOTSPOT_BAND_TYPE_5G} or {@link HOTSPOT_BAND_TYPE_2G}.
 * @return Returns the signal level if it is obtained; returns <b>-1</b> otherwise.
 * @since 7
 */
int GetSignalLevel(int rssi, int band)
功能:
	获取接收信号强度和频率
参数:
	rssi:信号强度
	band:频率,HOTSPOT_BAND_TYPE_5G或HOTSPOT_BAND_TYPE_2G
返回值:
	获取到的信号水平    

3.5 EnableHotspot

/**
 * @brief Enables the hotspot mode.
 *
 * Before using this function, you need to invoke {@link SetHotspotConfig} and set at least the SSID, security type,
 * and key. \n
 *
 * @return Returns {@link WIFI_SUCCESS} if the hotspot mode is enabled; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode EnableHotspot(void)
功能:
	启用Wifi热点模式
参数:
	
返回值:
	0 成功,非 0 错误值      

AP热点 接口位于 foundation\communication\interfaces\kits\wifi_lite\wifiservice\wifi_hotspot.h。

3.6 DisableHotspot

/**
 * @brief Disables the hotspot mode.
 *
 * @return Returns {@link WIFI_SUCCESS} if the hotspot mode is disabled; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode DisableHotspot(void)
功能:
	禁用Wifi热点模式
参数:
	
返回值:
	0 成功,非 0 错误值       

3.7 SetHotspotConfig

/**
 * @brief Sets a specified hotspot configuration.
 *
 * The hotspot configuration includes the SSID, security type, and key. The configuration set overwrites the existing
 * configuration and takes effect after the hotspot mode is re-enabled. \n
 * Before enabling the hotspot mode for the first time, you must call this function. \n
 *
 * @param config Indicates the hotspot configuration to set.
 * @return Returns {@link WIFI_SUCCESS} if the hotspot configuration is set; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode SetHotspotConfig(const HotspotConfig *config)
功能:
	设置指定的热点配置
参数:
	config:热点配置参数;包括 WIFI 热点名称、密码、频率安全类型等
返回值:
	0 成功,非 0 错误值   

HotspotConfig类型

/**
 * @brief Represents the hotspot configuration.
 *
 * A hotspot configuration must contain the SSID (or BSSID), security type, and key (if the security type is open). \n
 *
 * @since 7
 */
typedef struct {
    /** Service set ID (SSID). For its length, see {@link WIFI_MAX_SSID_LEN}. */
    char ssid[WIFI_MAX_SSID_LEN];
    /** Security type */
    int securityType;
    /** Frequency band */
    int band;
    /** Channel number */
    int channelNum;
    /** Key. For its length, see {@link WIFI_MAX_SSID_LEN}. */
    char preSharedKey[WIFI_MAX_KEY_LEN];
} HotspotConfig;

ssid:为热点名称,默认长度最大为 33

WifiSecurityType类型

/**
 * @brief Enumerates Wi-Fi security types.
 *
 * @since 7
 */
typedef enum {
    /** Invalid security type */
    WIFI_SEC_TYPE_INVALID = -1,
    /** Open */
    WIFI_SEC_TYPE_OPEN,
    /** Wired Equivalent Privacy (WEP) */
    WIFI_SEC_TYPE_WEP,
    /** Pre-shared key (PSK) */
    WIFI_SEC_TYPE_PSK,
    /** Simultaneous Authentication of Equals (SAE) */
    WIFI_SEC_TYPE_SAE,
} WifiSecurityType;

WIFI_SEC_TYPE_OPEN,即开放式 Wi-Fi 网络,是指没有设置任何加密或安全验证措施的无线网络。在这种类型的网络中,任何设备都可以直接连接到 Wi-Fi网络,而无需输入任何密码或进行身份验证。

WIFI_SEC_TYPE_WEP(Wired Equivalent Privacy)是一种早期的无线网络安全协议,旨在提供与有线网络相当的安全性。然而,随着时间的推移和加密技术的进步,WEP 已被证明存在严重的安全漏洞,并且不再被推荐用于保护无线网络。

WIFI_SEC_TYPE_PSK(Pre-Shared Key)是 Wi-Fi 网络中常用的一种安全类型,它代表预共享密钥模式。在这种模式下,网络上的所有客户端都使用相同的密钥(密码)来访问网络,这个密钥在网络设置时由管理员设定,并需要在客户端设备连接到网络时输入。

WIFI_SEC_TYPE_SAE(Simultaneous Authentication of Equals)是 Wi-Fi Protected Access 3(WPA3)标准中引入的一种安全类型,它主要用于增强个人无线网络的安全性。

band:Wi-Fi 热点模式支持的频带

/**
 * @brief Enumerates frequency bands supported by the Wi-Fi hotspot mode.
 *
 * @since 7
 */
typedef enum {
    /** 2.4 GHz */
    HOTSPOT_BAND_TYPE_2G = 1,
    /** 5 GHz */
    HOTSPOT_BAND_TYPE_5G = 2,
} HotspotBandType;

channelNum:2.4G 频段 wifi 信道可支持 14 个,可选为 1-14;

preSharedKey:WIFI 共享密钥,最大长度为 65

3.8 GetHotspotConfig

/**
 * @brief Obtains a specified hotspot configuration.
 *
 * The hotspot configuration includes the SSID, security type, and key. \n
 *
 * @param result Indicates the obtained hotspot configuration.
 * @return Returns {@link WIFI_SUCCESS} if the hotspot configuration is obtained; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode GetHotspotConfig(HotspotConfig *result)
功能:
	获取指定的热点配置
参数:
	result:获取指定的热点配置结果
返回值:
	0 成功,非 0 错误值     

3.9 IsHotspotActive

/**
 * @brief Checks whether the hotspot mode is enabled.
 *
 * @return Returns {@link WIFI_HOTSPOT_ACTIVE} if the hotspot mode is enabled; returns {@link WIFI_HOTSPOT_NOT_ACTIVE}
 * otherwise.
 * @since 7
 */
int IsHotspotActive(void)
功能:
	检查AP热点模式是否启用
参数:
	
返回值:
	WIFI_HOTSPOT_ACTIVE 激活,WIFI_HOTSPOT_NOT_ACTIVE 未激活

04. 硬件设计

由于 Hi3861 内置 WIFI 功能,所以直接在开发板上使用即可,无需额外连接。

05. 模块参考

5.1 注册wifi事件的回调函数

通过 RegisterWifiEvent 接口向系统注册热点状态改变事件、STA站点加入事件、STA站点退出事件

//注册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");

5.2 终端设备加入

定义成功加入AP热点的终端设备数量 g_apEnableSuccess

static int g_apEnableSuccess = 0;

实现 OnHotspotStaJoinHandler() 终端设备加入处理函数。

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

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;
}

实现 HotspotStaJoinTask() 终端设备加入处理任务

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++;
}

5.3 终端设备离开

实现 OnHotspotStaLeaveHandler() 终端设备离开处理函数。

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

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;
}

5.4 AP热点状态改变

实现 OnHotspotStateChangedHandler() AP热点状态改变处理函数。

用于绑定热点状态改变事件,该回调函数有一个参数 state

  • state表示是否开启AP模式,取值为0和1,0表示已启用Wifi AP模式,1表示已禁用Wifi AP模式;
  • 当已启用Wifi AP模式,该回调函数会将标志位 g_apEnableSuccess 置 1;
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");
    }
}

5.5 Wi-Fi配置

调用 SetHotspotConfig 接口,设置指定的热点配置。

//设置指定的热点配置
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;      // 2.4G频率
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");

5.6 Wi-Fi启动阶段

调用 EnableHotspot 接口,使能 Wifi AP 模式。
调用 IsHotspotActive 接口,检查AP热点模式是否启用。

//启动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");

5.7 LwIP初始阶段

//启动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");
}

5.8 参考完整代码

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

#include "cmsis_os2.h"
#include "ohos_init.h"

#include "wifi_device.h"
#include "wifi_hotspot.h"
#include "wifi_error_code.h"
#include "lwip/netifapi.h"


#define AP_SSID "BearPi"
#define AP_PSK  "12345678"

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

    }

    while (1)
    {
        osDelay(1000);
    }
}

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

static void Wifi_AP_Demo(void)
{
    osThreadAttr_t attr;

    attr.name = "WifiAPTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = 25;

    if (osThreadNew((osThreadFunc_t)WifiAPTask, NULL, &attr) == NULL)
    {
        printf("Falied to create WifiAPTask!\r\n");
    }
}

APP_FEATURE_INIT(Wifi_AP_Demo);

06. 软件设计

bsp_wifi.h

#ifndef __BSP_WIFI_H__
#define __BSP_WIFI_H__


#include "cmsis_os2.h"
#include "hi_io.h"
#include "hi_gpio.h"
#include "wifi_error_code.h"
#include "wifi_device.h"

//函数声明
WifiErrorCode WiFi_createHotSpots(const char *ssid, const char *psk);



#endif /* __BSP_WIFI_H__ */


bsp_wifi.c


#include "bsp_wifi.h"

#include <unistd.h>
#include "wifi_device.h"
#include "wifi_hotspot.h"
#include "lwip/netifapi.h"
#include "lwip/netif.h"
#include "lwip/ip4_addr.h"
#include "lwip/api_shell.h"


//WIFI通道
#define WIFI_CHANNEL    5

/** Hotspot state change */
void OnHotspotStateChangedCallbak(int state)
{
    printf("OnHotspotStateChangedCallbak: state is %d.\n", state);
    if (WIFI_HOTSPOT_ACTIVE == state)
    {
        printf("wifi hotspot active\n");
    }
    else
    {
        printf("wifi hotspot noactive\n");
    }
}

/** Station connected */
void OnHotspotStaJoinCallbak(StationInfo *info)
{
    static char macAddr[32] = {0};
    static unsigned char *mac = NULL;

    if (NULL == info)
    {
        printf("OnHotspotStaJoinCallbak is NULL\n");
    }
    else
    {
        mac = info->macAddress;
        snprintf(macAddr, sizeof(macAddr), "%02X:%02X:%02X:%02X:%02X:%02X",
        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

        printf("OnHotspotStaJoinCallbak: mac: %s reason: %d\n", macAddr, info->disconnectedReason);
    }
}

/** Station disconnected */
void OnHotspotStaLeaveCallbak(StationInfo *info)
{
    static char macAddr[32] = {0};
    static unsigned char *mac = NULL;

    if (NULL == info)
    {
        printf("OnHotspotStaLeaveCallbak is NULL\n");
    }
    else
    {
        mac = info->macAddress;
        snprintf(macAddr, sizeof(macAddr), "%02X:%02X:%02X:%02X:%02X:%02X",
        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

        printf("OnHotspotStaLeaveCallbak: mac: %s reason: %d\n", macAddr, info->disconnectedReason);
    }

}

//创建Wifi热点
WifiErrorCode WiFi_createHotSpots(const char *ssid, const char *psk)
{
    WifiErrorCode ret;

    static WifiEvent event;

    static HotspotConfig config;

    printf("Start Initialization of WiFI AP Mode\r\n");

    //注册WIFI事件的回调函数
    event.OnHotspotStaJoin = OnHotspotStaJoinCallbak;
    event.OnHotspotStaLeave = OnHotspotStaLeaveCallbak;
    event.OnHotspotStateChanged =OnHotspotStateChangedCallbak;
    ret = RegisterWifiEvent(&event);
    if (WIFI_SUCCESS != ret)
    {
        printf("RegisterWifiEvent failed....\n");
        return -1;
    }
    printf("RegisterWifiEvent OK .....\n");

    //设置热点
    strcpy(config.ssid, ssid);
    strcpy(config.preSharedKey, psk);
    config.band = HOTSPOT_BAND_TYPE_2G;
    config.channelNum = WIFI_CHANNEL;
    config.securityType = WIFI_SEC_TYPE_PSK;
    ret = SetHotspotConfig(&config);
    if (WIFI_SUCCESS != ret)
    {
        printf("SetHotspotConfig failed....\n");
        return -1;
    }
    printf("SetHotspotConfig OK....\n");

    //启动WIFI AP模式
    ret = EnableHotspot();
    if (WIFI_SUCCESS != ret)
    {
        printf("EnableHotspot failed...\n");
        return -1;
    }
    printf("EnableHotspot OK ....\n");

    //检查热点模式是否使能
    if (WIFI_HOTSPOT_ACTIVE != IsHotspotActive())
    {
        printf("IsHotspotActive failed....\n");
        return -1;
    }
    printf("IsHotspotActive OK .....\n");
}

template.c


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

#include "ohos_init.h"
#include "cmsis_os2.h"

#include "bsp_wifi.h"

#define TASK_STACK_SIZE 1024

//任务1ID
osThreadId_t task1_id;
osThreadId_t task2_id;



//线程回调入口函数
void task1 (void *argument)
{

    WiFi_createHotSpots("IOT2", "12345678");

    while(1)
    {
        sleep(1);
    }

}



/**
 * @description: 初始化并创建任务
 * @param {*}
 * @return {*}
 */
static void template_demo(void)
{  
    osThreadAttr_t attr;
    attr.name = "task1"; //任务名称
    attr.attr_bits = osThreadDetached; //分离状态
    attr.cb_mem = NULL;
    attr.cb_size = 0;
    attr.stack_mem = NULL;
    attr.stack_size = TASK_STACK_SIZE * 10;
    attr.priority = osPriorityNormal;


    //创建任务1
    task1_id = osThreadNew(task1, NULL, &attr);
    if (NULL != task1_id)
    {
        printf("任务1创建OK task1_id = %d\n", task1_id);
    }

}
SYS_RUN(template_demo);

07. 实验现象

实验现象:建立好 WiFi 热点之后,手机可以连接这个节点,然后在串口调试助手中打印出设备的连接信息。

在这里插入图片描述

08. 附录

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2319649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大模型的微调技术(高效微调原理篇)

背景 公司有需求做农业方向的大模型应用以及Agent助手&#xff0c;那么适配农业数据就非常重要。但众所周知&#xff0c;大模型的全量微调对算力资源要求巨大&#xff0c;在现实的限制条件下基本“玩不起”&#xff0c;那么高效微调技术就非常必要。为了更好地对微调技术选型和…

区间震荡指标

区间震荡指标的逻辑如下&#xff1a; 一、函数注解 1. Summation函数 功能&#xff1a; 计算给定价格序列Price的前Length个数据点的和&#xff0c;或在数据点数量超过Length时&#xff0c;计算滚动窗口内的价格和。 参数&#xff1a; Price(1)&#xff1a;价格序列&#…

HCIE-SLAAC

文章目录 SLAAC &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Datacom专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2025年03月21日10点58分 SLAAC 帮助设备发现本地直连链路相连的设备&#xff0c;并获取与地址自动配置的相关前缀和其他…

JavaScript | 爬虫逆向 | 掌握基础 | 01

一、摘要 实践是最好的导师 二、环境配置 在开始之前&#xff0c;需要确保你的计算机上已经安装了 Node.js。Node.js 是一个开源的、跨平台的 JavaScript 运行时环境&#xff0c;它允许你在服务器端运行 JavaScript 代码。 1. 下载 安装地址&#xff1a;https://nodejs.org…

力扣算法Hot100——128. 最长连续序列

题目要求时间复杂度为O(n)&#xff0c;因此不能使用两次循环匹配。 首先使用 HashSet 去重&#xff0c;并且 HashSet 查找一个数的复杂度为O(1)外循环还是遍历set集合&#xff0c;里面一重循环需要添加判断&#xff0c;这样才不会达到O( n 2 n^2 n2)判断是否进入最长序列查找循…

深入解析 Java Stream API:从 List 到 Map 的优雅转换!!!

&#x1f680; 深入解析 Java Stream API&#xff1a;从 List 到 Map 的优雅转换 &#x1f527; 大家好&#xff01;&#x1f44b; 今天我们来聊聊 Java 8 中一个非常常见的操作&#xff1a;使用 Stream API 将 List 转换为 Map。&#x1f389; 具体来说&#xff0c;我们将深入…

当全球化成为商业常态,Shopify 如何为品牌生意铺平出海之路?

从独立站搭建到支付履约&#xff0c;从数据分析到生态整合&#xff0c;Shopify 为不同规模的企业提供可扩展的解决方案。 在数字化浪潮的推动下&#xff0c;跨境电商与品牌出海的黄金时代已然到来。然而&#xff0c;看似广阔的市场蓝海背后&#xff0c;是无数企业正在经历的“成…

RC6在线加密工具

RC6加密算法是一种基于RC5改进的分组密码算法&#xff0c;曾作为AES&#xff08;高级加密标准&#xff09;的候选算法之一。它采用了4个32位寄存器&#xff0c;增加了32位整数乘法运算&#xff0c;以增强扩散和混淆特性&#xff0c;提高了安全性。RC6的设计简单、高效&#xff…

python每日十题(5)

保留字&#xff0c;也称关键字&#xff0c;是指被编程语言内部定义并保留使用的标识符。Python 3.x版本中有35个保留字&#xff0c;分别为&#xff1a;and, as,assert,async,await,break,class,continue,def,del,elif,else, except, False, finally,for,from,global, if,import…

应用案例 | 核能工业:M-PM助力核工业科研项目

M-PM助力核工业科研项目 一、项目背景 在核工业复杂系统的研发进程中&#xff0c;MBSE&#xff08;基于模型的系统工程&#xff09;方法的应用愈发成熟&#xff0c;已然成为推动系统设计与优化的关键力量。如今&#xff0c;各相关设计系统的 MBSE 模型数据呈现出精细化、多元…

4.1、网络安全模型

目录 网络安全体系概述网络安全模型-BLP模型网络安全模型-Biba模型网络安全模型 - 信息流模型信息保障模型能力成熟度模型其它安全模型网络安全原则 网络安全体系概述 网络安全体系是网络安全保证系统的最高层概念抽象&#xff0c;是一个体系&#xff0c;体系一般是一个概念&a…

ManiWAV:通过野外的音频-视频数据学习机器人操作

24年6月来自斯坦福大学、哥伦比亚大学和 TRI 的论文“ManiWAV: Learning Robot Manipulation from In-the-Wild Audio-Visual Data”。 音频信号通过接触为机器人交互和物体属性提供丰富的信息。这些信息可以简化接触丰富的机器人操作技能学习&#xff0c;尤其是当视觉信息本身…

Floyd 算法——97. 小明逛公园

卡码网:97. 小明逛公园https://kamacoder.com/problempage.php?pid=1155 题目描述 小明喜欢去公园散步,公园内布置了许多的景点,相互之间通过小路连接,小明希望在观看景点的同时,能够节省体力,走最短的路径。 给定一个公园景点图,图中有 N 个景点(编号为 1 到 N),…

QT二 QT使用generate form 生成常用UI,各种UI控件

一 。没有使用general form 和 使用 general form 后&#xff0c;file层面和代码层面的不同比较 file层面的不同 代码层面的不同&#xff0c; 在 使用了general form之后&#xff0c;在主界面的构造方法中&#xff0c;使用ui->setupUi(this),就完成了所有UI的处理。 而之…

多条件排序(C# and Lua)

C# 升序排序 OrderBy 按升序对序列的元素进行排序 ThenBy 按升序对序列中的元素执行后续排序 降序排序 OrderByDescending 按降序对序列的元素排序 ThenByDescending 按降序对序列中的元素执行后续排序 public class Fruit {public int id;public string name;publi…

人工智能之数学基础:线性方程组求解的得力助手——增广矩阵

本文重点 增广矩阵是一个极具实用价值的工具,尤其在处理线性方程组时,它展现了卓越的功效。通过整合系数和常数项,增广矩阵简化了计算过程并提供了判断方程组解集的有效方法。 增广矩阵的起源与定义 增广矩阵的概念源于线性方程组求解的需求。在解决线性方程组时,我们常…

关于Flask框架30道面试题及解析

文章目录 基础概念1. 什么是Flask?其核心特性是什么?2. Flask和Django的主要区别?3. 解释Flask中的“路由”概念。如何定义动态路由?核心组件4. Flask的请求上下文(Request Context)和应用上下文(Application Context)有什么区别?5. 如何访问请求参数?POST和GET方法的…

服务安全认证概述与基础认证方式

文章目录 1. 引言1.1 认证与授权的区别1.2 认证方式的演进 2. 基础认证方式2.1 HTTP Basic Authentication2.2 API Key 认证2.3 HMAC-SHA256 签名认证2.4 JWT&#xff08;JSON Web Token&#xff09; 3. 认证方式对比与总结3.1 认证方式对比3.2 如何选择合适的认证方式&#xf…

【Android Studio开发】生命周期、Activity和组件通信(上)

零、前期配置 1.【Android】模式 2.点击【运行】&#xff0c;弹出模拟器 右侧是模拟机&#xff0c;显示Hello World 3. 打开【activity_main.xml】文件&#xff0c;点击【Design】&#xff0c;然后点击【Component Tree】 在弹出的Component Tree中右键【main】,选择【Conver…

【ES】Elasticsearch学习

文章目录 简单的安装 简单的安装 参考&#xff1a;https://blog.csdn.net/smilehappiness/article/details/118466378 官网&#xff1a;https://www.elastic.co/guide/en/elasticsearch/reference/current/targz.html 下载&#xff1a;https://www.elastic.co/cn/downloads/e…