赞
踩
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芯片适应于智能家电等物联网智能终端领域。
更多的可以去官方社区账号专栏看。本文主要总结鸿蒙的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.11协议实现模块。
Platform平台:提供SoC系统板级支持包(包括:芯片和外围设备驱动、操作系统以及系统管理)
鸿蒙系统代码的API文件在如下路径:
foundation\communication\interfaces\kits\wifi_lite\wifiservice\wifi_device.h foundation\communication\interfaces\kits\wifi_lite\wifiservice\wifi_hotspot.h
1. RegisterWifiEvent()
WifiErrorCode RegisterWifiEvent (WifiEvent * event)
描述: 为指定的Wi-Fi事件注册回调函数。当WifiEvent中定义的Wi-Fi事件发生时,将调用已注册的回调函数
参数:
名字 | 描述 |
---|---|
event | 表示要注册回调的事件 |
2. EnableHotspot()
WifiErrorCode EnableHotspot (void )
描述: 启用Wifi热点模式
3. SetHotspotConfig()
WifiErrorCode SetHotspotConfig(const HotspotConfig* config)
描述: 设置指定的热点配置
4. IsHotspotActive()
int IsHotspotActive(void);
描述: 检查AP热点模式是否启用
5. GetStationList()
WifiErrorCode GetStationList(StationInfo* result, unsigned int* size)
描述: 获取连接到该热点的一系列STA
参数:
名字 | 描述 |
---|---|
result | 表示连接到该热点的STA列表 |
size | 表示连接到该热点的STA数量 |
6. EnableWifi()
WifiErrorCode EnableWifi (void )
描述: 启用STA模式
7. AddDeviceConfig()
WifiErrorCode AddDeviceConfig (const WifiDeviceConfig * config, int * result )
描述: 添加用于配置连接的热点信息,此函数生成一个networkId
参数:
名字 | 描述 |
---|---|
config | 表示要连接的热点信息 |
result | 表示生成的networkId。每个networkId匹配一个热点配置 |
8. ConnectTo()
WifiErrorCode ConnectTo (int networkId)
描述: 连接到指定networkId的热点
9. netifapi_netif_find()
struct netif *netifapi_netif_find(const char *name);
描述: 获取netif用于IP操作
10. dhcp_start()
err_t dhcp_start(n)
描述:启动DHCP, 获取IP
AP:无线接入点,是一个无线网络的创建者,是网络的中心节点。一般家庭或办公室使用的无线路由器就是一个AP。
STA站点:就是每一个连接到无线网络中的终端(如笔记本电脑、PDA及其它可以联网的用户设备)都可称为一个站点。
AP模式: Access Point,提供无线接入服务,允许其它无线设备接入,提供数据访问,一般的无线路由/网桥工作在该模式下。AP和AP之间允许相互连接。
在此模式下,手机、PAD、电脑等设备可以直接连上模块,可以很方便对用户设备进行控制。
Sta模式: Station, 类似于无线终端,sta本身并不接受无线的接入,它可以连接到AP,一般无线网卡即工作在该模式。
这是一种基本的组网方式,由一个AP和许多STA组成。其特点是AP处于中心地位,STA之间的相互通信都通过AP转发完成。该模式下,WIFI模块工作在STA(CLIENT)模式。通过适当的设置,COM的数据与WIFI的网路数据相互转换。
鸿蒙设备完成Wifi热点的扫描需要以下几步
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地址;
调用 SetHotspotConfig
接口,设置指定的热点配置;
调用 EnableHotspot
接口,使能 Wifi AP 模式;
调用 IsHotspotActive
接口,检查AP热点模式是否启用;
调用 netifapi_netif_set_addr
函数设置网卡信息;
调用 netifapi_dhcps_start
函数启动dhcp服务;
鸿蒙设备完成Wifi热点的连接需要以下几步
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断开的原因. |
EnableWifi
接口,使能 Wifi。AddDeviceConfig
接口,配置连接的热点信息。ConnectTo
接口,连接到指定networkId的热点。WaitConnectResult
接口等待,该函数中会有15s的时间去轮询连接成功标志位 g_ConnectSuccess
,当g_ConnectSuccess
为 1 时退出等待。netifapi_netif_find
接口,获取 netif 用于 IP 操作dhcp_start
接口,启动 DHCP, 获取 IP此模式下并不能联网,只是能够将终端连接到设备而已。如需联网应该采用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"); } }
1.修改BUILD.gn
修改 applications\BearPi\BearPi-HM_Nano\sample
路径下 BUILD.gn 文件,指定 wifi_ap 参与编译。
2.编译
Linux终端或者MobaXterm的会话连接内,进入代码目录执行 python build.py BearPi-HM_Nano
进行编译。
3.烧录
使用HiBurn工具,波特率设置为2000000.
选择对应的com口和要烧录的文件,勾选auto burn。点击connect,再点开发板复位按键。进行烧录。
4.运行结果
通过MobaXterm的串口工具查看。用手机连一下试试。
此模式下设备能联网,但是不能够将终端连接到设备。如需联网应该采用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{ //重置标志位 ssid_count = 0; g_staScanSuccess = 0; //开始扫描 Scan(); //等待扫描结果 WaitSacnResult(); //获取扫描列表 error = GetScanInfoList(info, &size); }while(g_staScanSuccess != 1); //打印WiFi列表 printf("********************\r\n"); for(uint8_t i = 0; i < ssid_count; i++) { printf("no:%03d, ssid:%-30s, rssi:%5d\r\n", i+1, info[i].ssid, info[i].rssi/100); } printf("********************\r\n"); //连接指定的WiFi热点 for(uint8_t i = 0; i < ssid_count; i++) { if (strcmp(SELECT_WIFI_SSID, info[i].ssid) == 0) { int result; printf("Select:%3d wireless, Waiting...\r\n", i+1); //拷贝要连接的热点信息 strcpy(select_ap_config.ssid, info[i].ssid); strcpy(select_ap_config.preSharedKey, SELECT_WIFI_PASSWORD); select_ap_config.securityType = SELECT_WIFI_SECURITYTYPE; if (AddDeviceConfig(&select_ap_config, &result) == WIFI_SUCCESS) { if (ConnectTo(result) == WIFI_SUCCESS && WaitConnectResult() == 1) { printf("WiFi connect succeed!\r\n"); g_lwip_netif = netifapi_netif_find(SELECT_WLAN_PORT); break; } } } if(i == ssid_count-1) { printf("ERROR: No wifi as expected\r\n"); while(1) osDelay(100); } } //启动DHCP if (g_lwip_netif) { dhcp_start(g_lwip_netif); printf("begain to dhcp"); } //等待DHCP for(;;) { if(dhcp_is_bound(g_lwip_netif) == ERR_OK) { printf("<-- DHCP state:OK -->\r\n"); //打印获取到的IP信息 netifapi_netif_common(g_lwip_netif, dhcp_clients_info_show, NULL); break; } printf("<-- DHCP state:Inprogress -->\r\n"); osDelay(100); } //执行其他操作 for(;;) { osDelay(100); } }
回调函数
将回调函数的注册绑定写到了初始化函数里。
static void WiFiInit(void) { printf("<--Wifi Init-->\r\n"); g_wifiEventHandler.OnWifiScanStateChanged = OnWifiScanStateChangedHandler; g_wifiEventHandler.OnWifiConnectionChanged = OnWifiConnectionChangedHandler; g_wifiEventHandler.OnHotspotStaJoin = OnHotspotStaJoinHandler; g_wifiEventHandler.OnHotspotStaLeave = OnHotspotStaLeaveHandler; g_wifiEventHandler.OnHotspotStateChanged = OnHotspotStateChangedHandler; error = RegisterWifiEvent(&g_wifiEventHandler); if (error != WIFI_SUCCESS) { printf("register wifi event fail!\r\n"); } else { printf("register wifi event succeed!\r\n"); } } static void OnWifiScanStateChangedHandler(int state, int size) { (void)state; if (size > 0) { ssid_count = size; g_staScanSuccess = 1; } return; } static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo *info) { (void)info; if (state > 0) { g_ConnectSuccess = 1; printf("callback function for wifi connect\r\n"); } else { printf("connect error,please check password\r\n"); } return; } static void OnHotspotStaJoinHandler(StationInfo *info) { (void)info; printf("STA join AP\n"); return; } static void OnHotspotStaLeaveHandler(StationInfo *info) { (void)info; printf("HotspotStaLeave:info is null.\n"); return; } static void OnHotspotStateChangedHandler(int state) { printf("HotspotStateChanged:state is %d.\n", state); return; } static void WaitSacnResult(void) { int scanTimeout = DEF_TIMEOUT; while (scanTimeout > 0) { sleep(ONE_SECOND); scanTimeout--; if (g_staScanSuccess == 1) { printf("WaitSacnResult:wait success[%d]s\n", (DEF_TIMEOUT - scanTimeout)); break; } } if (scanTimeout <= 0) { printf("WaitSacnResult:timeout!\n"); } } static int WaitConnectResult(void) { int ConnectTimeout = DEF_TIMEOUT; while (ConnectTimeout > 0) { sleep(1); ConnectTimeout--; if (g_ConnectSuccess == 1) { printf("WaitConnectResult:wait success[%d]s\n", (DEF_TIMEOUT - ConnectTimeout)); break; } } if (ConnectTimeout <= 0) { printf("WaitConnectResult:timeout!\n"); return 0; } return 1; }
1.修改BUILD.gn
修改 applications\BearPi\BearPi-HM_Nano\sample
路径下 BUILD.gn 文件,指定 wifi_sta_connect
参与编译。
2.编译
Linux终端或者MobaXterm的会话连接内,进入代码目录执行 python build.py BearPi-HM_Nano
进行编译。
3.烧录
使用HiBurn工具,波特率设置为2000000.
选择对应的com口和要烧录的文件,勾选auto burn。点击connect,再点开发板复位按键。进行烧录。
4.运行结果
通过MobaXterm的串口工具查看。
ready to OS start sdk ver:Hi3861V100R001C00SPC025 2020-09-03 18:10:00 formatting spiffs... FileSystem mount ok. wifi init success! 00 00:00:00 0 196 D 0/HIVIEW: hilog init success. 00 00:00:00 0 196 D 0/HIVIEW: log limit init success. 00 00:00:00 0 196 I 1/SAMGR: Bootstrap core services(count:3). 00 00:00:00 0 196 I 1/SAMGR: Init service:0x4af9bc TaskPool:0xfa724 00 00:00:00 0 196 I 1/SAMGR: Init service:0x4af9e0 TaskPool:0xfad94 00 00:00:00 0 196 I 1/SAMGR: Init service:0x4afaf0 TaskPool:0xfaf54 00 00:00:00 0 228 I 1/SAMGR: Init service 0x4af9e0 <time: 0ms> success! 00 00:00:00 0 128 I 1/SAMGR: Init service 0x4af9bc <time: 0ms> success! 00 00:00:00 0 72 D 0/HIVIEW: hiview init success. 00 00:00:00 0 72 I 1/SAMGR: Init service 0x4afaf0 <time: 0ms> success! 00 00:00:00 0 72 I 1/SAMGR: Initialized all core system services! 00 00:00:00 0 128 I 1/SAMGR: Bootstrap system and application services(count:0). 00 00:00:00 0 128 I 1/SAMGR: Initialized all system and application services! 00 00:00:00 0 128 I 1/SAMGR: Bootstrap dynamic registered services(count:0). <--System Init--> <--Wifi Init--> register wifi event succeed! +NOTICE:SCANFINISH WaitSacnResult:wait success[1]s ******************** no:001, ssid:HONOR 70 Pro , rssi: -48 no:002, ssid:FAST_3886 , rssi: -51 ******************** Select: 1 wireless, Waiting... +NOTICE:CONNECTED callback function for wifi connect WaitConnectResult:wait success[1]s WiFi connect succeed! begain to dhcp<-- DHCP state:Inprogress --> <-- DHCP state:OK --> server : server_id : 192.168.244.147 mask : 255.255.255.0, 1 gw : 192.168.244.147 T0 : 3599 T1 : 1799 T2 : 3149 clients <1> : mac_idx mac addr state lease tries rto 0 3c11317c4ad7 192.168.244.27 10 0 1 4
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。