esp32s3中ap与sta模式的wps配对问题

无线路由器中的WPS是Wi-Fi Protected Setup的简称,中文翻译为Wi-Fi安全防护设置,它是由Wi-Fi安全联盟推出的一种无线加密认证方式。主要是为了简化无线局域网的安装及安全性能配置工作,通过这种设置,让无线连接更加方便和安全。省去了输入繁琐密码的过程,也增加了wifi的安全性,但现在手机只有少部分还保留了这个功能。

在嵌入式wifi系统中比如esp32无线配对还是非常实用,匹配时需要一对一触发,否则相互干扰。

esp32作为ap端:

1.需要在menuconfig中添加组件支持,

component config -->wifi-->add wps register support in softap mode

2.wps配置和功能

#ifndef __BOARD_AP_WPS_H__
#define __BOARD_AP_WPS_H__

#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_mac.h"
#include "esp_log.h"
#include "esp_wps.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include <string.h>

/**
 * #ifndef os_memcpy
 * #define os_memcpy(d, s, n) memcpy((d), (s), (n))
 * #endif
 * 由此可见是一回事
 * */
#include <os.h>




/*set wps mode via project configuration */
#define WPS_MODE WPS_TYPE_PBC

//PBC方式使用默认的PIN"00000000",改变他和常规的差异化,只适合自己的设备配对
#define WPS_PIN_REDEFINE  "12345678"

static esp_wps_config_t ap_config = WPS_CONFIG_INIT_DEFAULT(WPS_MODE);

static bool is_wps_rg_status = false;



static inline void ap_wps_start(void)
{

	os_memcpy((void *)ap_config.pin, WPS_PIN_REDEFINE, 8);

	ESP_ERROR_CHECK(esp_wifi_ap_wps_enable(&ap_config));

	if (ap_config.wps_type == WPS_TYPE_PBC) {
		//ESP_LOGI(TAG, "Staring WPS registrar in PBC mode");
	} else {
		//ESP_LOGI(TAG, "Staring WPS registrar with random generated pin");
	}

	is_wps_rg_status = false;

	ESP_ERROR_CHECK(esp_wifi_ap_wps_start(NULL));

}


static inline void ap_wps_restart(void)
{

	os_memcpy((void *)ap_config.pin, WPS_PIN_REDEFINE, 8);

	ESP_ERROR_CHECK(esp_wifi_ap_wps_disable());
	ESP_ERROR_CHECK(esp_wifi_ap_wps_enable(&ap_config));

	is_wps_rg_status = false;

	ESP_ERROR_CHECK(esp_wifi_ap_wps_start(NULL));

}


static inline void ap_wps_stop(void)
{

	ESP_ERROR_CHECK(esp_wifi_ap_wps_disable());

}

static inline void ap_wps_set_rg_status(bool status)
{
	is_wps_rg_status = status;
}


static inline bool ap_wps_get_rg_status(void)
{
	return is_wps_rg_status;
}


#endif

3.板上配置一个按键用来监听配对触发

#ifndef __BOARD_GPIO_IN_H__
#define __BOARD_GPIO_IN_H__


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"




//复用BOOT脚作为wps key触发引脚,这个脚默认是没有接的,悬空状态,那就将其配置为内部上拉,下降沿触发
#define GPIO_INPUT_IO  (0)
#define GPIO_INPUT_PIN_SEL  (1ULL<<GPIO_INPUT_IO)//((1ULL<<GPIO_INPUT_IO_0) | (1ULL<<GPIO_INPUT_IO_1))


#define ESP_INTR_FLAG_DEFAULT (0)

static QueueHandle_t gpio_evt_queue = NULL;


//需要这种事件传递的形式
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    uint32_t gpio_num = (uint32_t) arg;

    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}


static void gpio_task_example(void* arg)
{
    #define WPS_TRIGGER_TIME (2000)
    #define WPS_LOOP_TIME    (100)
    #define WPS_TIMEOUT      (20 * 1000)

    uint32_t io_num;

    for(;;) {

        if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
            //printf("GPIO[%"PRIu32"] intr, val: %d\n", io_num, gpio_get_level(io_num));

        	int loop_cnt = 0;
        	while(loop_cnt < (WPS_TRIGGER_TIME / WPS_LOOP_TIME))
        	{
        		//按键松开了就重新开始监听
        		if(gpio_get_level(io_num))
        		{
        			break;
        		}

                loop_cnt++;

        		vTaskDelay(WPS_LOOP_TIME / portTICK_PERIOD_MS);
        	}


        	if(loop_cnt < (WPS_TRIGGER_TIME / WPS_LOOP_TIME))
        	{
        		printf("wps key abort!\n");
        		continue;
        	}

            printf("wps key pressed!\n");

            ap_wps_restart();

            /**
             * 尽管WIFI_EVENT_AP_WPS_RG_TIMEOUT时间比较长,不过他是
             * 超时以后不断循环ap_wps_restart,所以默认上超时是无限期的,
             * 这时候就可以人为的使用一个延时来主动停止wps即可,同时也避免了
             * wps按键的重复触发问题.
             * */
            loop_cnt = 0;
            while(loop_cnt < (WPS_TIMEOUT / WPS_LOOP_TIME))
            {
            	if(ap_wps_get_rg_status())
            	{
            		break;
            	}

            	loop_cnt++;
            	vTaskDelay(WPS_LOOP_TIME / portTICK_PERIOD_MS);
            }

            ap_wps_stop();
            printf("wps stop!\n");

        	//清空队列防止干扰
            xQueueReset(gpio_evt_queue);

        }
    }
}




static inline void gpio_in_init(void)
{
     //interrupt of rising edge
	gpio_config_t io_conf = {};

	io_conf.intr_type = GPIO_INTR_NEGEDGE;
    //bit mask of the pins, use GPIO4/5 here
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    //set as input mode
    io_conf.mode = GPIO_MODE_INPUT;
    //enable pull-up mode
    io_conf.pull_up_en = 1;//下降沿触发当然默认拉高

    io_conf.pull_down_en = 0;//上升沿当然先拉低默认

    gpio_config(&io_conf);

    //change gpio interrupt type for one pin
    //gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE);

    //create a queue to handle gpio event from isr
    //不需要发送10次,发送1次就好
    gpio_evt_queue = xQueueCreate(1/*10*/, sizeof(uint32_t));
    //start gpio task
    xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, GPIO_KEY_TASK_PRIORITY, NULL);


    //install gpio isr service
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_INPUT_IO, gpio_isr_handler, (void*) GPIO_INPUT_IO);

}



static inline void test_gpio_in(void)
{
	gpio_in_init();

	gpio_out_init();

	gpio_out_value(0);
}



#endif
/ / 

4.wifi事件的监听和处理


static void wifi_event_handler(void* arg, esp_event_base_t event_base,
		int32_t event_id, void* event_data)
{
	switch (event_id) {
	case WIFI_EVENT_AP_START:
		ESP_LOGI(TAG, "WIFI_EVENT_AP_START");
		break;
	case WIFI_EVENT_AP_STADISCONNECTED:
		{
			ESP_LOGI(TAG, "WIFI_EVENT_AP_STADISCONNECTED");
			wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
			ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
					MAC2STR(event->mac), event->aid);
		}
		break;
	case WIFI_EVENT_AP_STACONNECTED:
		{
			ESP_LOGI(TAG, "WIFI_EVENT_AP_STACONNECTED");
			wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
			ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
					MAC2STR(event->mac), event->aid);
		}
		break;
	case WIFI_EVENT_AP_WPS_RG_SUCCESS:
		{
			ESP_LOGI(TAG, "WIFI_EVENT_AP_WPS_RG_SUCCESS");
			wifi_event_ap_wps_rg_success_t *evt = (wifi_event_ap_wps_rg_success_t *)event_data;
			ESP_LOGI(TAG, "station "MACSTR" WPS successful",
					MAC2STR(evt->peer_macaddr));

			ap_wps_set_rg_status(true);
		}
		break;
	case WIFI_EVENT_AP_WPS_RG_FAILED:
		{
			ESP_LOGI(TAG, "WIFI_EVENT_AP_WPS_RG_FAILED");
			wifi_event_ap_wps_rg_fail_reason_t *evt = (wifi_event_ap_wps_rg_fail_reason_t *)event_data;
			ESP_LOGI(TAG, "station "MACSTR" WPS failed, reason=%d",
						MAC2STR(evt->peer_macaddr), evt->reason);
		    ap_wps_restart();
		}
		break;
	case WIFI_EVENT_AP_WPS_RG_TIMEOUT:
		{
			ESP_LOGI(TAG, "WIFI_EVENT_AP_WPS_RG_TIMEOUT");
			ap_wps_restart();
		}
		break;
	default:
		break;
	}
}






static void wifi_init_softap(void)
{

    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_t*mynetif = esp_netif_create_default_wifi_ap();


    esp_netif_ip_info_t ipInfo;

    IP4_ADDR(&ipInfo.ip, 192,168,28,1);
	IP4_ADDR(&ipInfo.gw, 192,168,28,1);
	IP4_ADDR(&ipInfo.netmask, 255,255,255,0);

	esp_netif_dhcps_stop(mynetif);
	esp_netif_set_ip_info(mynetif, &ipInfo);
	esp_netif_dhcps_start(mynetif);


    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        NULL));


    //这个是默认mac base,比如softap是+1等等.
    //本地无线网卡地址
    uint8_t local_mac[6];
    //esp_efuse_mac_get_default(mac);
    esp_read_mac(local_mac,ESP_MAC_WIFI_SOFTAP);

    //for(int i=0;i<sizeof(mac);i++)
    //    printf("%2X ",mac[i]);
    //printf("\n");
    uint8_t buf[32] = {0};

    sprintf((char*)buf,"%s-%02X%02X%02X",EXAMPLE_ESP_WIFI_SSID_PREFIX,local_mac[3],local_mac[4],local_mac[5]);

    wifi_config_t wifi_config = {
        .ap = {
            .ssid = EXAMPLE_ESP_WIFI_SSID_PREFIX,//此处只能常量
            .ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID_PREFIX),
            .channel = EXAMPLE_ESP_WIFI_CHANNEL,
            .password = EXAMPLE_ESP_WIFI_PASS,
            .max_connection = EXAMPLE_MAX_STA_CONN,
#ifdef CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT
            .authmode = WIFI_AUTH_WPA3_PSK,
            .sae_pwe_h2e = WPA3_SAE_PWE_BOTH,
#else /* CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT */
            .authmode = WIFI_AUTH_WPA2_PSK,
#endif
            .pmf_cfg = {
                    .required = true,
            },
        },
    };
//wifi_config.ap.pairwise_cipher
    wifi_config.ap.ssid_len = strlen((char*)buf);
    memcpy(wifi_config.ap.ssid,buf,wifi_config.ap.ssid_len);


    wifi_config.ap.channel = sta_wifi_get_best_channel();


    if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {
        wifi_config.ap.authmode = WIFI_AUTH_OPEN;
    }

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));

    ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));

    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d",
             buf, EXAMPLE_ESP_WIFI_PASS, wifi_config.ap.channel);

}

esp32作为sta端:

1.wps配置和功能

#ifndef __BOARD_STA_WPS_H__
#define __BOARD_STA_WPS_H__


#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "esp_wps.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include <string.h>



#define WPS_PIN_REDEFINE  "12345678"

static esp_wps_config_t sta_config = WPS_CONFIG_INIT_DEFAULT(WPS_TYPE_PBC);

static bool is_wps_er_status = false;


static inline void sta_wps_start(void)
{
	//暂停wifi连接
	esp_wifi_disconnect();

	memcpy(sta_config.pin, WPS_PIN_REDEFINE, 8);

    ESP_ERROR_CHECK(esp_wifi_wps_enable(&sta_config));

    is_wps_er_status = false;

    ESP_ERROR_CHECK(esp_wifi_wps_start(0));

}


static inline void sta_wps_restart(void)
{
	//暂停wifi连接
	esp_wifi_disconnect();

	memcpy(sta_config.pin, WPS_PIN_REDEFINE, 8);

    ESP_ERROR_CHECK(esp_wifi_wps_disable());
    ESP_ERROR_CHECK(esp_wifi_wps_enable(&sta_config));

    is_wps_er_status = false;

    ESP_ERROR_CHECK(esp_wifi_wps_start(0));

}


static inline void sta_wps_stop(void)
{

	ESP_ERROR_CHECK(esp_wifi_wps_disable());

	//恢复wifi连接
    esp_wifi_connect();

}


static inline void sta_wps_set_er_status(bool status)
{
	is_wps_er_status = status;
}


static inline bool sta_wps_get_er_status(void)
{
	return is_wps_er_status;
}


#endif
/

2.板上配置一个按键用来监听配对触发

#ifndef __BOARD_GPIO_IN_H__
#define __BOARD_GPIO_IN_H__


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"




//暂时假设服用BOOT脚作为wps key触发引脚,这个脚默认是没有接的,悬空状态,那就将其配置为内部上拉,下降沿触发
#define GPIO_INPUT_IO  (0)
#define GPIO_INPUT_PIN_SEL  (1ULL<<GPIO_INPUT_IO)//((1ULL<<GPIO_INPUT_IO_0) | (1ULL<<GPIO_INPUT_IO_1))


#define ESP_INTR_FLAG_DEFAULT (0)

extern int global_wifi_connect;

static QueueHandle_t gpio_evt_queue = NULL;

static bool is_wps_key_pressed = false;



//需要这种事件传递的形式
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    uint32_t gpio_num = (uint32_t) arg;

    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}


static void gpio_task_example(void* arg)
{
    #define WPS_TRIGGER_TIME (2000)
    #define WPS_LOOP_TIME    (100)
    #define WPS_TIMEOUT      (20 * 1000)

    uint32_t io_num;

    for(;;) {

        if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
            //printf("GPIO[%"PRIu32"] intr, val: %d\n", io_num, gpio_get_level(io_num));

        	int loop_cnt = 0;
        	while(loop_cnt < (WPS_TRIGGER_TIME / WPS_LOOP_TIME))
        	{
        		//按键松开了就重新开始监听
        		if(gpio_get_level(io_num))
        		{
        			break;
        		}

                loop_cnt++;

        		vTaskDelay(WPS_LOOP_TIME / portTICK_PERIOD_MS);
        	}


        	if(loop_cnt < (WPS_TRIGGER_TIME / WPS_LOOP_TIME))
        	{
        		printf("sta wps key abort!\n");
        		continue;
        	}

            printf("sta wps key pressed!\n");


            is_wps_key_pressed = true;

            /**在wifi已经连接上的情况下,先断开wifi连接,再终止wifi重连,再启动wps
             * */
            if(global_wifi_connect > 0)
            {
            	//由于is_wps_key_pressed = true,WIFI_EVENT_STA_DISCONNECTED中wifi不能改变状态
            	//所以要手动更改.
            	global_wifi_connect = 0;
                esp_wifi_disconnect();
            	vTaskDelay(100 / portTICK_PERIOD_MS);
            }


            /**
             * W (20543) wifi:sta_scan: STA is connecting, scan are not allowed!
             * 看来wifi在连接的时候是不能进行wps配对的.
             * */
            sta_wps_restart();

            /**
             * 尽管WIFI_EVENT_AP_WPS_RG_TIMEOUT时间比较长,不过他是
             * 超时以后不断循环ap_wps_restart,所以默认上超时是无限期的,
             * 这时候就可以人为的使用一个延时来主动停止wps即可,同时也避免了
             * wps按键的重复触发问题.
             * */
            loop_cnt = 0;
            while(loop_cnt < (WPS_TIMEOUT / WPS_LOOP_TIME))
            {
            	if(sta_wps_get_er_status())
            	{
            		break;
            	}

            	loop_cnt++;
            	vTaskDelay(WPS_LOOP_TIME / portTICK_PERIOD_MS);
            }

            if(!sta_wps_get_er_status())
            {
                sta_wps_stop();
                printf("sta wps stop!\n");
            }

            is_wps_key_pressed = false;

        	//清空队列防止干扰
            xQueueReset(gpio_evt_queue);

        }
    }
}





static inline void gpio_in_init(void)
{
     //interrupt of rising edge
	gpio_config_t io_conf = {};

	io_conf.intr_type = GPIO_INTR_NEGEDGE;
    //bit mask of the pins, use GPIO4/5 here
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    //set as input mode
    io_conf.mode = GPIO_MODE_INPUT;
    //enable pull-up mode
    io_conf.pull_up_en = 1;//下降沿触发当然默认拉高

    io_conf.pull_down_en = 0;//上升沿当然先拉低默认

    gpio_config(&io_conf);

    //change gpio interrupt type for one pin
    //gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE);

    //create a queue to handle gpio event from isr
    //不需要发送10次,发送1次就好
    gpio_evt_queue = xQueueCreate(1/*10*/, sizeof(uint32_t));
    //start gpio task
    xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, GPIO_KEY_TASK_PRIORITY, NULL);


    //install gpio isr service
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_INPUT_IO, gpio_isr_handler, (void*) GPIO_INPUT_IO);

}



static inline bool board_gpio_get_wps_key_status(void)
{
	return is_wps_key_pressed;
}



static inline void test_gpio_in(void)
{
	gpio_in_init();

	gpio_out_init();

	gpio_out_value(0);
}



#endif
/ / 

3.wifi事件的监听和处理


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)
    {
    	global_wifi_connect = -1;

        esp_wifi_connect();

    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
    {
    	if(!board_gpio_get_wps_key_status())
    	{
			/**
			 * 这种基于事件的重连方式不错
			 * */
			if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {

				global_wifi_connect = 0;

				esp_wifi_connect();
				s_retry_num++;
				ESP_LOGI(TAG, "retry to connect to the AP");


			} else {

				global_wifi_connect = -1;

				xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);

			}

			ESP_LOGI(TAG,"connect to the AP fail");

    	}
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED)
    {
    	//此处获取bssid,wifi ap's wlan mac
    	wifi_event_sta_connected_t* event = (wifi_event_sta_connected_t*) event_data;
        //printf("get ap's bssid:");
        //print0x(event->bssid,sizeof(event->bssid));

        uint16_t chs = Crc_Calculate(event->bssid, sizeof(event->bssid));
        set_send_mavlink_protocol_crc(chs >> 8,chs & 0xFF);

        //printf("ap's mac chs=%04X\n",chs);

        char str[32] = {0};
        size_t str_len = sizeof(str);
        esp_err_t err;

        err = board_read_string("wifi_name", str, &str_len);
        if(err == ESP_OK && str_len > 0)
        {
        	str[str_len] = 0;

        	//和已经保存的ssid不一致才需要重新保存
            if(strcmp((char*)event->ssid,(char*)str))
            {
            	board_write_string("wifi_name", (char*)event->ssid);

            	printf("wifi name differ,need save!\n");
            }
        }
        else
        {
        	//没有保存ssid就立即保存
        	if(ESP_ERR_NVS_NOT_FOUND == err)
        	{
        		board_write_string("wifi_name", (char*)event->ssid);

        		printf("wifi name not found,need save!\n");
        	}
        }

    }
    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;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);

        global_wifi_connect = 1;

    }



	//wps连接
    switch (event_id) {

        case WIFI_EVENT_STA_WPS_ER_SUCCESS:
            ESP_LOGI(TAG, "WIFI_EVENT_STA_WPS_ER_SUCCESS");
            {
                wifi_event_sta_wps_er_success_t *evt =
                    (wifi_event_sta_wps_er_success_t *)event_data;
                int i;

                if (evt) {
                    s_ap_creds_num = evt->ap_cred_cnt;
                    for (i = 0; i < s_ap_creds_num; i++) {
                        memcpy(wps_ap_creds[i].sta.ssid, evt->ap_cred[i].ssid,
                               sizeof(evt->ap_cred[i].ssid));
                        memcpy(wps_ap_creds[i].sta.password, evt->ap_cred[i].passphrase,
                               sizeof(evt->ap_cred[i].passphrase));
                    }
                    /* If multiple AP credentials are received from WPS, connect with first one */
                    ESP_LOGI(TAG, "Connecting to SSID: %s, Passphrase: %s",
                             wps_ap_creds[0].sta.ssid, wps_ap_creds[0].sta.password);
                    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wps_ap_creds[0]) );
                }


                //此处已经说明只有一个ap wps则没有event data,直接连接即可
                /*
                 * If only one AP credential is received from WPS, there will be no event data and
                 * esp_wifi_set_config() is already called by WPS modules for backward compatibility
                 * with legacy apps. So directly attempt connection here.
                 */
                ESP_ERROR_CHECK(esp_wifi_wps_disable());

                sta_wps_set_er_status(true);

                esp_wifi_connect();

            }
            break;
        case WIFI_EVENT_STA_WPS_ER_FAILED:

            ESP_LOGI(TAG, "WIFI_EVENT_STA_WPS_ER_FAILED");
            sta_wps_restart();

            break;
        case WIFI_EVENT_STA_WPS_ER_TIMEOUT:
            ESP_LOGI(TAG, "WIFI_EVENT_STA_WPS_ER_TIMEOUT");
            sta_wps_restart();

            break;
        case WIFI_EVENT_STA_WPS_ER_PIN:

            ESP_LOGI(TAG, "WIFI_EVENT_STA_WPS_ER_PIN");
            /* display the PIN code */
            wifi_event_sta_wps_er_pin_t* event = (wifi_event_sta_wps_er_pin_t*) event_data;
            printf("display pincode=%s\n",(char*)event->pin_code);

            break;
        default:
            break;
    }
}




void wifi_init_sta(void)
{
    s_wifi_event_group = xEventGroupCreate();

    ESP_ERROR_CHECK(esp_netif_init());

    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;

    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    wifi_config_t wifi_config = {
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS,
            /* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (pasword len => 8).
             * If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value
             * to WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK and set the password with length and format matching to
             * WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK standards.
             */
            .threshold.authmode = WIFI_AUTH_WPA3_PSK,
            .sae_pwe_h2e = WPA3_SAE_PWE_BOTH,
            .sae_h2e_identifier = "",
        },
    };



    /**
     * 获取已经保存的wifi&password
     * */
    char str[32] = {0};
    size_t str_len = sizeof(str);
    esp_err_t err;

    err = board_read_string("wifi_name", str, &str_len);
    if(err == ESP_OK && str_len > 0)
    {
    	str[str_len] = 0;
    	strcpy((char*)wifi_config.sta.ssid,str);

    	printf("get saved wifi_name=%s\n",str);

        memset(str,0,sizeof(str));
        str_len = sizeof(str);
    }


    err = board_read_string("wifi_passwd", str, &str_len);
    if(err == ESP_OK && str_len > 0)
    {
    	str[str_len] = 0;
    	strcpy((char*)wifi_config.sta.password,str);

    	printf("get saved wifi_passwd=%s\n",str);
    }



    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );

    //禁止modem休眠,降低延迟
    ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));

    ESP_ERROR_CHECK(esp_wifi_start() );

    ESP_LOGI(TAG, "wifi_init_sta finished.");

    //不需要堵塞等候连接!不过没有连接堵塞在这里也不搓,也没必要后续初始化和任务启动,只需要wps已经启动即可
    /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
     * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
            pdFALSE,
            pdFALSE,
            portMAX_DELAY);

    /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
     * happened. */
    if (bits & WIFI_CONNECTED_BIT) {
//        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
//                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                 wifi_config.sta.ssid, wifi_config.sta.password);
    } else if (bits & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }

}

最后两块板子在2秒时间内依次按下配对按键,即可建立无线配对,sta端保存ap端wifi信息用于下次启动直连,方便快捷。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值