feat(wifi) save credential on successful connection and auto connect to it
This commit is contained in:
		
							parent
							
								
									a4d65c367d
								
							
						
					
					
						commit
						6fdfa76a14
					
				| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
file(GLOB SOURCES *.c)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
idf_component_register(
 | 
			
		||||
        SRCS ${SOURCES}
 | 
			
		||||
        INCLUDE_DIRS "."
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,96 @@
 | 
			
		|||
/*
 | 
			
		||||
 * SPDX-FileCopyrightText: Copyright (c) 2009, Jouni Malinen <j@w1.fi>
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef LIST_H_GUARD
 | 
			
		||||
#define LIST_H_GUARD
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct dl_list - Doubly-linked list
 | 
			
		||||
 */
 | 
			
		||||
struct dl_list {
 | 
			
		||||
	struct dl_list *next;
 | 
			
		||||
	struct dl_list *prev;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline void dl_list_init(struct dl_list *list)
 | 
			
		||||
{
 | 
			
		||||
	list->next = list;
 | 
			
		||||
	list->prev = list;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void dl_list_add(struct dl_list *list, struct dl_list *item)
 | 
			
		||||
{
 | 
			
		||||
	item->next = list->next;
 | 
			
		||||
	item->prev = list;
 | 
			
		||||
	list->next->prev = item;
 | 
			
		||||
	list->next = item;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void dl_list_add_tail(struct dl_list *list, struct dl_list *item)
 | 
			
		||||
{
 | 
			
		||||
	dl_list_add(list->prev, item);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void dl_list_del(struct dl_list *item)
 | 
			
		||||
{
 | 
			
		||||
	item->next->prev = item->prev;
 | 
			
		||||
	item->prev->next = item->next;
 | 
			
		||||
	item->next = NULL;
 | 
			
		||||
	item->prev = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int dl_list_empty(struct dl_list *list)
 | 
			
		||||
{
 | 
			
		||||
	return list->next == list;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline unsigned int dl_list_len(struct dl_list *list)
 | 
			
		||||
{
 | 
			
		||||
	struct dl_list *item;
 | 
			
		||||
	int count = 0;
 | 
			
		||||
	for (item = list->next; item != list; item = item->next)
 | 
			
		||||
		count++;
 | 
			
		||||
	return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef offsetof
 | 
			
		||||
#define offsetof(type, member) ((long) &((type *) 0)->member)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define dl_list_entry(item, type, member) \
 | 
			
		||||
	((type *) ((char *) item - offsetof(type, member)))
 | 
			
		||||
 | 
			
		||||
#define dl_list_first(list, type, member) \
 | 
			
		||||
	(dl_list_empty((list)) ? NULL : \
 | 
			
		||||
	 dl_list_entry((list)->next, type, member))
 | 
			
		||||
 | 
			
		||||
#define dl_list_last(list, type, member) \
 | 
			
		||||
	(dl_list_empty((list)) ? NULL : \
 | 
			
		||||
	 dl_list_entry((list)->prev, type, member))
 | 
			
		||||
 | 
			
		||||
#define dl_list_for_each(item, list, type, member) \
 | 
			
		||||
	for (item = dl_list_entry((list)->next, type, member); \
 | 
			
		||||
	     &item->member != (list); \
 | 
			
		||||
	     item = dl_list_entry(item->member.next, type, member))
 | 
			
		||||
 | 
			
		||||
#define dl_list_for_each_safe(item, n, list, type, member) \
 | 
			
		||||
	for (item = dl_list_entry((list)->next, type, member), \
 | 
			
		||||
		     n = dl_list_entry(item->member.next, type, member); \
 | 
			
		||||
	     &item->member != (list); \
 | 
			
		||||
	     item = n, n = dl_list_entry(n->member.next, type, member))
 | 
			
		||||
 | 
			
		||||
#define dl_list_for_each_reverse(item, list, type, member) \
 | 
			
		||||
	for (item = dl_list_entry((list)->prev, type, member); \
 | 
			
		||||
	     &item->member != (list); \
 | 
			
		||||
	     item = dl_list_entry(item->member.prev, type, member))
 | 
			
		||||
 | 
			
		||||
#define DEFINE_DL_LIST(name) \
 | 
			
		||||
	struct dl_list name = { &(name), &(name) }
 | 
			
		||||
 | 
			
		||||
#endif //LIST_H_GUARD
 | 
			
		||||
| 
						 | 
				
			
			@ -26,13 +26,13 @@ _Noreturn void req_long_task(void *arg)
 | 
			
		|||
		if (unlikely(xQueueReceive(long_run_queue, &req, portMAX_DELAY) != pdTRUE)) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		int status = req->module.helper_cb(req->module.arg);
 | 
			
		||||
		req->status = req->module.helper_cb(req->module.arg);
 | 
			
		||||
 | 
			
		||||
		/* if send out queue is busy, set status and let the cb to cancel send out
 | 
			
		||||
		 * */
 | 
			
		||||
		if (req_queue_push_send_out(req, pdMS_TO_TICKS(20)) != 0) {
 | 
			
		||||
			status = -1;
 | 
			
		||||
			req->send_out.cb(req->send_out.arg, status);
 | 
			
		||||
			req->status = -1;
 | 
			
		||||
			req->send_out.cb(req->send_out.arg, req->status);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +42,7 @@ _Noreturn void req_send_out_task(void *arg)
 | 
			
		|||
	req_task_cb_t *req;
 | 
			
		||||
	while (1) {
 | 
			
		||||
		if (likely(xQueueReceive(send_out_queue, &req, portMAX_DELAY))) {
 | 
			
		||||
			req->send_out.cb(req->send_out.arg, 0);
 | 
			
		||||
			req->send_out.cb(req->send_out.arg, req->status);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,7 @@ typedef struct req_module_cb_t {
 | 
			
		|||
typedef struct req_task_cb_t {
 | 
			
		||||
	req_module_cb_t module;
 | 
			
		||||
	req_send_out_cb_t send_out;
 | 
			
		||||
	int status;
 | 
			
		||||
} req_task_cb_t;
 | 
			
		||||
 | 
			
		||||
int request_runner_init();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ typedef struct post_request_t {
 | 
			
		|||
} post_request_t;
 | 
			
		||||
 | 
			
		||||
static void async_send_out_cb(void *arg, int module_status);
 | 
			
		||||
static int uri_api_send_out(httpd_req_t *req, post_request_t *post_req);
 | 
			
		||||
static int uri_api_send_out(httpd_req_t *req, post_request_t *post_req, int err);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static esp_err_t api_post_handler(httpd_req_t *req)
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +87,7 @@ static esp_err_t api_post_handler(httpd_req_t *req)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	/* api function returns something, send back to http client */
 | 
			
		||||
	err = uri_api_send_out(req, post_req);
 | 
			
		||||
	err = uri_api_send_out(req, post_req, 0);
 | 
			
		||||
	goto put_buf;
 | 
			
		||||
 | 
			
		||||
end:
 | 
			
		||||
| 
						 | 
				
			
			@ -101,19 +101,21 @@ put_buf:
 | 
			
		|||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int uri_api_send_out(httpd_req_t *req, post_request_t *post_req)
 | 
			
		||||
int uri_api_send_out(httpd_req_t *req, post_request_t *post_req, int err)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	char *buf;
 | 
			
		||||
	uint32_t buf_len;
 | 
			
		||||
 | 
			
		||||
	buf = post_req->buf;
 | 
			
		||||
	buf_len = static_buffer_get_buf_size() - sizeof(post_request_t);
 | 
			
		||||
 | 
			
		||||
	httpd_resp_set_type(req, HTTPD_TYPE_JSON);
 | 
			
		||||
	err = !cJSON_PrintPreallocated(post_req->json.out, buf, buf_len - 5, 0);
 | 
			
		||||
	cJSON_Delete(post_req->json.out);
 | 
			
		||||
	cJSON_Delete(post_req->json.in);
 | 
			
		||||
	if (post_req->json.out) {
 | 
			
		||||
		ESP_LOGI(TAG, "json out ok");
 | 
			
		||||
		httpd_resp_set_type(req, HTTPD_TYPE_JSON);
 | 
			
		||||
		err = !cJSON_PrintPreallocated(post_req->json.out, buf, buf_len - 5, 0);
 | 
			
		||||
		cJSON_Delete(post_req->json.out);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (unlikely(err)) {
 | 
			
		||||
		httpd_resp_set_status(req, HTTPD_500);
 | 
			
		||||
		return httpd_resp_send(req, NULL, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -126,11 +128,13 @@ void async_send_out_cb(void *arg, int module_status)
 | 
			
		|||
{
 | 
			
		||||
	post_request_t *req = arg;
 | 
			
		||||
	if (module_status != API_JSON_OK) {
 | 
			
		||||
		httpd_sess_trigger_close(req->req_out->handle,
 | 
			
		||||
		                         httpd_req_to_sockfd(req->req_out->handle));
 | 
			
		||||
		/* BUG: httpd_req_to_sockfd cause crash, fd not closed for the moment
 | 
			
		||||
		 * issue is opened on esp-idf github */
 | 
			
		||||
//		httpd_sess_trigger_close(req->req_out->handle,
 | 
			
		||||
//		                         httpd_req_to_sockfd(req->req_out->handle));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uri_api_send_out(req->req_out, req);
 | 
			
		||||
	uri_api_send_out(req->req_out, req, module_status);
 | 
			
		||||
 | 
			
		||||
	/* clean resources */
 | 
			
		||||
	httpd_req_async_handler_complete(req->req_out);
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +154,6 @@ static const httpd_uri_t uri_api = {
 | 
			
		|||
 | 
			
		||||
static int URI_API_INIT(const httpd_uri_t **uri_conf) {
 | 
			
		||||
	*uri_conf = &uri_api;
 | 
			
		||||
	api_json_router_init();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -136,13 +136,11 @@ static const httpd_uri_t uri_api = {
 | 
			
		|||
	.user_ctx  = NULL,
 | 
			
		||||
	.is_websocket = true,
 | 
			
		||||
	.supported_subprotocol = NULL,
 | 
			
		||||
	/* in esp-idf v5.2.0, set to false cause infinite queue_work fail on wifi disconnect when at least 1 ws client */
 | 
			
		||||
	.handle_ws_control_frames = true,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int WS_REQ_INIT(const httpd_uri_t **uri_conf) {
 | 
			
		||||
	*uri_conf = &uri_api;
 | 
			
		||||
	api_json_router_init();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,13 +4,14 @@ file(GLOB SOURCES
 | 
			
		|||
        wifi_api_json.c
 | 
			
		||||
        wifi_api.c
 | 
			
		||||
        wifi_json_utils.c
 | 
			
		||||
        wifi_storage.c
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
idf_component_register(
 | 
			
		||||
        SRCS ${SOURCES}
 | 
			
		||||
        INCLUDE_DIRS "."
 | 
			
		||||
        PRIV_REQUIRES mdns esp_wifi esp_event api_router
 | 
			
		||||
        PRIV_REQUIRES mdns esp_wifi esp_event api_router wt_storage
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,9 +27,6 @@ static int rssi_comp(const void *a, const void *b)
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief blocking function
 | 
			
		||||
 * @param number
 | 
			
		||||
 * @param ap_info
 | 
			
		||||
 * @return
 | 
			
		||||
 */
 | 
			
		||||
int wifi_api_get_scan_list(uint16_t *number, wifi_api_ap_info_t *ap_info)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -76,13 +73,12 @@ static void wifi_manager_scan_done(uint16_t ap_found, wifi_ap_record_t *records,
 | 
			
		|||
	scan_done_cb(ap_found, ap_info, arg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int wifi_api_trigger_scan(uint16_t *max_ap_count, wifi_api_scan_done_cb cb, void *cb_arg)
 | 
			
		||||
int wifi_api_connect(const char *ssid, const char *password)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	err = wifi_manager_trigger_scan(wifi_manager_scan_done, cb_arg);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
	scan_done_cb = cb;
 | 
			
		||||
	return 0;
 | 
			
		||||
	return wifi_manager_connect(ssid, password);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int wifi_api_disconnect(void)
 | 
			
		||||
{
 | 
			
		||||
	return wifi_manager_disconnect();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,5 +20,9 @@ int wifi_api_trigger_scan(uint16_t *max_ap_count, wifi_api_scan_done_cb cb, void
 | 
			
		|||
 | 
			
		||||
int wifi_api_get_scan_list(uint16_t *number, wifi_api_ap_info_t *ap_info);
 | 
			
		||||
 | 
			
		||||
int wifi_api_connect(const char *ssid, const char *password);
 | 
			
		||||
 | 
			
		||||
int wifi_api_disconnect(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif //WIFI_API_H_GUARD
 | 
			
		||||
| 
						 | 
				
			
			@ -10,34 +10,44 @@ static int wifi_api_json_get_ap_info(api_json_req_t *req);
 | 
			
		|||
 | 
			
		||||
static int wifi_api_json_get_scan(api_json_req_t *req);
 | 
			
		||||
 | 
			
		||||
static int on_async_call(void *arg)
 | 
			
		||||
static int wifi_api_json_connect(api_json_req_t *req);
 | 
			
		||||
 | 
			
		||||
static int wifi_api_json_disconnect(api_json_req_t *req);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int async_helper_cb(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	api_json_module_req_t *req = arg;
 | 
			
		||||
	return req->func(req->arg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int set_async(api_json_req_t *req, api_json_module_async_t *async, int (*func)(api_json_req_t *))
 | 
			
		||||
{
 | 
			
		||||
	async->module.func = func;
 | 
			
		||||
	async->module.arg = req;
 | 
			
		||||
	async->req_task.module.helper_cb = async_helper_cb;
 | 
			
		||||
	async->req_task.module.arg = &async->module;
 | 
			
		||||
	return API_JSON_ASYNC;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int on_json_req(uint16_t cmd, api_json_req_t *req, api_json_module_async_t *async)
 | 
			
		||||
{
 | 
			
		||||
	wifi_api_json_cmd_t wifi_cmd = cmd;
 | 
			
		||||
	switch (wifi_cmd) {
 | 
			
		||||
	case WIFI_API_JSON_GET_AP_INFO:
 | 
			
		||||
		return wifi_api_json_get_ap_info(req);
 | 
			
		||||
	case WIFI_API_JSON_CONNECT:
 | 
			
		||||
 | 
			
		||||
		break;
 | 
			
		||||
	case WIFI_API_JSON_GET_SCAN:
 | 
			
		||||
		async->module.func = wifi_api_json_get_scan;
 | 
			
		||||
		async->module.arg = req;
 | 
			
		||||
		async->req_task.module.helper_cb = on_async_call;
 | 
			
		||||
		async->req_task.module.arg = &async->module;
 | 
			
		||||
		return API_JSON_ASYNC;
 | 
			
		||||
	case UNKNOWN:
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	case WIFI_API_JSON_GET_AP_INFO:
 | 
			
		||||
		return wifi_api_json_get_ap_info(req);
 | 
			
		||||
	case WIFI_API_JSON_CONNECT:
 | 
			
		||||
		return set_async(req, async, wifi_api_json_connect);
 | 
			
		||||
	case WIFI_API_JSON_GET_SCAN:
 | 
			
		||||
		return set_async(req, async, wifi_api_json_get_scan);
 | 
			
		||||
	case WIFI_API_JSON_DISCONNECT:
 | 
			
		||||
		return wifi_api_json_disconnect(req);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	printf("cmd %d\n", cmd);
 | 
			
		||||
 | 
			
		||||
	printf("cmd %d not executed\n", cmd);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -70,6 +80,26 @@ static int wifi_api_json_get_scan(api_json_req_t *req)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int wifi_api_json_connect(api_json_req_t *req)
 | 
			
		||||
{
 | 
			
		||||
	char *ssid;
 | 
			
		||||
	char *password;
 | 
			
		||||
 | 
			
		||||
	ssid = cJSON_GetStringValue(cJSON_GetObjectItem(req->in, "ssid"));
 | 
			
		||||
	password = cJSON_GetStringValue(cJSON_GetObjectItem(req->in, "password"));
 | 
			
		||||
	if (ssid == NULL || password == NULL) {
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	printf("trigger connect\n");
 | 
			
		||||
	return wifi_api_connect(ssid, password);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int wifi_api_json_disconnect(api_json_req_t *req)
 | 
			
		||||
{
 | 
			
		||||
	return wifi_api_disconnect();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ****
 | 
			
		||||
 *  register module
 | 
			
		||||
 * */
 | 
			
		||||
| 
						 | 
				
			
			@ -81,6 +111,6 @@ static int wifi_api_json_init(api_json_module_cfg_t *cfg)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
API_JSON_MODULE_REGISTER(0x90, wifi_api_json_init);
 | 
			
		||||
API_JSON_MODULE_REGISTER(0x90, wifi_api_json_init)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@ typedef enum wifi_api_json_cmd_t {
 | 
			
		|||
	WIFI_API_JSON_GET_AP_INFO,
 | 
			
		||||
	WIFI_API_JSON_CONNECT,
 | 
			
		||||
	WIFI_API_JSON_GET_SCAN,
 | 
			
		||||
	WIFI_API_JSON_DISCONNECT,
 | 
			
		||||
 | 
			
		||||
} wifi_api_json_cmd_t;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,42 +44,52 @@ void ip_event_handler(void *handler_arg __attribute__((unused)),
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct wifi_scan_ctx_t {
 | 
			
		||||
	wifi_ap_record_t *ap;
 | 
			
		||||
	wifi_event_scan_done_cb cb;
 | 
			
		||||
	uint16_t number;
 | 
			
		||||
} wifi_scan_ctx_t;
 | 
			
		||||
typedef struct wifi_event_ctx_t {
 | 
			
		||||
	/* WIFI scan */
 | 
			
		||||
	struct {
 | 
			
		||||
		wifi_ap_record_t *ap;
 | 
			
		||||
		wifi_event_scan_done_cb cb;
 | 
			
		||||
		uint16_t number;
 | 
			
		||||
	};
 | 
			
		||||
	/* WIFI connect */
 | 
			
		||||
	struct {
 | 
			
		||||
		wifi_event_connect_done_cb cb;
 | 
			
		||||
		void *arg;
 | 
			
		||||
		void (*disconn_handler)(void);
 | 
			
		||||
		uint8_t attempt;
 | 
			
		||||
	} conn;
 | 
			
		||||
	uint8_t is_connected;
 | 
			
		||||
} wifi_event_ctx_t;
 | 
			
		||||
 | 
			
		||||
static wifi_scan_ctx_t scan_ctx = {
 | 
			
		||||
static wifi_event_ctx_t event_ctx = {
 | 
			
		||||
	.ap = NULL,
 | 
			
		||||
	.is_connected = 0,
 | 
			
		||||
	.conn.disconn_handler = NULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void wifi_on_scan_done(wifi_event_sta_scan_done_t *event)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	if (!scan_ctx.cb || !scan_ctx.ap) {
 | 
			
		||||
		scan_ctx.number = 0;
 | 
			
		||||
	if (!event_ctx.cb || !event_ctx.ap) {
 | 
			
		||||
		event_ctx.number = 0;
 | 
			
		||||
	} else if (event->status == 1) {
 | 
			
		||||
		/* error */
 | 
			
		||||
		scan_ctx.number = 0;
 | 
			
		||||
		event_ctx.number = 0;
 | 
			
		||||
	} else if (event->number == 0) {
 | 
			
		||||
		/* no ap found on current channel */
 | 
			
		||||
		scan_ctx.number = 0;
 | 
			
		||||
		event_ctx.number = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = esp_wifi_scan_get_ap_records(&scan_ctx.number, scan_ctx.ap);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		esp_wifi_clear_ap_list();
 | 
			
		||||
	}
 | 
			
		||||
	esp_wifi_scan_get_ap_records(&event_ctx.number, event_ctx.ap);
 | 
			
		||||
	esp_wifi_clear_ap_list();
 | 
			
		||||
 | 
			
		||||
	int i;
 | 
			
		||||
	for (i = 0; i < scan_ctx.number; ++i) {
 | 
			
		||||
		if (scan_ctx.ap[i].rssi < -80)
 | 
			
		||||
	for (i = 0; i < event_ctx.number; ++i) {
 | 
			
		||||
		if (event_ctx.ap[i].rssi < -80)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scan_ctx.number = i;
 | 
			
		||||
	return scan_ctx.cb(scan_ctx.number, scan_ctx.ap);
 | 
			
		||||
	event_ctx.number = i;
 | 
			
		||||
	return event_ctx.cb(event_ctx.number, event_ctx.ap);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -108,12 +118,20 @@ int wifi_event_trigger_scan(uint8_t channel, wifi_event_scan_done_cb cb, uint16_
 | 
			
		|||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scan_ctx.cb = cb;
 | 
			
		||||
	scan_ctx.number = number;
 | 
			
		||||
	scan_ctx.ap = aps;
 | 
			
		||||
	event_ctx.cb = cb;
 | 
			
		||||
	event_ctx.number = number;
 | 
			
		||||
	event_ctx.ap = aps;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * WIFI EVENT
 | 
			
		||||
 * */
 | 
			
		||||
 | 
			
		||||
static void reconnect_after_disco();
 | 
			
		||||
 | 
			
		||||
void event_on_connected(wifi_event_sta_connected_t *event);
 | 
			
		||||
 | 
			
		||||
void wifi_event_handler(void *handler_arg __attribute__((unused)),
 | 
			
		||||
                        esp_event_base_t event_base __attribute__((unused)),
 | 
			
		||||
                        int32_t event_id,
 | 
			
		||||
| 
						 | 
				
			
			@ -128,13 +146,12 @@ void wifi_event_handler(void *handler_arg __attribute__((unused)),
 | 
			
		|||
//		printf("event: WIFI_EVENT_SCAN_DONE: ok: %lu, nr: %u, seq: %u\n",
 | 
			
		||||
//		       event->status, event->number, event->scan_id);
 | 
			
		||||
		wifi_on_scan_done(event);
 | 
			
		||||
		scan_ctx.ap = NULL;
 | 
			
		||||
		scan_ctx.cb = NULL;
 | 
			
		||||
		event_ctx.ap = NULL;
 | 
			
		||||
		event_ctx.cb = NULL;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	case WIFI_EVENT_STA_START:
 | 
			
		||||
		printf("event: WIFI_EVENT_STA_START\n");
 | 
			
		||||
		esp_wifi_connect();
 | 
			
		||||
		break;
 | 
			
		||||
	case WIFI_EVENT_STA_CONNECTED: {
 | 
			
		||||
		wifi_event_sta_connected_t *event = event_data;
 | 
			
		||||
| 
						 | 
				
			
			@ -145,6 +162,8 @@ void wifi_event_handler(void *handler_arg __attribute__((unused)),
 | 
			
		|||
#ifdef CONFIG_EXAMPLE_IPV6
 | 
			
		||||
		tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA);
 | 
			
		||||
#endif
 | 
			
		||||
		event_ctx.is_connected = 1;
 | 
			
		||||
		event_on_connected(event);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	case WIFI_EVENT_STA_DISCONNECTED: {
 | 
			
		||||
| 
						 | 
				
			
			@ -153,8 +172,8 @@ void wifi_event_handler(void *handler_arg __attribute__((unused)),
 | 
			
		|||
		printf("event: WIFI_EVENT_STA_DISCONNECTED ");
 | 
			
		||||
		printf("sta %02X:%02X:%02X:%02X:%02X:%02X disconnect reason %d\n",
 | 
			
		||||
		       m[0], m[1], m[2], m[3], m[4], m[5], event->reason);
 | 
			
		||||
		/* auto reconnect after disconnection */
 | 
			
		||||
		esp_wifi_connect();
 | 
			
		||||
		event_ctx.is_connected = 0;
 | 
			
		||||
		reconnect_after_disco();
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	case WIFI_EVENT_AP_START:
 | 
			
		||||
| 
						 | 
				
			
			@ -181,3 +200,65 @@ void wifi_event_handler(void *handler_arg __attribute__((unused)),
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void wifi_event_set_disco_handler(void (*disconn_handler)(void))
 | 
			
		||||
{
 | 
			
		||||
	event_ctx.conn.disconn_handler = disconn_handler;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int wifi_event_trigger_connect(uint8_t attempt, wifi_event_connect_done_cb cb, void *arg)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	event_ctx.conn.attempt = attempt;
 | 
			
		||||
	event_ctx.conn.cb = cb;
 | 
			
		||||
	event_ctx.conn.arg = arg;
 | 
			
		||||
	if (event_ctx.is_connected) {
 | 
			
		||||
		err = esp_wifi_disconnect();
 | 
			
		||||
	} else {
 | 
			
		||||
		err = esp_wifi_connect();
 | 
			
		||||
	}
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void event_on_connected(wifi_event_sta_connected_t *event)
 | 
			
		||||
{
 | 
			
		||||
	if (event_ctx.conn.cb) {
 | 
			
		||||
		event_ctx.conn.cb(event_ctx.conn.arg, event);
 | 
			
		||||
	}
 | 
			
		||||
	event_ctx.conn.attempt = 0;
 | 
			
		||||
	event_ctx.conn.cb = NULL;
 | 
			
		||||
	event_ctx.conn.arg = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void reconnect_after_disco()
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	ESP_LOGI(TAG, "reco... atempt %d", event_ctx.conn.attempt);
 | 
			
		||||
 | 
			
		||||
	if (event_ctx.conn.attempt == 0) {
 | 
			
		||||
		goto call;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = esp_wifi_connect();
 | 
			
		||||
	if (err) {
 | 
			
		||||
		event_ctx.conn.attempt = 0;
 | 
			
		||||
		/* connect err: stop connect and call cb */
 | 
			
		||||
		ESP_LOGE(TAG, "wifi connect error %s", esp_err_to_name(err));
 | 
			
		||||
		goto call;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	event_ctx.conn.attempt--;
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
call:
 | 
			
		||||
	if (event_ctx.conn.cb) {
 | 
			
		||||
		event_ctx.conn.cb(event_ctx.conn.arg, NULL);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* disconnected from extern environment, notify */
 | 
			
		||||
		if (event_ctx.conn.disconn_handler) {
 | 
			
		||||
			event_ctx.conn.disconn_handler();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	event_ctx.conn.cb = NULL;
 | 
			
		||||
	event_ctx.conn.arg = NULL;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,10 +9,17 @@ void ip_event_handler(void *handler_arg, esp_event_base_t event_base, int32_t ev
 | 
			
		|||
 | 
			
		||||
void wifi_event_handler(void *handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef void (*wifi_event_scan_done_cb)(uint16_t ap_count, wifi_ap_record_t *aps_info);
 | 
			
		||||
 | 
			
		||||
int wifi_event_trigger_scan(uint8_t channel, wifi_event_scan_done_cb cb, uint16_t number, wifi_ap_record_t *aps);
 | 
			
		||||
void wifi_event_set_disco_handler(void (*disconn_handler)(void));
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief
 | 
			
		||||
 * @param connect_status 0: SUCCESS, OTHER: ERROR
 | 
			
		||||
 */
 | 
			
		||||
typedef void (*wifi_event_connect_done_cb)(void *arg, wifi_event_sta_connected_t *event);
 | 
			
		||||
int wifi_event_trigger_connect(uint8_t attempt, wifi_event_connect_done_cb cb, void *arg);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif //WIFI_EVENT_HANDLER_H_GUARD
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
#include "wifi_manager.h"
 | 
			
		||||
#include "wifi_configuration.h"
 | 
			
		||||
#include "wifi_event_handler.h"
 | 
			
		||||
#include "wifi_storage.h"
 | 
			
		||||
 | 
			
		||||
#include <esp_err.h>
 | 
			
		||||
#include <esp_netif.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -16,26 +17,41 @@
 | 
			
		|||
 | 
			
		||||
#define TAG __FILENAME__
 | 
			
		||||
 | 
			
		||||
typedef struct wifi_scan_ctx_t {
 | 
			
		||||
	wifi_ap_record_t *ap;
 | 
			
		||||
	wifi_manager_scan_done_cb cb;
 | 
			
		||||
	void *arg;
 | 
			
		||||
typedef struct wifi_ctx_t {
 | 
			
		||||
	SemaphoreHandle_t lock;
 | 
			
		||||
	TaskHandle_t task;
 | 
			
		||||
	uint16_t total_aps;
 | 
			
		||||
	uint16_t nr_aps_in_channel;
 | 
			
		||||
	uint8_t status;
 | 
			
		||||
	uint8_t max_ap;
 | 
			
		||||
} wifi_scan_ctx_t;
 | 
			
		||||
	union {
 | 
			
		||||
		struct {
 | 
			
		||||
			wifi_ap_record_t *ap;
 | 
			
		||||
			wifi_manager_scan_done_cb cb;
 | 
			
		||||
			void *arg;
 | 
			
		||||
			uint16_t total_aps;
 | 
			
		||||
			uint16_t nr_aps_in_channel;
 | 
			
		||||
			uint8_t max_ap;
 | 
			
		||||
		} scan;
 | 
			
		||||
		struct {
 | 
			
		||||
			wifi_event_sta_connected_t *event;
 | 
			
		||||
			uint8_t need_unlock; /* used when trigger connection from wifi_manager instead of wifi_api */
 | 
			
		||||
		} conn;
 | 
			
		||||
	};
 | 
			
		||||
	uint8_t is_endless_connect:1;
 | 
			
		||||
	uint8_t auto_reconnect:1;
 | 
			
		||||
	uint8_t reserved:6;
 | 
			
		||||
} wifi_ctx_t;
 | 
			
		||||
 | 
			
		||||
static esp_netif_t *ap_netif;
 | 
			
		||||
static esp_netif_t *sta_netif;
 | 
			
		||||
 | 
			
		||||
static wifi_scan_ctx_t scan_ctx;
 | 
			
		||||
static wifi_ctx_t ctx;
 | 
			
		||||
 | 
			
		||||
static void set_sta_cred(const char *ssid, const char *password);
 | 
			
		||||
static void disconn_handler(void);
 | 
			
		||||
static int set_default_sta_cred(void);
 | 
			
		||||
 | 
			
		||||
void wifi_manager_init(void)
 | 
			
		||||
{
 | 
			
		||||
	esp_err_t err;
 | 
			
		||||
	uint8_t do_connect = 0;
 | 
			
		||||
 | 
			
		||||
	ap_netif = esp_netif_create_default_wifi_ap();
 | 
			
		||||
	assert(ap_netif);
 | 
			
		||||
| 
						 | 
				
			
			@ -54,26 +70,21 @@ void wifi_manager_init(void)
 | 
			
		|||
	ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
 | 
			
		||||
	ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
 | 
			
		||||
 | 
			
		||||
	wifi_config_t ap_config = {0};
 | 
			
		||||
	{
 | 
			
		||||
		wifi_config_t ap_config = {0};
 | 
			
		||||
 | 
			
		||||
	strncpy((char *) ap_config.ap.ssid, WIFI_DEFAULT_AP_SSID, 32);
 | 
			
		||||
	strncpy((char *) ap_config.ap.password, WIFI_DEFAULT_AP_PASS, 64);
 | 
			
		||||
	ap_config.ap.authmode = WIFI_AUTH_WPA2_WPA3_PSK;
 | 
			
		||||
	ap_config.ap.max_connection = 4;
 | 
			
		||||
	ap_config.ap.channel = 6;
 | 
			
		||||
	ap_config.ap.ssid_hidden = 0;
 | 
			
		||||
	ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &ap_config));
 | 
			
		||||
		strncpy((char *) ap_config.ap.ssid, WIFI_DEFAULT_AP_SSID, 32);
 | 
			
		||||
		strncpy((char *) ap_config.ap.password, WIFI_DEFAULT_AP_PASS, 64);
 | 
			
		||||
		ap_config.ap.authmode = WIFI_AUTH_WPA2_WPA3_PSK;
 | 
			
		||||
		ap_config.ap.max_connection = 4;
 | 
			
		||||
		ap_config.ap.channel = 6;
 | 
			
		||||
		ap_config.ap.ssid_hidden = 0;
 | 
			
		||||
		ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &ap_config));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: scan once and connect to known wifi
 | 
			
		||||
 | 
			
		||||
	wifi_config_t wifi_config = {
 | 
			
		||||
		.sta = {
 | 
			
		||||
			.ssid = WIFI_DEFAULT_STA_SSID,
 | 
			
		||||
			.password = WIFI_DEFAULT_STA_PASS,
 | 
			
		||||
			.sort_method = WIFI_CONNECT_AP_BY_SIGNAL,
 | 
			
		||||
		},
 | 
			
		||||
	};
 | 
			
		||||
	ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
 | 
			
		||||
	if (set_default_sta_cred() == 0) {
 | 
			
		||||
		do_connect = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* TODO: Read from nvs */
 | 
			
		||||
	esp_netif_ip_info_t ip_info;
 | 
			
		||||
| 
						 | 
				
			
			@ -96,35 +107,42 @@ void wifi_manager_init(void)
 | 
			
		|||
 | 
			
		||||
	ESP_ERROR_CHECK(esp_wifi_start());
 | 
			
		||||
	ESP_LOGI(TAG, "wifi started");
 | 
			
		||||
	esp_log_level_set("wifi", ESP_LOG_WARN);
 | 
			
		||||
 | 
			
		||||
	scan_ctx.lock = xSemaphoreCreateBinary();
 | 
			
		||||
	scan_ctx.status = 0;
 | 
			
		||||
	xSemaphoreGive(scan_ctx.lock);
 | 
			
		||||
	ctx.lock = xSemaphoreCreateBinary();
 | 
			
		||||
	ctx.is_endless_connect = 0;
 | 
			
		||||
	ctx.auto_reconnect = 1;
 | 
			
		||||
	xSemaphoreGive(ctx.lock);
 | 
			
		||||
 | 
			
		||||
	wifi_event_set_disco_handler(disconn_handler);
 | 
			
		||||
	if (do_connect) {
 | 
			
		||||
		disconn_handler();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void wifi_event_scan_channel_done(uint16_t number, wifi_ap_record_t *aps)
 | 
			
		||||
{
 | 
			
		||||
	scan_ctx.nr_aps_in_channel = number;
 | 
			
		||||
	scan_ctx.total_aps += number;
 | 
			
		||||
	if (scan_ctx.task) {
 | 
			
		||||
		xTaskNotifyGive(scan_ctx.task);
 | 
			
		||||
	ctx.scan.nr_aps_in_channel = number;
 | 
			
		||||
	ctx.scan.total_aps += number;
 | 
			
		||||
	if (ctx.task) {
 | 
			
		||||
		xTaskNotifyGive(ctx.task);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void scan_loop()
 | 
			
		||||
static int scan_loop()
 | 
			
		||||
{
 | 
			
		||||
	uint32_t ret;
 | 
			
		||||
	uint16_t number;
 | 
			
		||||
 | 
			
		||||
	scan_ctx.total_aps = 0;
 | 
			
		||||
	ctx.scan.total_aps = 0;
 | 
			
		||||
 | 
			
		||||
	for (int scan_channel = 1; scan_channel <= 13; ++scan_channel) {
 | 
			
		||||
		number = scan_ctx.max_ap - scan_ctx.total_aps;
 | 
			
		||||
		number = ctx.scan.max_ap - ctx.scan.total_aps;
 | 
			
		||||
		if (wifi_event_trigger_scan(scan_channel,
 | 
			
		||||
		                            wifi_event_scan_channel_done, number,
 | 
			
		||||
		                            &scan_ctx.ap[scan_ctx.total_aps])) {
 | 
			
		||||
		                            &ctx.scan.ap[ctx.scan.total_aps])) {
 | 
			
		||||
			ESP_LOGE(TAG, "trigger scan %d error", scan_channel);
 | 
			
		||||
			return;
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
		/* shadow wifi_event_scan_channel_done() called */
 | 
			
		||||
		vTaskDelay(100);
 | 
			
		||||
| 
						 | 
				
			
			@ -133,59 +151,51 @@ static void scan_loop()
 | 
			
		|||
		if (ret == 0) {
 | 
			
		||||
			/* timeout */
 | 
			
		||||
			ESP_LOGE(TAG, "scan channel %d timeout", scan_channel);
 | 
			
		||||
			return;
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void wifi_manager_scan_task(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	scan_loop();
 | 
			
		||||
	free(scan_ctx.ap);
 | 
			
		||||
	/* callback */
 | 
			
		||||
	if (scan_ctx.cb) {
 | 
			
		||||
		scan_ctx.cb(scan_ctx.total_aps, scan_ctx.ap, arg);
 | 
			
		||||
	}
 | 
			
		||||
	xSemaphoreGive(scan_ctx.lock);
 | 
			
		||||
	vTaskDelete(NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int wifi_manager_trigger_scan(wifi_manager_scan_done_cb cb, void *arg)
 | 
			
		||||
{
 | 
			
		||||
	if (xSemaphoreTake(scan_ctx.lock, pdMS_TO_TICKS(0)) != pdTRUE) {
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	/* TODO: let API allocate ? */
 | 
			
		||||
	scan_ctx.ap = malloc(sizeof(wifi_scan_ctx_t) * 32);
 | 
			
		||||
	if (scan_ctx.ap == NULL) {
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scan_ctx.cb = cb;
 | 
			
		||||
	scan_ctx.arg = arg;
 | 
			
		||||
	scan_ctx.max_ap = 32;
 | 
			
		||||
 | 
			
		||||
	ulTaskNotifyTake(pdTRUE, 0);
 | 
			
		||||
	xTaskCreatePinnedToCore(wifi_manager_scan_task, "scan task", 4 * 1024,
 | 
			
		||||
							arg, 7, &scan_ctx.task, 0);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int wifi_manager_get_scan_list(uint16_t *number, wifi_ap_record_t *aps)
 | 
			
		||||
{
 | 
			
		||||
	if (xSemaphoreTake(scan_ctx.lock, pdMS_TO_TICKS(0)) != pdTRUE) {
 | 
			
		||||
		return 1;
 | 
			
		||||
	int err;
 | 
			
		||||
	int broke_endless_connect = 0;
 | 
			
		||||
	if (xSemaphoreTake(ctx.lock, pdMS_TO_TICKS(0)) != pdTRUE) {
 | 
			
		||||
		if (ctx.is_endless_connect == 0) {
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
		ESP_LOGI(TAG, "deleting connecting %p", ctx.task);
 | 
			
		||||
		vTaskDelete(ctx.task);
 | 
			
		||||
		/* in case lock is released when deleting the task */
 | 
			
		||||
		xSemaphoreTake(ctx.lock, pdMS_TO_TICKS(0));
 | 
			
		||||
		esp_wifi_disconnect();
 | 
			
		||||
		ctx.is_endless_connect = 0;
 | 
			
		||||
		broke_endless_connect = 1;
 | 
			
		||||
 | 
			
		||||
	} else if (ctx.is_endless_connect == 1) {
 | 
			
		||||
		ESP_LOGI(TAG, "deleting delay %p", ctx.task);
 | 
			
		||||
		vTaskDelete(ctx.task);
 | 
			
		||||
		ctx.is_endless_connect = 0;
 | 
			
		||||
		broke_endless_connect = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scan_ctx.ap = aps;
 | 
			
		||||
	scan_ctx.max_ap = *number;
 | 
			
		||||
	scan_ctx.cb = NULL;
 | 
			
		||||
	scan_ctx.task = xTaskGetCurrentTaskHandle();
 | 
			
		||||
	ctx.scan.ap = aps;
 | 
			
		||||
	ctx.scan.max_ap = *number;
 | 
			
		||||
	ctx.scan.cb = NULL;
 | 
			
		||||
	ctx.task = xTaskGetCurrentTaskHandle();
 | 
			
		||||
 | 
			
		||||
	scan_loop();
 | 
			
		||||
	xSemaphoreGive(scan_ctx.lock);
 | 
			
		||||
	*number = scan_ctx.total_aps;
 | 
			
		||||
	return 0;
 | 
			
		||||
	err = scan_loop();
 | 
			
		||||
	xSemaphoreGive(ctx.lock);
 | 
			
		||||
	*number = ctx.scan.total_aps;
 | 
			
		||||
 | 
			
		||||
	if (broke_endless_connect) {
 | 
			
		||||
		if (set_default_sta_cred() == 0) {
 | 
			
		||||
			disconn_handler();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *wifi_manager_get_ap_netif()
 | 
			
		||||
| 
						 | 
				
			
			@ -197,3 +207,147 @@ void *wifi_manager_get_sta_netif()
 | 
			
		|||
{
 | 
			
		||||
	return sta_netif;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void try_connect_done(void *arg, wifi_event_sta_connected_t *event)
 | 
			
		||||
{
 | 
			
		||||
	ctx.conn.event = event;
 | 
			
		||||
	if (ctx.task) {
 | 
			
		||||
		xTaskNotifyGive(ctx.task);
 | 
			
		||||
	}
 | 
			
		||||
	if (ctx.conn.need_unlock) {
 | 
			
		||||
		ctx.conn.need_unlock = 0;
 | 
			
		||||
		xSemaphoreGive(ctx.lock);
 | 
			
		||||
	}
 | 
			
		||||
	ESP_LOGI(TAG, "event done %p", ctx.task);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int set_default_sta_cred()
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	wifi_credential_t credential;
 | 
			
		||||
	err = wifi_data_get_last_conn_cred(&credential);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	set_sta_cred(credential.ssid, credential.password);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int wifi_manager_connect(const char *ssid, const char *password)
 | 
			
		||||
{
 | 
			
		||||
	if (xSemaphoreTake(ctx.lock, pdMS_TO_TICKS(0)) != pdTRUE) {
 | 
			
		||||
		if (ctx.is_endless_connect == 0) {
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
		vTaskDelete(ctx.task);
 | 
			
		||||
		ctx.is_endless_connect = 0;
 | 
			
		||||
	}
 | 
			
		||||
	int ret;
 | 
			
		||||
	set_sta_cred(ssid, password);
 | 
			
		||||
 | 
			
		||||
	ctx.task = xTaskGetCurrentTaskHandle();
 | 
			
		||||
	ctx.auto_reconnect = 1;
 | 
			
		||||
 | 
			
		||||
	wifi_event_trigger_connect(2, try_connect_done, NULL);
 | 
			
		||||
	ret = ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(10000));
 | 
			
		||||
 | 
			
		||||
	xSemaphoreGive(ctx.lock);
 | 
			
		||||
	if (ret == 0 || ctx.conn.event == NULL) {
 | 
			
		||||
		ESP_LOGI(TAG, "conn error");
 | 
			
		||||
		if (set_default_sta_cred() == 0) {
 | 
			
		||||
			disconn_handler();
 | 
			
		||||
		}
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wifi_credential_t credential;
 | 
			
		||||
	memcpy(credential.ssid, ssid, 32);
 | 
			
		||||
	memcpy(credential.password, password, 64);
 | 
			
		||||
	ret = wifi_save_ap_credential(&credential);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		ESP_LOGE(TAG, "nvs save error: %s", esp_err_to_name(ret));
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_sta_cred(const char *ssid, const char *password)
 | 
			
		||||
{
 | 
			
		||||
	wifi_config_t wifi_config = {
 | 
			
		||||
		.sta = {
 | 
			
		||||
			.threshold.rssi = -80,
 | 
			
		||||
			.sort_method = WIFI_CONNECT_AP_BY_SIGNAL,
 | 
			
		||||
		},
 | 
			
		||||
	};
 | 
			
		||||
	memcpy((char *) wifi_config.sta.ssid, ssid, 32);
 | 
			
		||||
	memcpy((char *) wifi_config.sta.password, password, 64);
 | 
			
		||||
 | 
			
		||||
	ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void reconnection_task(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	ctx.is_endless_connect = 1;
 | 
			
		||||
	ctx.task = xTaskGetCurrentTaskHandle();
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		ESP_LOGI(TAG, "reco task: try connect, task %p", xTaskGetCurrentTaskHandle());
 | 
			
		||||
		err = wifi_event_trigger_connect(0, try_connect_done, NULL);
 | 
			
		||||
		if (err) {
 | 
			
		||||
			ESP_LOGE(TAG, "trigger connect err: %s", esp_err_to_name(err));
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(20000));
 | 
			
		||||
		if (ctx.conn.event || ctx.auto_reconnect == 0) {
 | 
			
		||||
			/* reconnection successful or stop reconnect */
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* long wait to not spam try to reconnect */
 | 
			
		||||
		xSemaphoreGive(ctx.lock);
 | 
			
		||||
		ESP_LOGI(TAG, "retry connection in 5 seconds");
 | 
			
		||||
		vTaskDelay(pdMS_TO_TICKS(5 * 1000));
 | 
			
		||||
		if (xSemaphoreTake(ctx.lock, pdMS_TO_TICKS(0)) != pdTRUE) {
 | 
			
		||||
			ESP_LOGE(TAG, "reconnection failed");
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	} while (1);
 | 
			
		||||
 | 
			
		||||
	ctx.is_endless_connect = 0;
 | 
			
		||||
	xSemaphoreGive(ctx.lock);
 | 
			
		||||
	vTaskDelete(NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void disconn_handler(void)
 | 
			
		||||
{
 | 
			
		||||
	/* disconnected
 | 
			
		||||
	 * 1. WI-FI AP is far away
 | 
			
		||||
	 * 2. WI-FI AP or AP device is closed
 | 
			
		||||
	 * 3. this device is ejected by AP
 | 
			
		||||
	 * */
 | 
			
		||||
 | 
			
		||||
	if (ctx.auto_reconnect == 0) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (xSemaphoreTake(ctx.lock, pdMS_TO_TICKS(0)) != pdTRUE) {
 | 
			
		||||
		ESP_LOGE(TAG, "disconn_handler failed");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ESP_LOGI(TAG, "start reconn task");
 | 
			
		||||
	xTaskCreate(reconnection_task, "reconn task", 4 * 1024, NULL, 7, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief kill reconnection task
 | 
			
		||||
 * @return
 | 
			
		||||
 */
 | 
			
		||||
int wifi_manager_disconnect(void)
 | 
			
		||||
{
 | 
			
		||||
	ctx.auto_reconnect = 0;
 | 
			
		||||
	return esp_wifi_disconnect();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,9 +13,9 @@ void *wifi_manager_get_ap_netif();
 | 
			
		|||
void *wifi_manager_get_sta_netif();
 | 
			
		||||
 | 
			
		||||
typedef void (*wifi_manager_scan_done_cb)(uint16_t ap_found, wifi_ap_record_t *record, void *arg);
 | 
			
		||||
int wifi_manager_scan(uint16_t *number, wifi_ap_record_t *records, uint8_t is_async);
 | 
			
		||||
int wifi_manager_trigger_scan(wifi_manager_scan_done_cb cb, void *arg);
 | 
			
		||||
int wifi_manager_get_scan_list(uint16_t *number, wifi_ap_record_t *aps);
 | 
			
		||||
int wifi_manager_connect(const char *ssid, const char *password);
 | 
			
		||||
int wifi_manager_disconnect(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,77 @@
 | 
			
		|||
#include "wifi_storage.h"
 | 
			
		||||
#include "wifi_storage_priv.h"
 | 
			
		||||
#include "wt_nvs.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#define NVS_NAMESPACE "wifi"
 | 
			
		||||
 | 
			
		||||
int wifi_data_get_last_conn_cred(wifi_credential_t *ap_credential)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t ap_bitmap = 0;
 | 
			
		||||
	nvs_handle_t handle;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	err = wt_nvs_open(NVS_NAMESPACE, &handle);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		return WT_NVS_ERR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = wt_nvs_get(handle, KEY_WIFI_STA_AP_BITMAP, &ap_bitmap, sizeof(ap_bitmap));
 | 
			
		||||
	if (err || ap_bitmap == 0) {
 | 
			
		||||
		return WT_NVS_ERR_NOT_FOUND;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = wt_nvs_get(handle, KEY_WIFI_STA_LAST_AP_CRED,
 | 
			
		||||
					 ap_credential, sizeof(wifi_credential_t));
 | 
			
		||||
	if (err) {
 | 
			
		||||
		return WT_NVS_ERR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wt_nvs_close(handle);
 | 
			
		||||
	return WT_NVS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Called when connect to an AP,
 | 
			
		||||
 */
 | 
			
		||||
int wifi_save_ap_credential(wifi_credential_t *ap_credential)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t ap_bitmap;
 | 
			
		||||
	int err;
 | 
			
		||||
	nvs_handle_t handle;
 | 
			
		||||
 | 
			
		||||
	err = wt_nvs_open(NVS_NAMESPACE, &handle);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = wt_nvs_get(handle, KEY_WIFI_STA_AP_BITMAP, &ap_bitmap, sizeof(ap_bitmap));
 | 
			
		||||
	if (err) {
 | 
			
		||||
		if (err != ESP_ERR_NVS_NOT_FOUND) {
 | 
			
		||||
			return err;
 | 
			
		||||
		}
 | 
			
		||||
		ap_bitmap = 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (ap_bitmap == 0) {
 | 
			
		||||
		ap_bitmap = 1;
 | 
			
		||||
		err = wt_nvs_set(handle, KEY_WIFI_STA_AP_BITMAP, &ap_bitmap, sizeof(ap_bitmap));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	wifi_credential_t credential;
 | 
			
		||||
	err = wt_nvs_get(handle, KEY_WIFI_STA_LAST_AP_CRED, &credential, sizeof(ap_bitmap));
 | 
			
		||||
	if (err) {
 | 
			
		||||
		if (err != ESP_ERR_NVS_NOT_FOUND) {
 | 
			
		||||
			return err;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err |= wt_nvs_set(handle, KEY_WIFI_STA_LAST_AP_CRED, ap_credential, sizeof(wifi_credential_t));
 | 
			
		||||
	if (err) {
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wt_nvs_close(handle);
 | 
			
		||||
	return WT_NVS_OK;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
#ifndef WIFI_STORAGE_H_GUARD
 | 
			
		||||
#define WIFI_STORAGE_H_GUARD
 | 
			
		||||
 | 
			
		||||
#include <stdint-gcc.h>
 | 
			
		||||
 | 
			
		||||
typedef struct nvs_wifi_credential_t {
 | 
			
		||||
	char ssid[32];
 | 
			
		||||
	char password[64];
 | 
			
		||||
} wifi_credential_t;
 | 
			
		||||
 | 
			
		||||
int wifi_data_get_last_conn_cred(wifi_credential_t *ap_credential);
 | 
			
		||||
 | 
			
		||||
int wifi_get_ap_password_of_ssid(wifi_credential_t *ap_credential);
 | 
			
		||||
int wifi_save_ap_credential(wifi_credential_t *ap_credential);
 | 
			
		||||
int wifi_rm_ap_credential(const char *ssid);
 | 
			
		||||
 | 
			
		||||
void wifi_cache_enable(uint8_t en);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif //WIFI_STORAGE_H_GUARD
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
#ifndef WIFI_STORAGE_PRIV_H_GUARD
 | 
			
		||||
#define WIFI_STORAGE_PRIV_H_GUARD
 | 
			
		||||
 | 
			
		||||
#define WIFI_MAX_AP_CRED_RECORD 1
 | 
			
		||||
 | 
			
		||||
typedef struct w_cache_t {
 | 
			
		||||
	uint32_t ap_bitmap;
 | 
			
		||||
	wifi_credential_t ap_creds[WIFI_MAX_AP_CRED_RECORD];
 | 
			
		||||
} w_cache_t;
 | 
			
		||||
 | 
			
		||||
typedef enum wt_wifi_key_enum {
 | 
			
		||||
	KEY_WIFI_RESERVED = 0x000,
 | 
			
		||||
/* WIFI */
 | 
			
		||||
	KEY_WIFI_AP_SSID,
 | 
			
		||||
	KEY_WIFI_AP_PASSWORD,
 | 
			
		||||
 | 
			
		||||
/* TODO: should have 1 for each AP */
 | 
			
		||||
	KEY_WIFI_STA_USE_STATIC, /* bit[0:31]=[IP, MASK, GATEWAY, DNS] */
 | 
			
		||||
	KEY_WIFI_STA_STATIC_IP, /* 4B */
 | 
			
		||||
	KEY_WIFI_STA_STATIC_MASK, /* 4B */
 | 
			
		||||
	KEY_WIFI_STA_STATIC_GATEWAY, /* 4B */
 | 
			
		||||
	KEY_WIFI_STA_STATIC_DNS, /* 4B */
 | 
			
		||||
 | 
			
		||||
/* AP's information */
 | 
			
		||||
	KEY_WIFI_STA_LAST_AP_CRED, /*!< ssid[32] + password[64] */
 | 
			
		||||
	KEY_WIFI_STA_AP_BITMAP,
 | 
			
		||||
} wt_wifi_key;
 | 
			
		||||
 | 
			
		||||
#endif //WIFI_STORAGE_PRIV_H_GUARD
 | 
			
		||||
| 
						 | 
				
			
			@ -3,5 +3,6 @@ file(GLOB SOURCES wt_nvs.c wt_storage.c)
 | 
			
		|||
idf_component_register(
 | 
			
		||||
        SRCS ${SOURCES}
 | 
			
		||||
        INCLUDE_DIRS "."
 | 
			
		||||
        PRIV_REQUIRES nvs_flash
 | 
			
		||||
        PRIV_REQUIRES
 | 
			
		||||
        REQUIRES nvs_flash
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -14,3 +14,73 @@ void wt_nvs_init()
 | 
			
		|||
	}
 | 
			
		||||
	ESP_ERROR_CHECK(err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int wt_nvs_open(const char* namespace, nvs_handle_t *out_handle)
 | 
			
		||||
{
 | 
			
		||||
	return nvs_open(namespace, NVS_READWRITE, out_handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void wt_nvs_close(nvs_handle_t handle)
 | 
			
		||||
{
 | 
			
		||||
	ESP_ERROR_CHECK(nvs_commit(handle));
 | 
			
		||||
	nvs_close(handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int wt_nvs_get(nvs_handle_t handle, const uint32_t key, void *data, uint32_t data_size)
 | 
			
		||||
{
 | 
			
		||||
	switch (data_size) {
 | 
			
		||||
	case 0: {
 | 
			
		||||
		uint8_t tmp;
 | 
			
		||||
		return nvs_get_u8(handle, (const char *) &key, &tmp);
 | 
			
		||||
	}
 | 
			
		||||
	case 1:
 | 
			
		||||
		return nvs_get_u8(handle, (const char *) &key, data);
 | 
			
		||||
	case 2:
 | 
			
		||||
		return nvs_get_u16(handle, (const char *) &key, data);
 | 
			
		||||
	case 4:
 | 
			
		||||
		return nvs_get_u32(handle, (const char *) &key, data);
 | 
			
		||||
	case 8:
 | 
			
		||||
		return nvs_get_u64(handle, (const char *) &key, data);
 | 
			
		||||
	default:
 | 
			
		||||
		return nvs_get_blob(handle, (const char *) &key, data,
 | 
			
		||||
							(size_t *) &data_size);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int wt_nvs_set(nvs_handle_t handle, const uint32_t key, void *data, uint32_t data_size)
 | 
			
		||||
{
 | 
			
		||||
	switch (data_size) {
 | 
			
		||||
	case 0: {
 | 
			
		||||
		uint8_t tmp = 0xFF;
 | 
			
		||||
		return nvs_set_u8(handle, (const char *) &key, tmp);
 | 
			
		||||
	}
 | 
			
		||||
	case 1:
 | 
			
		||||
		return nvs_set_u8(handle, (const char *) &key, *(uint8_t *)data);
 | 
			
		||||
	case 2:
 | 
			
		||||
		return nvs_set_u16(handle, (const char *) &key, *(uint16_t *)data);
 | 
			
		||||
	case 4:
 | 
			
		||||
		return nvs_set_u32(handle, (const char *) &key, *(uint32_t *)data);
 | 
			
		||||
	case 8:
 | 
			
		||||
		return nvs_set_u64(handle, (const char *) &key, *(uint64_t *)data);
 | 
			
		||||
	default:
 | 
			
		||||
		return nvs_set_blob(handle, (const char *) &key, data, data_size);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int wt_nvs_get_once(const char* namespace, const uint32_t key, void *data, uint32_t data_size)
 | 
			
		||||
{
 | 
			
		||||
	nvs_handle_t handle;
 | 
			
		||||
	int err;
 | 
			
		||||
	err = wt_nvs_open(namespace, &handle);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = wt_nvs_get(handle, key, data, data_size);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wt_nvs_close(handle);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,25 @@
 | 
			
		|||
#define WT_NVS_H_GUARD
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <nvs.h>
 | 
			
		||||
 | 
			
		||||
typedef enum wt_nvs_error_enum {
 | 
			
		||||
	WT_NVS_OK = 0,
 | 
			
		||||
	WT_NVS_ERR,
 | 
			
		||||
	WT_NVS_NO_MEM,
 | 
			
		||||
	WT_NVS_ERR_NOT_FOUND,
 | 
			
		||||
 | 
			
		||||
} wt_nvs_key_error;
 | 
			
		||||
 | 
			
		||||
int wt_nvs_open(const char* namespace, nvs_handle_t *out_handle);
 | 
			
		||||
 | 
			
		||||
void wt_nvs_close(nvs_handle_t handle);
 | 
			
		||||
 | 
			
		||||
int wt_nvs_get(nvs_handle_t handle, uint32_t key, void *data, uint32_t data_size);
 | 
			
		||||
 | 
			
		||||
int wt_nvs_set(nvs_handle_t handle, uint32_t key, void *data, uint32_t data_size);
 | 
			
		||||
 | 
			
		||||
int wt_nvs_flush(nvs_handle_t handle);
 | 
			
		||||
 | 
			
		||||
void wt_nvs_init();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue