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 热点之后,手机可以连接这个节点,然后在串口调试助手中打印出设备的连接信息。