新增WiFi-STA模式联网案例

This commit is contained in:
艾彬 2021-09-29 11:04:57 +08:00
parent 32346e353f
commit bcda109949
9 changed files with 570 additions and 2 deletions

View File

@ -78,6 +78,7 @@
| TW105 | I2C | i2c_sht30 | [I2C温湿度传感器采集](applications/app/TW105_I2C_sht30/README.md) | 核心板 + 马达扩展板| | TW105 | I2C | i2c_sht30 | [I2C温湿度传感器采集](applications/app/TW105_I2C_sht30/README.md) | 核心板 + 马达扩展板|
| TW106 | UART | uart | [UART串口自发自收](applications/app/TW106_UART/README.md) | 核心板 | | TW106 | UART | uart | [UART串口自发自收](applications/app/TW106_UART/README.md) | 核心板 |
| TW201 | Module | oled | [OLED显示屏驱动](applications/app/TW201_Module_oled/README.md) | 核心板 + OLED扩展板| | TW201 | Module | oled | [OLED显示屏驱动](applications/app/TW201_Module_oled/README.md) | 核心板 + OLED扩展板|
| TW301 | Network | wifista | [WiFi-STA连接演示](applications/app/TW301_Network_wifista/README.md) | 核心板 |
## 五、源码目录简介 ## 五、源码目录简介

View File

@ -29,5 +29,6 @@ lite_component("app") {
# "TW105_I2C_sht30:i2c_sht30", # "TW105_I2C_sht30:i2c_sht30",
# "TW106_UART:uart_example", # "TW106_UART:uart_example",
# "TW201_Module_oled:module_oled_example", # "TW201_Module_oled:module_oled_example",
# "TW301_Network_wifista:network_wifista_example",
] ]
} }

View File

@ -28,3 +28,4 @@
| TW105 | I2C | i2c_sht30 | [I2C温湿度传感器采集](applications/app/TW105_I2C_sht30/README.md) | 核心板 + 马达扩展板| | TW105 | I2C | i2c_sht30 | [I2C温湿度传感器采集](applications/app/TW105_I2C_sht30/README.md) | 核心板 + 马达扩展板|
| TW106 | UART | uart | [UART串口自发自收](applications/app/TW106_UART/README.md) | 核心板 | | TW106 | UART | uart | [UART串口自发自收](applications/app/TW106_UART/README.md) | 核心板 |
| TW201 | Module | oled | [OLED显示屏驱动](applications/app/TW201_Module_oled/README.md) | 核心板 + OLED扩展板| | TW201 | Module | oled | [OLED显示屏驱动](applications/app/TW201_Module_oled/README.md) | 核心板 + OLED扩展板|
| TW301 | Network | wifista | [WiFi-STA连接演示](applications/app/TW301_Network_wifista/README.md) | 核心板 |

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
static_library("uart_test"){ static_library("uart_example"){
sources =[ sources =[
"uart_example.c" "uart_example.c"
] ]

View File

@ -0,0 +1,25 @@
# Copyright (c) 2021 Talkweb Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("network_wifista_example") {
sources = [
"wifi_connect_demo.c",
]
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/kal/cmsis",
"//foundation/communication/wifi_lite/interfaces/wifiservice",
"//device/talkweb/niobe/sdk_liteos/third_party/lwip_sack/include",
]
}

View File

@ -0,0 +1,322 @@
# Niobe开发板WiFi-STA联网演示
本案例程序将演示怎么在拓维Niobe WiFi IoT Core开发板上编写一个连接Wifi热点的业务程序实现开发板联网效果。
![image-20210924115053858](figure/image-20210924115053858.png)
## Wifi API分析
本案例主要使用了以下几个API完成Wifi联网
## RegisterWifiEvent()
```
WifiErrorCode RegisterWifiEvent (WifiEvent * event)
```
**描述:** 为指定的Wi-Fi事件注册回调函数。当WifiEvent中定义的Wi-Fi事件发生时将调用已注册的回调函数
**参数:**
| 名字 | 描述 |
| ----- | --------------------- |
| event | 表示要注册回调的事件. |
## UnRegisterWifiEvent()
```
WifiErrorCode UnRegisterWifiEvent (WifiEvent * event)
```
**描述:** 为指定的Wi-Fi事件取消已经注册的回调函数。
**参数:**
| 名字 | 描述 |
| ----- | ------------------------- |
| event | 表示已经注册的回调的事件. |
## EnableWifi()
```
WifiErrorCode EnableWifi (void )
```
**描述:**
启用STA模式
## DisableWifi()
```
WifiErrorCode DisableWifi (void )
```
**描述:**
禁用STA模式
## AddDeviceConfig()
```
WifiErrorCode AddDeviceConfig (const WifiDeviceConfig * config, int * result )
```
**描述:**
添加用于配置连接到热点信息此函数生成一个networkId
**参数:**
| 名字 | 描述 |
| ------ | -------------------------------------------------- |
| config | 表示要连接的热点信息. |
| result | 表示生成的networkId。每个networkId匹配一个热点配置 |
## ConnectTo()
```
WifiErrorCode ConnectTo (int networkId)
```
**描述:**
连接到指定networkId的热点
**参数:**
| 名字 | 描述 |
| --------- | --------------------------- |
| networkId | 表示与目标热点匹配的网络id. |
## Disconnect()
```
WifiErrorCode Disconnect (void)
```
**描述:**
断开已连接到的热点
## netifapi_netif_find()
```
struct netif *netifapi_netif_find(const char *name);
```
**描述:**
获取netif用于IP操作
## netifapi_dhcp_start()
```
err_t netifapi_dhcp_start(struct netif *netif);
```
**描述:**
启动DHCP, 获取IP
## dhcp_clients_info_show()
```
void dhcp_clients_info_show(struct netif *netif_p);
```
**描述:**
格式化DHCP信息到控制台
## netifapi_netif_common()
```
err_t netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc, netifapi_errt_fn errtfunc);
```
**描述:**
此函数主要是保证voidfunc和errtfunc在安全线程中执行。
## 软件设计
**主要代码分析**
完成Wifi热点的连接需要以下几步
1. 通过 `RegisterWifiEvent` 接口向系统注册扫描状态监听函数,用于接收扫描状态通知,如扫描动作是否完成等。
`OnWifiConnectionChanged` 用于绑定连接状态监听函数,该回调函数有两个参数 `state``info`
state表示扫描状态取值为0和11表示热点连接成功
info表示Wi-Fi连接信息包含以下参数
| 名字 | 描述 |
| ------------------------ | ------------------- |
| ssid [WIFI_MAX_SSID_LEN] | 连接的热点名称. |
| bssid [WIFI_MAC_LEN] | MAC地址. |
| rssi | 接收信号强度(RSSI). |
| connState | Wifi连接状态. |
| disconnectedReason | Wi-Fi断开的原因. |
| ipAddress | 连接的特点IP地址 |
2. 调用 `EnableWifi` 接口,启动 Wifi STA模式。
3. 调用 `AddDeviceConfig` 接口,配置连接的热点信息。
4. 调用 `ConnectTo` 接口连接到指定networkId的热点。
5. while循环等待该过程中会有几秒钟的时间去轮询WiFi连接成功标志位 `g_wifiState`,当`g_wifiState` 为 1 时退出等待。
6. 调用 `netifapi_netif_find` 接口,获取 netif 用于 IP 操作。
7. 调用 `netifapi_dhcp_start` 接口,启动 DHCP, 获取 IP。
8. 调用`netifapi_netif_common`接口打印HDCP信息。
9. 如果DHCP IP获取失败断开WiFi连接重新启动。
```c
static void IotWifiConnectTask(void *arg)
{
(void)arg;
WifiErrorCode errCode;
WifiEvent eventListener = {
.OnWifiConnectionChanged = OnWifiConnectionChanged,
.OnWifiScanStateChanged = OnWifiScanStateChanged};
WifiDeviceConfig apConfig = {
.ssid = DEFAILT_WIFI_SSID,
.preSharedKey = DEFAILT_WIFI_PASSWORD,
.securityType = WIFI_SEC_TYPE_PSK};
Delay(10);
errCode = RegisterWifiEvent(&eventListener);
printf("RegisterWifiEvent errCode: %d\r\n", errCode);
while (1)
{
int networkId = -1;
//启动WiFi STA模式
errCode = EnableWifi();
printf("EnableWifi errCode: %d\r\n", errCode);
Delay(100);
errCode = AddDeviceConfig(&apConfig, &networkId);
printf("AddDeviceConfig errCode: %d\r\n", errCode);
g_wifiState = 0;
errCode = ConnectTo(networkId);
printf("ConnectTo(%d) errCode: %d\r\n", networkId, errCode);
while (!g_wifiState)
{
Delay(10);
}
printf("g_wifiState: %d\r\n", g_wifiState);
Delay(3000);
// 联网业务开始
// 这里是网络业务代码...
struct netif *iface = netifapi_netif_find("wlan0");
if (iface)
{
err_t ret = netifapi_dhcp_start(iface);
printf("netifapi_dhcp_start: %d\r\n", ret);
Delay(2000); // 等待DHCP服务分配IP地址
ret = netifapi_netif_common(iface, dhcp_clients_info_show, NULL);
printf("netifapi_netif_common: %d\r\n", ret);
g_wifiState = WIFI_STATE_AVALIABLE;
break; //联网成功,退出循环
}
else
{
// 联网业务结束断开和AP的连接
Disconnect();
RemoveDevice(networkId);
//关闭WiFi STA模式
errCode = DisableWifi();
printf("DisableWifi errCode: %d\r\n", errCode);
Delay(500);
}
}
errCode = UnRegisterWifiEvent(&eventListener);
printf("UnRegisterWifiEvent errCode: %d\r\n", errCode);
}
```
## 编译调试
### 修改对接热点的账号密码
修改`wifi_connect_demo.h`第20行和21行的WiFi热点SSID和密码改成自己环境中的WiFi热点。
```
//此处是默认测试WiFi连接热点具体使用时请修改WiFi的ssid和password
#define DEFAILT_WIFI_SSID "DESKTOP-TALKWEB"
#define DEFAILT_WIFI_PASSWORD "ai123456789"
```
### 修改 BUILD.gn 文件
修改 `applications/app/BUILD.gn` 路径中的 BUILD.gn 文件,指定 `network_wifista_example` 参与编译。
```
# "TW208_Module_ds1307:module_ds1307_example",
# "TW209_Module_gps:module_gps_example",
"TW301_Network_wifista:network_wifista_example",
# "TW302_Network_wifiap:network_wifiap_example",
# "TW303_Network_mqttclient:network_mqttclient_example",
# "TW304_Network_httpclient:network_httpclient_example",
# "TW305_Network_ntpclient:network_ntpclient_example",
```
### 运行结果
示例代码编译烧录代码后按下开发板的RESET按键通过串口助手查看日志会打印连接到的Wifi热点信息。
```
entry wifi connect demo.
RegisterWifiEvent errCode: 0
EnableWifi errCode: 0
AddDeviceConfig errCode: 0
ConnectTo(1) errCode: 0
No crash dump found!
+NOTICE:SCANFINISH
+NOTICE:CONNECTED
OnWifiConnectionChanged 50, state = 1
info: bssid: BA:81:98:01:A9:A5, rssi: 0, connState: 0, reason: 0, ssid: DESKTOP-TALKWEB
g_wifiState: 1
netifapi_dhcp_start: 0
server :
server_id : 192.168.137.1
mask : 255.255.255.0, 1
gw : 192.168.137.1
T0 : 604800
T1 : 302400
T2 : 453600
clients <1> :
mac_idx mac addr state lease tries rto
0 20579e6185a4 192.168.137.176 10 0 1 2
netifapi_netif_common: 0
UnRegisterWifiEvent errCode: 0
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

View File

@ -0,0 +1,190 @@
/*
* Copyright (c) 2021 Talkweb Co.,ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_device.h"
#include "lwip/netifapi.h"
#include "lwip/api_shell.h"
#include "wifi_connect_demo.h"
int g_wifiState = 0;
/**
* @brief WifiLinkedInfo信息
* @param info WifiLinkedInfo指针
*/
static void PrintWifiLinkedInfo(WifiLinkedInfo *info)
{
if (!info)
return;
static char macAddress[32] = {0};
unsigned char *mac = info->bssid;
snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
printf("info: bssid: %s, rssi: %d, connState: %d, reason: %d, ssid: %s\r\n",
macAddress, info->rssi, info->connState, info->disconnectedReason, info->ssid);
}
/**
* @brief WiFi连接状态改变回调
* @param state WiFi连接状态WifiEventState
* @param info WiFi连接信息
*/
static void OnWifiConnectionChanged(int state, WifiLinkedInfo *info)
{
if (!info)
return;
printf("%s %d, state = %d \r\n", __FUNCTION__, __LINE__, state);
PrintWifiLinkedInfo(info);
g_wifiState = state;
}
/**
* @brief WiFi扫描状态改变回调
* @param state WiFi连接状态WifiEventState
* @param size
*/
static void OnWifiScanStateChanged(int state, int size)
{
printf("%s %d, state = %X, size = %d\r\n", __FUNCTION__, __LINE__, state, size);
}
/**
* @brief
* @param ms
*/
static void Delay(uint32_t ms)
{
uint32_t usPerTicks = (1000 * 1000) / osKernelGetTickFreq();
osDelay((ms * 1000) / usPerTicks);
usleep((ms * 1000) % usPerTicks);
}
/**
* @brief WiFi连接程序,CMSIS线程回调函数
* @param arg 线
*/
static void IotWifiConnectTask(void *arg)
{
(void)arg;
WifiErrorCode errCode;
WifiEvent eventListener = {
.OnWifiConnectionChanged = OnWifiConnectionChanged,
.OnWifiScanStateChanged = OnWifiScanStateChanged};
WifiDeviceConfig apConfig = {
.ssid = DEFAILT_WIFI_SSID,
.preSharedKey = DEFAILT_WIFI_PASSWORD,
.securityType = WIFI_SEC_TYPE_PSK};
Delay(10);
errCode = RegisterWifiEvent(&eventListener);
printf("RegisterWifiEvent errCode: %d\r\n", errCode);
while (1)
{
int networkId = -1;
//启动WiFi STA模式
errCode = EnableWifi();
printf("EnableWifi errCode: %d\r\n", errCode);
Delay(100);
errCode = AddDeviceConfig(&apConfig, &networkId);
printf("AddDeviceConfig errCode: %d\r\n", errCode);
g_wifiState = 0;
errCode = ConnectTo(networkId);
printf("ConnectTo(%d) errCode: %d\r\n", networkId, errCode);
while (!g_wifiState)
{
Delay(10);
}
printf("g_wifiState: %d\r\n", g_wifiState);
Delay(3000);
// 联网业务开始
// 这里是网络业务代码...
struct netif *iface = netifapi_netif_find("wlan0");
if (iface)
{
err_t ret = netifapi_dhcp_start(iface);
printf("netifapi_dhcp_start: %d\r\n", ret);
Delay(2000); // 等待DHCP服务分配IP地址
ret = netifapi_netif_common(iface, dhcp_clients_info_show, NULL);
printf("netifapi_netif_common: %d\r\n", ret);
g_wifiState = WIFI_STATE_AVALIABLE;
break; //联网成功,退出循环
}
else
{
// 联网业务结束断开和AP的连接
Disconnect();
RemoveDevice(networkId);
//关闭WiFi STA模式
errCode = DisableWifi();
printf("DisableWifi errCode: %d\r\n", errCode);
Delay(500);
}
}
errCode = UnRegisterWifiEvent(&eventListener);
printf("UnRegisterWifiEvent errCode: %d\r\n", errCode);
}
/**
* @brief WiFi STA模式案例入口函数
*/
void IotWifiConnect(void)
{
printf("\n\n entry wifi connect demo.\r\n");
osThreadAttr_t attr;
attr.name = "IotWifiConnectTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 10240;
attr.priority = osPriorityNormal;
if (osThreadNew(IotWifiConnectTask, NULL, &attr) == NULL)
{
printf("[Talkweb Niobe] Falied to create IotWifiConnectTask!\n");
}
}
APP_FEATURE_INIT(IotWifiConnect);

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2021 Talkweb Co.,ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WIFI_CONNECT_DEMO_H
#define WIFI_CONNECT_DEMO_H
//此处是默认测试WiFi连接热点具体使用时请修改WiFi的ssid和password
#define DEFAILT_WIFI_SSID "DESKTOP-TALKWEB"
#define DEFAILT_WIFI_PASSWORD "ai123456789"
extern int g_wifiState;
void IotWifiConnect(void);
#endif