1
+ /**
2
+ * Bootwifi - Boot the WiFi environment.
3
+ *
4
+ * Compile with -DBOOTWIFI_OVERRIDE_GPIO=<num> where <num> is a GPIO pin number
5
+ * to use a GPIO override.
6
+ * See the README.md for full information.
7
+ *
8
+ */
9
+ #include <freertos/FreeRTOS.h>
10
+ #include <freertos/task.h>
1
11
#include <esp_log.h>
2
12
#include <esp_err.h>
3
13
#include <esp_system.h>
6
16
#include <esp_wifi.h>
7
17
#include <nvs.h>
8
18
#include <nvs_flash.h>
9
- #include <freertos/FreeRTOS.h>
10
- #include <freertos/task.h>
11
19
#include <driver/gpio.h>
20
+ #include <tcpip_adapter.h>
21
+ #include <lwip/sockets.h>
12
22
#include <mongoose.h>
13
23
#include "bootwifi.h"
14
24
#include "sdkconfig.h"
15
25
#include "selectAP.h"
16
- // Key used in NVS for connection info
17
- #define KEY_CONNECTION_INFO "connectionInfo"
18
26
19
- // Namespace in NVS for bootwifi
20
- #define BOOTWIFI_NAMESPACE "bootwifi"
27
+ // If the structure of a record saved for a subsequent reboot changes
28
+ // then consider using semver to change the version number or else
29
+ // we may try and boot with the wrong data.
30
+ #define KEY_VERSION "version"
31
+ uint32_t g_version = 0x0100 ;
21
32
22
- #define SSID_SIZE (32)
23
- #define PASSWORD_SIZE (64)
24
-
25
- #define OVERRIDE_GPIO GPIO_NUM_25
33
+ #define KEY_CONNECTION_INFO "connectionInfo" // Key used in NVS for connection info
34
+ #define BOOTWIFI_NAMESPACE "bootwifi" // Namespace in NVS for bootwifi
35
+ #define SSID_SIZE (32) // Maximum SSID size
36
+ #define PASSWORD_SIZE (64) // Maximum password size
26
37
27
38
typedef struct {
28
39
char ssid [SSID_SIZE ];
29
40
char password [PASSWORD_SIZE ];
41
+ tcpip_adapter_ip_info_t ipInfo ; // Optional static IP information
30
42
} connection_info_t ;
31
43
32
- static char tag [] = "bootwifi" ;
33
-
34
- static bootwifi_callback_t g_callback = NULL ;
44
+ static bootwifi_callback_t g_callback = NULL ; // Callback function to be invoked when we have finished.
35
45
36
46
static int g_mongooseStarted = 0 ; // Has the mongoose server started?
37
47
static int g_mongooseStopRequest = 0 ; // Request to stop the mongoose server.
38
48
49
+ // Forward declarations
39
50
static void saveConnectionInfo (connection_info_t * pConnectionInfo );
40
51
static void becomeAccessPoint ();
41
52
static void bootWiFi2 ();
42
53
54
+ static char tag [] = "bootwifi" ;
55
+
56
+
57
+
58
+
59
+
43
60
/**
44
- * Convert a Mongoose event type to a string.
61
+ * Convert a Mongoose event type to a string. Used for debugging.
45
62
*/
46
63
static char * mongoose_eventToString (int ev ) {
47
64
static char temp [100 ];
@@ -134,21 +151,52 @@ static void mongoose_event_handler(struct mg_connection *nc, int ev, void *evDat
134
151
} if (strcmp (uri , "/" ) == 0 ) {
135
152
mg_send_head (nc , 200 , sizeof (selectAP_html ), "Content-Type: text/html" );
136
153
mg_send (nc , selectAP_html , sizeof (selectAP_html ));
137
- } if (strcmp (uri , "/ssidSelected" ) == 0 ) {
154
+ }
155
+ // Handle /ssidSelected
156
+ // This is an incoming form with properties:
157
+ // * ssid - The ssid of the network to connect against.
158
+ // * password - the password to use to connect.
159
+ // * ip - Static IP address ... may be empty
160
+ // * gw - Static GW address ... may be empty
161
+ // * netmask - Static netmask ... may be empty
162
+ if (strcmp (uri , "/ssidSelected" ) == 0 ) {
138
163
// We have received a form page containing the details. The form body will
139
164
// contain:
140
165
// ssid=<value>&password=<value>
141
166
ESP_LOGD (tag , "- body: %.*s" , message -> body .len , message -> body .p );
142
167
connection_info_t connectionInfo ;
143
- mg_get_http_var (& message -> body , "ssid" ,
144
- connectionInfo .ssid , SSID_SIZE );
145
- mg_get_http_var (& message -> body , "password" ,
146
- connectionInfo .password , PASSWORD_SIZE );
168
+ mg_get_http_var (& message -> body , "ssid" , connectionInfo .ssid , SSID_SIZE );
169
+ mg_get_http_var (& message -> body , "password" , connectionInfo .password , PASSWORD_SIZE );
170
+
171
+ char ipBuf [20 ];
172
+ if (mg_get_http_var (& message -> body , "ip" , ipBuf , sizeof (ipBuf )) > 0 ) {
173
+ inet_pton (AF_INET , ipBuf , & connectionInfo .ipInfo .ip );
174
+ } else {
175
+ connectionInfo .ipInfo .ip .addr = 0 ;
176
+ }
177
+
178
+ if (mg_get_http_var (& message -> body , "gw" , ipBuf , sizeof (ipBuf )) > 0 ) {
179
+ inet_pton (AF_INET , ipBuf , & connectionInfo .ipInfo .gw );
180
+ }
181
+ else {
182
+ connectionInfo .ipInfo .gw .addr = 0 ;
183
+ }
184
+
185
+ if (mg_get_http_var (& message -> body , "netmask" , ipBuf , sizeof (ipBuf )) > 0 ) {
186
+ inet_pton (AF_INET , ipBuf , & connectionInfo .ipInfo .netmask );
187
+ }
188
+ else {
189
+ connectionInfo .ipInfo .netmask .addr = 0 ;
190
+ }
191
+
147
192
ESP_LOGD (tag , "ssid: %s, password: %s" , connectionInfo .ssid , connectionInfo .password );
193
+
148
194
mg_send_head (nc , 200 , 0 , "Content-Type: text/plain" );
149
195
saveConnectionInfo (& connectionInfo );
150
196
bootWiFi2 ();
151
- } else {
197
+ } // url is "/ssidSelected"
198
+ // Else ... unknown URL
199
+ else {
152
200
mg_send_head (nc , 404 , 0 , "Content-Type: text/plain" );
153
201
}
154
202
nc -> flags |= MG_F_SEND_AND_CLOSE ;
@@ -189,6 +237,11 @@ static void mongooseTask(void *data) {
189
237
mg_mgr_free (& mgr );
190
238
g_mongooseStarted = 0 ;
191
239
240
+ // Since we HAVE ended mongoose, time to invoke the callback.
241
+ if (g_callback ) {
242
+ g_callback (1 );
243
+ }
244
+
192
245
ESP_LOGD (tag , "<< mongooseTask" );
193
246
vTaskDelete (NULL );
194
247
return ;
@@ -218,18 +271,24 @@ static esp_err_t esp32_wifi_eventHandler(void *ctx, system_event_t *event) {
218
271
switch (event -> event_id ) {
219
272
// When we have started being an access point, then start being a web server.
220
273
case SYSTEM_EVENT_AP_START : { // Handle the AP start event
221
- ESP_LOGD (tag , "AP started" );
274
+ tcpip_adapter_ip_info_t ip_info ;
275
+ tcpip_adapter_get_ip_info (TCPIP_ADAPTER_IF_AP , & ip_info );
276
+ ESP_LOGD (tag , "**********************************************" );
277
+ ESP_LOGD (tag , "* We are now an access point and you can point" )
278
+ ESP_LOGD (tag , "* your browser to http://" IPSTR , IP2STR (& ip_info .ip ));
279
+ ESP_LOGD (tag , "**********************************************" );
222
280
// Start Mongoose ...
223
281
if (!g_mongooseStarted )
224
282
{
225
283
g_mongooseStarted = 1 ;
226
- xTaskCreatePinnedToCore (& mongooseTask , "mongoose_task " , 2048 , NULL , 5 , NULL , 0 );
284
+ xTaskCreatePinnedToCore (& mongooseTask , "bootwifi_mongoose_task" , 8000 , NULL , 5 , NULL , 0 );
227
285
}
228
286
break ;
229
287
} // SYSTEM_EVENT_AP_START
230
288
231
289
// If we fail to connect to an access point as a station, become an access point.
232
290
case SYSTEM_EVENT_STA_DISCONNECTED : {
291
+ ESP_LOGD (tag , "Station disconnected started" );
233
292
// We think we tried to connect as a station and failed! ... become
234
293
// an access point.
235
294
becomeAccessPoint ();
@@ -239,14 +298,18 @@ static esp_err_t esp32_wifi_eventHandler(void *ctx, system_event_t *event) {
239
298
// If we connected as a station then we are done and we can stop being a
240
299
// web server.
241
300
case SYSTEM_EVENT_STA_GOT_IP : {
242
- ESP_LOGD (tag , " *******************************************" );
301
+ ESP_LOGD (tag , "* *******************************************" );
243
302
ESP_LOGD (tag , "* We are now connected and ready to do work!" )
244
303
ESP_LOGD (tag , "* - Our IP address is: " IPSTR , IP2STR (& event -> event_info .got_ip .ip_info .ip ));
245
- ESP_LOGD (tag , " *******************************************" );
304
+ ESP_LOGD (tag , "* *******************************************" );
246
305
g_mongooseStopRequest = 1 ; // Stop mongoose (if it is running).
247
- if (g_callback ) {
248
- g_callback (1 );
249
- }
306
+ // Invoke the callback if Mongoose has NOT been started ... otherwise
307
+ // we will invoke the callback when mongoose has ended.
308
+ if (!g_mongooseStarted ) {
309
+ if (g_callback ) {
310
+ g_callback (1 );
311
+ }
312
+ } // Mongoose was NOT started
250
313
break ;
251
314
} // SYSTEM_EVENT_STA_GOTIP
252
315
@@ -265,24 +328,49 @@ static int getConnectionInfo(connection_info_t *pConnectionInfo) {
265
328
nvs_handle handle ;
266
329
size_t size ;
267
330
esp_err_t err ;
331
+ uint32_t version ;
268
332
err = nvs_open (BOOTWIFI_NAMESPACE , NVS_READWRITE , & handle );
269
333
if (err != 0 ) {
270
334
ESP_LOGE (tag , "nvs_open: %x" , err );
271
335
return -1 ;
272
336
}
273
337
338
+ // Get the version that the data was saved against.
339
+ err = nvs_get_u32 (handle , KEY_VERSION , & version );
340
+ if (err != ESP_OK ) {
341
+ ESP_LOGD (tag , "No version record found (%d)." , err );
342
+ nvs_close (handle );
343
+ return -1 ;
344
+ }
345
+
346
+ // Check the versions match
347
+ if ((version & 0xff00 ) != (g_version & 0xff00 )) {
348
+ ESP_LOGD (tag , "Incompatible versions ... current is %x, found is %x" , version , g_version );
349
+ nvs_close (handle );
350
+ return -1 ;
351
+ }
352
+
274
353
size = sizeof (connection_info_t );
275
354
err = nvs_get_blob (handle , KEY_CONNECTION_INFO , pConnectionInfo , & size );
276
- if (err == ESP_ERR_NVS_NOT_FOUND ) {
355
+ if (err != ESP_OK ) {
356
+ ESP_LOGD (tag , "No connection record found (%d)." , err );
277
357
nvs_close (handle );
278
358
return -1 ;
279
359
}
280
- if (err != 0 ) {
360
+ if (err != ESP_OK ) {
281
361
ESP_LOGE (tag , "nvs_open: %x" , err );
282
362
nvs_close (handle );
283
363
return -1 ;
284
364
}
365
+
366
+ // Cleanup
285
367
nvs_close (handle );
368
+
369
+ // Do a sanity check on the SSID
370
+ if (strlen (pConnectionInfo -> ssid ) == 0 ) {
371
+ ESP_LOGD (tag , "NULL ssid detected" );
372
+ return -1 ;
373
+ }
286
374
return 0 ;
287
375
} // getConnectionInfo
288
376
@@ -295,6 +383,7 @@ static void saveConnectionInfo(connection_info_t *pConnectionInfo) {
295
383
ESP_ERROR_CHECK (nvs_open (BOOTWIFI_NAMESPACE , NVS_READWRITE , & handle ));
296
384
ESP_ERROR_CHECK (nvs_set_blob (handle , KEY_CONNECTION_INFO , pConnectionInfo ,
297
385
sizeof (connection_info_t )));
386
+ ESP_ERROR_CHECK (nvs_set_u32 (handle , KEY_VERSION , g_version ));
298
387
ESP_ERROR_CHECK (nvs_commit (handle ));
299
388
nvs_close (handle );
300
389
} // setConnectionInfo
@@ -304,7 +393,17 @@ static void saveConnectionInfo(connection_info_t *pConnectionInfo) {
304
393
* Become a station connecting to an existing access point.
305
394
*/
306
395
static void becomeStation (connection_info_t * pConnectionInfo ) {
307
- ESP_LOGD (tag , "- Connecting to access point %s ..." , pConnectionInfo -> ssid );
396
+ ESP_LOGD (tag , "- Connecting to access point \"%s\" ..." , pConnectionInfo -> ssid );
397
+ assert (strlen (pConnectionInfo -> ssid ) > 0 );
398
+
399
+ // If we have a static IP address information, use that.
400
+ if (pConnectionInfo -> ipInfo .ip .addr != 0 ) {
401
+ ESP_LOGD (tag , " - using a static IP address of " IPSTR , IP2STR (& pConnectionInfo -> ipInfo .ip ));
402
+ tcpip_adapter_dhcpc_stop (TCPIP_ADAPTER_IF_STA );
403
+ tcpip_adapter_set_ip_info (TCPIP_ADAPTER_IF_STA , & pConnectionInfo -> ipInfo );
404
+ } else {
405
+ tcpip_adapter_dhcpc_start (TCPIP_ADAPTER_IF_STA );
406
+ }
308
407
309
408
ESP_ERROR_CHECK ( esp_wifi_set_mode (WIFI_MODE_STA ));
310
409
wifi_config_t sta_config ;
@@ -346,14 +445,20 @@ static void becomeAccessPoint() {
346
445
* indicate that we should not attempt to connect to any previously saved
347
446
* access point we may know about.
348
447
*/
448
+
349
449
static int checkOverrideGpio () {
350
- gpio_pad_select_gpio (OVERRIDE_GPIO );
351
- gpio_set_direction (OVERRIDE_GPIO , GPIO_MODE_INPUT );
352
- gpio_set_pull_mode (OVERRIDE_GPIO , GPIO_PULLDOWN_ONLY );
353
- return gpio_get_level (OVERRIDE_GPIO );
450
+ #ifdef BOOTWIFI_OVERRIDE_GPIO
451
+ gpio_pad_select_gpio (BOOTWIFI_OVERRIDE_GPIO );
452
+ gpio_set_direction (BOOTWIFI_OVERRIDE_GPIO , GPIO_MODE_INPUT );
453
+ gpio_set_pull_mode (BOOTWIFI_OVERRIDE_GPIO , GPIO_PULLDOWN_ONLY );
454
+ return gpio_get_level (BOOTWIFI_OVERRIDE_GPIO );
455
+ #else
456
+ return 0 ; // If no boot override, return false
457
+ #endif
354
458
} // checkOverrideGpio
355
459
356
460
461
+
357
462
static void bootWiFi2 () {
358
463
ESP_LOGD (tag , ">> bootWiFi2" );
359
464
// Check for a GPIO override which occurs when a physical Pin is high
0 commit comments