1 /* SoftAP based Custom Provisioning Example
2 
3    This example code is in the Public Domain (or CC0 licensed, at your option.)
4 
5    Unless required by applicable law or agreed to in writing, this
6    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7    CONDITIONS OF ANY KIND, either express or implied.
8 */
9 
10 /* This file is mostly a boiler-plate code that applications can use without much change */
11 
12 #include <stdio.h>
13 #include <string.h>
14 #include <esp_err.h>
15 #include <esp_log.h>
16 
17 #include <esp_wifi.h>
18 #include <esp_netif.h>
19 
20 #include <wifi_provisioning/wifi_config.h>
21 #include <custom_provisioning/custom_config.h>
22 
23 #include "app_prov.h"
24 
25 static const char* TAG = "app_prov_handler";
26 
27 /* Provide definition of wifi_prov_ctx_t */
28 struct wifi_prov_ctx {
29     wifi_config_t wifi_cfg;
30 };
31 
get_config(wifi_prov_ctx_t ** ctx)32 static wifi_config_t *get_config(wifi_prov_ctx_t **ctx)
33 {
34     return (*ctx ? &(*ctx)->wifi_cfg : NULL);
35 }
36 
new_config(wifi_prov_ctx_t ** ctx)37 static wifi_config_t *new_config(wifi_prov_ctx_t **ctx)
38 {
39     free(*ctx);
40     (*ctx) = (wifi_prov_ctx_t *) calloc(1, sizeof(wifi_prov_ctx_t));
41     return get_config(ctx);
42 }
43 
free_config(wifi_prov_ctx_t ** ctx)44 static void free_config(wifi_prov_ctx_t **ctx)
45 {
46     free(*ctx);
47     *ctx = NULL;
48 }
49 
50 /****************** Handler for Custom Configuration *******************/
custom_config_handler(const custom_config_t * config)51 static esp_err_t custom_config_handler(const custom_config_t *config)
52 {
53     ESP_LOGI(TAG, "Custom config received :\n\tInfo : %s\n\tVersion : %d",
54              config->info, config->version);
55     return ESP_OK;
56 }
57 
58 custom_prov_config_handler_t custom_prov_handler = custom_config_handler;
59 
60 /****************** Handlers for Wi-Fi Configuration *******************/
get_status_handler(wifi_prov_config_get_data_t * resp_data,wifi_prov_ctx_t ** ctx)61 static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi_prov_ctx_t **ctx)
62 {
63     /* Initialize to zero */
64     memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t));
65 
66     if (app_prov_get_wifi_state(&resp_data->wifi_state) != ESP_OK) {
67         ESP_LOGW(TAG, "Prov app not running");
68         return ESP_FAIL;
69     }
70 
71     if (resp_data->wifi_state == WIFI_PROV_STA_CONNECTED) {
72         ESP_LOGI(TAG, "Connected state");
73 
74         /* IP Addr assigned to STA */
75         esp_netif_ip_info_t ip_info;
76         esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info);
77         esp_ip4addr_ntoa(&ip_info.ip, resp_data->conn_info.ip_addr, sizeof(resp_data->conn_info.ip_addr));
78 
79         /* AP information to which STA is connected */
80         wifi_ap_record_t ap_info;
81         esp_wifi_sta_get_ap_info(&ap_info);
82         memcpy(resp_data->conn_info.bssid, (char *)ap_info.bssid, sizeof(ap_info.bssid));
83         memcpy(resp_data->conn_info.ssid,  (char *)ap_info.ssid,  sizeof(ap_info.ssid));
84         resp_data->conn_info.channel   = ap_info.primary;
85         resp_data->conn_info.auth_mode = ap_info.authmode;
86     } else if (resp_data->wifi_state == WIFI_PROV_STA_DISCONNECTED) {
87         ESP_LOGI(TAG, "Disconnected state");
88 
89         /* If disconnected, convey reason */
90         app_prov_get_wifi_disconnect_reason(&resp_data->fail_reason);
91     } else {
92         ESP_LOGI(TAG, "Connecting state");
93     }
94     return ESP_OK;
95 }
96 
set_config_handler(const wifi_prov_config_set_data_t * req_data,wifi_prov_ctx_t ** ctx)97 static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, wifi_prov_ctx_t **ctx)
98 {
99     wifi_config_t *wifi_cfg = get_config(ctx);
100     if (wifi_cfg) {
101         free_config(ctx);
102     }
103 
104     wifi_cfg = new_config(ctx);
105     if (!wifi_cfg) {
106         ESP_LOGE(TAG, "Unable to alloc wifi config");
107         return ESP_FAIL;
108     }
109 
110     ESP_LOGI(TAG, "WiFi Credentials Received : \n\tssid %s \n\tpassword %s",
111              req_data->ssid, req_data->password);
112 
113     /* Using memcpy allows the max SSID length to be 32 bytes (as per 802.11 standard).
114      * But this doesn't guarantee that the saved SSID will be null terminated, because
115      * wifi_cfg->sta.ssid is also 32 bytes long (without extra 1 byte for null character).
116      * Although, this is not a matter for concern because esp_wifi library reads the SSID
117      * upto 32 bytes in absence of null termination */
118     const size_t ssid_len = strnlen(req_data->ssid, sizeof(wifi_cfg->sta.ssid));
119     /* Ensure SSID less than 32 bytes is null terminated */
120     memset(wifi_cfg->sta.ssid, 0, sizeof(wifi_cfg->sta.ssid));
121     memcpy(wifi_cfg->sta.ssid, req_data->ssid, ssid_len);
122 
123     strlcpy((char *) wifi_cfg->sta.password, req_data->password, sizeof(wifi_cfg->sta.password));
124     return ESP_OK;
125 }
126 
apply_config_handler(wifi_prov_ctx_t ** ctx)127 static esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx)
128 {
129     wifi_config_t *wifi_cfg = get_config(ctx);
130     if (!wifi_cfg) {
131         ESP_LOGE(TAG, "WiFi config not set");
132         return ESP_FAIL;
133     }
134 
135     app_prov_configure_sta(wifi_cfg);
136     ESP_LOGI(TAG, "WiFi Credentials Applied");
137 
138     free_config(ctx);
139     return ESP_OK;
140 }
141 
142 wifi_prov_config_handlers_t wifi_prov_handlers = {
143     .get_status_handler   = get_status_handler,
144     .set_config_handler   = set_config_handler,
145     .apply_config_handler = apply_config_handler,
146     .ctx = NULL
147 };
148