或许连接操作也可由用户发起, 全部保存的一个变量记录当前设备是否联网即可。
#include "esp_err.h"
#include "esp_event.h"
#include "esp_http_server.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_wifi.h"
#include "esp_wifi_default.h"
#include "esp_wifi_types_generic.h"
#include "freertos/FreeRTOS.h"
#include "freertos/idf_additions.h"
#include "freertos/projdefs.h"
#include "freertos/stream_buffer.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include "portmacro.h"
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
static const char *TAG = "scan";
// 定义事件组, 这里用于阻塞联网后的操作,也就是等待联网后才开始干活
static EventGroupHandle_t s_wifi_event_group;
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
// 记录重试
static int s_retry_num = 0;
const char hello[] = "<h1>Hello, world</h1><p>ESP32C3 is speaking</p>";
static void event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data) {
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < 5) {
esp_wifi_connect();
s_retry_num += 1;
ESP_LOGI("STA", "retry connect to the AP");
} else {
// 超时
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) {
wifi_event_sta_connected_t *event =
(wifi_event_sta_connected_t *)event_data;
ESP_LOGI("STA", "connected: %s", event->ssid);
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
// 拿到 IP, 应该可以冲浪了
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
/**
* @brief init wifi with default
*/
void wifiInit() {
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
}
/**
* @brief Init wifi sta with default config
*
* register event_handler,
*/
void initSta() {
// 先安装事件
ESP_ERROR_CHECK(esp_event_handler_instance_register(
WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(
IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, NULL));
// Initialize default station as network interface instance (esp-netif)
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);
// Initialize and start WiFi
wifi_config_t wifi_config = {
.sta =
{
.ssid = "Man_2.4GHz",
.password = "liang114514",
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_LOGI("STA", "wifi_init_sta finished.");
}
/**
* @brief Connet wifi
*/
void connectWifi() {
// 先创建事件组
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_wifi_start());
// 无限等待, 返回
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE, pdFALSE, portMAX_DELAY);
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI("STA", "connected to ap");
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGI("STA", "Failed to connect to ap");
} else {
ESP_LOGE("Error", "UNEXPECTED EVENT");
}
vEventGroupDelete(s_wifi_event_group);
}
// GET /
static esp_err_t get_root(httpd_req_t *req) {
return httpd_send(req, hello, sizeof(hello));
}
const httpd_uri_t uri_get = {
.uri = "/", .method = HTTP_GET, .handler = get_root, .user_ctx = NULL};
httpd_handle_t setup_server() {
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
httpd_handle_t server = NULL;
if (httpd_start(&server, &config) == ESP_OK) {
// 绑定http请求处理函数,httpd自动解析path和method匹配处理
httpd_register_uri_handler(server, &uri_get);
}
return server;
}
void app_main() {
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
wifiInit();
initSta();
connectWifi();
setup_server();
}
本省 app_main
就是个线程, 其中 我们启用了事件轮训和 httpd_start
这里会创建其他的线程, 看门狗不会饿死的,所以app_main可以直接结束,这就是事件驱动。